Настройте тестовое программное обеспечение

Для оценки оборудования используется следующее программное обеспечение:

  • Audacity (устанавливается на ПК)
  • MATLAB (установлен на ПК)
  • Приложение для тестирования тактильных ощущений (установлено на тестируемое устройство)

Чтобы узнать больше о системных требованиях, см. Audacity для Windows , Audacity для Mac и MATLAB .

Настройте Смелость

Необходимо настроить Audacity для приема входных данных со звуковой карты Sound Blaster с определенной частотой дискретизации. Подключив Sound Blaster к USB-порту вашего компьютера, откройте Audacity и следуйте этим инструкциям.

  1. Выберите Line (USB Sound Blaster HD) в качестве источника входного микрофона, физически подключив выход CCLD к входному порту Line In Sound Blaster.

    Микрофонный вход

    Рисунок 1. Выбор микрофонного входа

  2. Установите частоту дискретизации 48 кГц, выбрав 48000 в меню Project Rate .

    Частота выборки

    Рисунок 2. Настройка частоты дискретизации

Скачать МАТЛАБ

  1. Загрузите файл MATLAB .

  2. Извлеките файл и найдите Effect1NEffect2_V1p0_2020PM.m (для Эффекта 1 и Эффекта 2) и Effect3_V1p0_2020PM.m (для Эффекта 3).

Установите тестовое приложение на телефоне

В этом разделе описывается, как настроить тестовое приложение на телефоне.

Подготовьтесь к тестированию приложения

  1. Скопируйте исходный код из блоков кода Java и Kotlin ниже. Выбирайте тот, который лучше всего подходит для вас.
  2. Напишите свой собственный код, следуя параметрам графического интерфейса, показанным на рисунке 3. При необходимости настройте детали исходного кода макета в соответствии с вашим телефоном.
  3. Убедитесь, что ваш графический интерфейс включает три интерактивные кнопки и визуальный индикатор для определения области расположения акселерометра.

    • Область расположения акселерометра представляет собой площадь экрана устройства, к которой обычно прикасаются рукой.
    • Во время этого измерения вы можете перемещать акселерометр в бирюзовой области, чтобы найти область экрана, которая улавливает самый сильный сигнал.
  4. Установите код на Android-устройство.

  5. Настоятельно рекомендуется установить режим навигации системы на режим жестов, если режим по умолчанию установлен в виде кнопок.

    • Установив режим жестов, вы можете максимально разместить акселерометр в нижней части телефона, не отвлекаясь на графический интерфейс навигации системы телефона.

Исходный код Java

package com.example.hapticeffectassessment;

import static android.os.VibrationEffect.EFFECT_CLICK;

import android.graphics.Color;
import android.os.Bundle;
import android.os.VibrationEffect;
import android.os.Vibrator;
import android.widget.Button;
import androidx.appcompat.app.AppCompatActivity;

public class MainActivity extends AppCompatActivity {

 private static final long oneShotTiming = 20;
 private static final int oneShotAmplitude = 255;

 private static final long[] waveformTimings = {500, 500};
 private static final int[] waveformAmplitudes = {128, 255};

 @Override
 protected void onCreate(Bundle savedInstanceState) {
   super.onCreate(savedInstanceState);
   setContentView(R.layout.activity_main);

   Vibrator vibrator = getSystemService(Vibrator.class);

   // Click R.id.button1 button to generate Effect 1
   findViewById(R.id.button1).setOnClickListener(
       view -> vibrator.vibrate(VibrationEffect.createPredefined(EFFECT_CLICK)));

   // Click R.id.button2 button to generate Effect 2
   findViewById(R.id.button2).setOnClickListener(
       view -> vibrator.vibrate(VibrationEffect.createOneShot(oneShotTiming, oneShotAmplitude)));

   // Click R.id.button3 button to generate Effect 3
   findViewById(R.id.button3).setOnClickListener(view -> {
     vibrator.vibrate(VibrationEffect.createWaveform(waveformTimings, waveformAmplitudes, -1));

     // See quick results of Effect 3
     Button button = (Button) view;
     if (vibrator.hasAmplitudeControl()) {
       button.setText("Effect 3: PASS");
       button.setBackgroundColor(Color.GREEN);
       button.setTextColor(Color.BLACK);
     } else {
       button.setText("Effect 3: FAIL");
       button.setBackgroundColor(Color.RED);
       button.setTextColor(Color.WHITE);
     }
   });
 }
}

Исходный код Котлина

package com.example.hapticeffectassessment

import android.graphics.Color
import android.os.Bundle
import android.os.VibrationEffect
import android.os.VibrationEffect.EFFECT_CLICK
import android.os.Vibrator
import android.widget.Button
import androidx.appcompat.app.AppCompatActivity
import kotlinx.android.synthetic.main.activity_main.*

class MainActivityKt : AppCompatActivity() {

 private val oneShotTiming: Long = 20
 private val oneShotAmplitude = 255

 private val waveformTimings = longArrayOf(500, 500)
 private val waveformAmplitudes = intArrayOf(128, 255)

 override fun onCreate(savedInstanceState: Bundle?) {
   super.onCreate(savedInstanceState)
   setContentView(R.layout.activity_main)

   val vibrator = getSystemService(Vibrator::class.java)

   // Click button1 to generate Effect 1
   button1.setOnClickListener {
     vibrator.vibrate(VibrationEffect.createPredefined(EFFECT_CLICK))
   }

   // Click button2 to generate Effect 2
   button2.setOnClickListener {
     vibrator.vibrate(VibrationEffect.createOneShot(oneShotTiming, oneShotAmplitude))
   }

   // Click button3 to generate Effect 3
   button3.setOnClickListener {
     vibrator.vibrate(
       VibrationEffect.createWaveform(waveformTimings, waveformAmplitudes, -1))

     // See quick results of Effect 3
     if (vibrator.hasAmplitudeControl()) {
       button3.text = "Effect 3: PASS"
       button3.setBackgroundColor(Color.GREEN)
       button3.setTextColor(Color.BLACK)
     } else {
       button3.text = "Effect 3: FAIL"
       button3.setBackgroundColor(Color.RED)
       button3.setTextColor(Color.WHITE)
     }
   }
 }
}

Исходный код макета (activity_main.xml)

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
   xmlns:app="http://schemas.android.com/apk/res-auto"
   xmlns:tools="http://schemas.android.com/tools"
   android:layout_width="match_parent"
   android:layout_height="match_parent"
   tools:context=".MainActivity">

   <Button
       android:id="@+id/button1"
       android:layout_width="350dp"
       android:layout_height="60dp"
       android:layout_marginStart="32dp"
       android:layout_marginTop="5dp"
       android:layout_marginEnd="32dp"
       android:text="Effect 1"
       android:textSize="18sp"
       app:layout_constraintEnd_toEndOf="parent"
       app:layout_constraintStart_toStartOf="parent"
       app:layout_constraintTop_toTopOf="parent" />

   <Button
       android:id="@+id/button2"
       android:layout_width="350dp"
       android:layout_height="60dp"
       android:layout_marginStart="32dp"
       android:layout_marginTop="5dp"
       android:layout_marginEnd="32dp"
       android:text="Effect 2"
       android:textSize="18sp"
       app:layout_constraintEnd_toEndOf="parent"
       app:layout_constraintStart_toStartOf="parent"
       app:layout_constraintTop_toBottomOf="@+id/button1" />

   <Button
       android:id="@+id/button3"
       android:layout_width="350dp"
       android:layout_height="60dp"
       android:layout_marginStart="32dp"
       android:layout_marginTop="5dp"
       android:layout_marginEnd="32dp"
       android:text="Effect 3"
       android:textSize="18sp"
       app:layout_constraintEnd_toEndOf="parent"
       app:layout_constraintStart_toStartOf="parent"
       app:layout_constraintTop_toBottomOf="@+id/button2" />

   <View
       android:id="@+id/divider"
       android:layout_width="363dp"
       android:layout_height="1dp"
       android:layout_marginStart="32dp"
       android:layout_marginTop="10dp"
       android:layout_marginEnd="32dp"
       android:background="?android:attr/listDivider"
       app:layout_constraintEnd_toEndOf="parent"
       app:layout_constraintHorizontal_bias="0.5"
       app:layout_constraintStart_toStartOf="parent"
       app:layout_constraintTop_toBottomOf="@+id/button3" />

   <androidx.constraintlayout.widget.ConstraintLayout
       android:layout_width="363dp"
       android:layout_height="0dp"
       app:layout_constraintBottom_toBottomOf="parent"
       app:layout_constraintEnd_toEndOf="parent"
       app:layout_constraintHorizontal_bias="0.5"
       app:layout_constraintStart_toStartOf="parent"
       app:layout_constraintTop_toBottomOf="@+id/divider">

       <ImageView
           android:id="@+id/imageView"
           android:layout_width="wrap_content"
           android:layout_height="wrap_content"
           android:adjustViewBounds="true"
           android:scaleType="fitXY"
           app:layout_constraintBottom_toBottomOf="parent"
           app:layout_constraintEnd_toEndOf="parent"
           app:layout_constraintHorizontal_bias="0.5"
           app:layout_constraintStart_toStartOf="parent"
           app:layout_constraintTop_toTopOf="parent"
           app:srcCompat="@drawable/bluebar" />
   </androidx.constraintlayout.widget.ConstraintLayout>

</androidx.constraintlayout.widget.ConstraintLayout>

Акселерометр

Рисунок 3. Крепление акселерометра в области, рекомендованной в графическом интерфейсе

,

Для оценки оборудования используется следующее программное обеспечение:

  • Audacity (устанавливается на ПК)
  • MATLAB (установлен на ПК)
  • Приложение для тестирования тактильных ощущений (установлено на тестируемое устройство)

Чтобы узнать больше о системных требованиях, см. Audacity для Windows , Audacity для Mac и MATLAB .

Настройте Смелость

Необходимо настроить Audacity для приема входных данных со звуковой карты Sound Blaster с определенной частотой дискретизации. Подключив Sound Blaster к USB-порту вашего компьютера, откройте Audacity и следуйте этим инструкциям.

  1. Выберите Line (USB Sound Blaster HD) в качестве источника входного микрофона, физически подключив выход CCLD к входному порту Line In Sound Blaster.

    Микрофонный вход

    Рисунок 1. Выбор микрофонного входа

  2. Установите частоту дискретизации 48 кГц, выбрав 48000 в меню Project Rate .

    Частота выборки

    Рисунок 2. Настройка частоты дискретизации

Скачать МАТЛАБ

  1. Загрузите файл MATLAB .

  2. Извлеките файл и найдите Effect1NEffect2_V1p0_2020PM.m (для Эффекта 1 и Эффекта 2) и Effect3_V1p0_2020PM.m (для Эффекта 3).

Установите тестовое приложение на телефоне

В этом разделе описывается, как настроить тестовое приложение на телефоне.

Подготовьтесь к тестированию приложения

  1. Скопируйте исходный код из блоков кода Java и Kotlin ниже. Выбирайте тот, который лучше всего подходит для вас.
  2. Напишите свой собственный код, следуя параметрам графического интерфейса, показанным на рисунке 3. При необходимости настройте детали исходного кода макета в соответствии с вашим телефоном.
  3. Убедитесь, что ваш графический интерфейс включает три интерактивные кнопки и визуальный индикатор для определения области расположения акселерометра.

    • Область расположения акселерометра представляет собой площадь экрана устройства, к которой обычно прикасаются рукой.
    • Во время этого измерения вы можете перемещать акселерометр в бирюзовой области, чтобы найти область экрана, которая улавливает самый сильный сигнал.
  4. Установите код на Android-устройство.

  5. Настоятельно рекомендуется установить режим навигации системы на режим жестов, если режим по умолчанию установлен в виде кнопок.

    • Установив режим жестов, вы можете максимально разместить акселерометр в нижней части телефона, не отвлекаясь на графический интерфейс навигации системы телефона.

Исходный код Java

package com.example.hapticeffectassessment;

import static android.os.VibrationEffect.EFFECT_CLICK;

import android.graphics.Color;
import android.os.Bundle;
import android.os.VibrationEffect;
import android.os.Vibrator;
import android.widget.Button;
import androidx.appcompat.app.AppCompatActivity;

public class MainActivity extends AppCompatActivity {

 private static final long oneShotTiming = 20;
 private static final int oneShotAmplitude = 255;

 private static final long[] waveformTimings = {500, 500};
 private static final int[] waveformAmplitudes = {128, 255};

 @Override
 protected void onCreate(Bundle savedInstanceState) {
   super.onCreate(savedInstanceState);
   setContentView(R.layout.activity_main);

   Vibrator vibrator = getSystemService(Vibrator.class);

   // Click R.id.button1 button to generate Effect 1
   findViewById(R.id.button1).setOnClickListener(
       view -> vibrator.vibrate(VibrationEffect.createPredefined(EFFECT_CLICK)));

   // Click R.id.button2 button to generate Effect 2
   findViewById(R.id.button2).setOnClickListener(
       view -> vibrator.vibrate(VibrationEffect.createOneShot(oneShotTiming, oneShotAmplitude)));

   // Click R.id.button3 button to generate Effect 3
   findViewById(R.id.button3).setOnClickListener(view -> {
     vibrator.vibrate(VibrationEffect.createWaveform(waveformTimings, waveformAmplitudes, -1));

     // See quick results of Effect 3
     Button button = (Button) view;
     if (vibrator.hasAmplitudeControl()) {
       button.setText("Effect 3: PASS");
       button.setBackgroundColor(Color.GREEN);
       button.setTextColor(Color.BLACK);
     } else {
       button.setText("Effect 3: FAIL");
       button.setBackgroundColor(Color.RED);
       button.setTextColor(Color.WHITE);
     }
   });
 }
}

Исходный код Котлина

package com.example.hapticeffectassessment

import android.graphics.Color
import android.os.Bundle
import android.os.VibrationEffect
import android.os.VibrationEffect.EFFECT_CLICK
import android.os.Vibrator
import android.widget.Button
import androidx.appcompat.app.AppCompatActivity
import kotlinx.android.synthetic.main.activity_main.*

class MainActivityKt : AppCompatActivity() {

 private val oneShotTiming: Long = 20
 private val oneShotAmplitude = 255

 private val waveformTimings = longArrayOf(500, 500)
 private val waveformAmplitudes = intArrayOf(128, 255)

 override fun onCreate(savedInstanceState: Bundle?) {
   super.onCreate(savedInstanceState)
   setContentView(R.layout.activity_main)

   val vibrator = getSystemService(Vibrator::class.java)

   // Click button1 to generate Effect 1
   button1.setOnClickListener {
     vibrator.vibrate(VibrationEffect.createPredefined(EFFECT_CLICK))
   }

   // Click button2 to generate Effect 2
   button2.setOnClickListener {
     vibrator.vibrate(VibrationEffect.createOneShot(oneShotTiming, oneShotAmplitude))
   }

   // Click button3 to generate Effect 3
   button3.setOnClickListener {
     vibrator.vibrate(
       VibrationEffect.createWaveform(waveformTimings, waveformAmplitudes, -1))

     // See quick results of Effect 3
     if (vibrator.hasAmplitudeControl()) {
       button3.text = "Effect 3: PASS"
       button3.setBackgroundColor(Color.GREEN)
       button3.setTextColor(Color.BLACK)
     } else {
       button3.text = "Effect 3: FAIL"
       button3.setBackgroundColor(Color.RED)
       button3.setTextColor(Color.WHITE)
     }
   }
 }
}

Исходный код макета (activity_main.xml)

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
   xmlns:app="http://schemas.android.com/apk/res-auto"
   xmlns:tools="http://schemas.android.com/tools"
   android:layout_width="match_parent"
   android:layout_height="match_parent"
   tools:context=".MainActivity">

   <Button
       android:id="@+id/button1"
       android:layout_width="350dp"
       android:layout_height="60dp"
       android:layout_marginStart="32dp"
       android:layout_marginTop="5dp"
       android:layout_marginEnd="32dp"
       android:text="Effect 1"
       android:textSize="18sp"
       app:layout_constraintEnd_toEndOf="parent"
       app:layout_constraintStart_toStartOf="parent"
       app:layout_constraintTop_toTopOf="parent" />

   <Button
       android:id="@+id/button2"
       android:layout_width="350dp"
       android:layout_height="60dp"
       android:layout_marginStart="32dp"
       android:layout_marginTop="5dp"
       android:layout_marginEnd="32dp"
       android:text="Effect 2"
       android:textSize="18sp"
       app:layout_constraintEnd_toEndOf="parent"
       app:layout_constraintStart_toStartOf="parent"
       app:layout_constraintTop_toBottomOf="@+id/button1" />

   <Button
       android:id="@+id/button3"
       android:layout_width="350dp"
       android:layout_height="60dp"
       android:layout_marginStart="32dp"
       android:layout_marginTop="5dp"
       android:layout_marginEnd="32dp"
       android:text="Effect 3"
       android:textSize="18sp"
       app:layout_constraintEnd_toEndOf="parent"
       app:layout_constraintStart_toStartOf="parent"
       app:layout_constraintTop_toBottomOf="@+id/button2" />

   <View
       android:id="@+id/divider"
       android:layout_width="363dp"
       android:layout_height="1dp"
       android:layout_marginStart="32dp"
       android:layout_marginTop="10dp"
       android:layout_marginEnd="32dp"
       android:background="?android:attr/listDivider"
       app:layout_constraintEnd_toEndOf="parent"
       app:layout_constraintHorizontal_bias="0.5"
       app:layout_constraintStart_toStartOf="parent"
       app:layout_constraintTop_toBottomOf="@+id/button3" />

   <androidx.constraintlayout.widget.ConstraintLayout
       android:layout_width="363dp"
       android:layout_height="0dp"
       app:layout_constraintBottom_toBottomOf="parent"
       app:layout_constraintEnd_toEndOf="parent"
       app:layout_constraintHorizontal_bias="0.5"
       app:layout_constraintStart_toStartOf="parent"
       app:layout_constraintTop_toBottomOf="@+id/divider">

       <ImageView
           android:id="@+id/imageView"
           android:layout_width="wrap_content"
           android:layout_height="wrap_content"
           android:adjustViewBounds="true"
           android:scaleType="fitXY"
           app:layout_constraintBottom_toBottomOf="parent"
           app:layout_constraintEnd_toEndOf="parent"
           app:layout_constraintHorizontal_bias="0.5"
           app:layout_constraintStart_toStartOf="parent"
           app:layout_constraintTop_toTopOf="parent"
           app:srcCompat="@drawable/bluebar" />
   </androidx.constraintlayout.widget.ConstraintLayout>

</androidx.constraintlayout.widget.ConstraintLayout>

Акселерометр

Рисунок 3. Крепление акселерометра в области, рекомендованной в графическом интерфейсе