Для оценки оборудования используется следующее программное обеспечение:
- Audacity (устанавливается на ПК)
- MATLAB (установлен на ПК)
- Приложение для тестирования тактильных ощущений (установлено на тестируемое устройство)
Чтобы узнать больше о системных требованиях, см. Audacity для Windows , Audacity для Mac и MATLAB .
Настройте Смелость
Необходимо настроить Audacity для приема входных данных со звуковой карты Sound Blaster с определенной частотой дискретизации. Подключив Sound Blaster к USB-порту вашего компьютера, откройте Audacity и следуйте этим инструкциям.
Выберите Line (USB Sound Blaster HD) в качестве источника входного микрофона, физически подключив выход CCLD к входному порту Line In Sound Blaster.
Рисунок 1. Выбор микрофонного входа
Установите частоту дискретизации 48 кГц, выбрав 48000 в меню Project Rate .
Рисунок 2. Настройка частоты дискретизации
Скачать МАТЛАБ
Загрузите файл MATLAB .
Извлеките файл и найдите
Effect1NEffect2_V1p0_2020PM.m
(для Эффекта 1 и Эффекта 2) иEffect3_V1p0_2020PM.m
(для Эффекта 3).
Установите тестовое приложение на телефоне
В этом разделе описывается, как настроить тестовое приложение на телефоне.
Подготовьтесь к тестированию приложения
- Скопируйте исходный код из блоков кода Java и Kotlin ниже. Выбирайте тот, который лучше всего подходит для вас.
- Напишите свой собственный код, следуя параметрам графического интерфейса, показанным на рисунке 3. При необходимости настройте детали исходного кода макета в соответствии с вашим телефоном.
Убедитесь, что ваш графический интерфейс включает три интерактивные кнопки и визуальный индикатор для определения области расположения акселерометра.
- Область расположения акселерометра представляет собой площадь экрана устройства, к которой обычно прикасаются рукой.
- Во время этого измерения вы можете перемещать акселерометр в бирюзовой области, чтобы найти область экрана, которая улавливает самый сильный сигнал.
Установите код на Android-устройство.
Настоятельно рекомендуется установить режим навигации системы на режим жестов, если режим по умолчанию установлен в виде кнопок.
- Установив режим жестов, вы можете максимально разместить акселерометр в нижней части телефона, не отвлекаясь на графический интерфейс навигации системы телефона.
Исходный код 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 и следуйте этим инструкциям.
Выберите Line (USB Sound Blaster HD) в качестве источника входного микрофона, физически подключив выход CCLD к входному порту Line In Sound Blaster.
Рисунок 1. Выбор микрофонного входа
Установите частоту дискретизации 48 кГц, выбрав 48000 в меню Project Rate .
Рисунок 2. Настройка частоты дискретизации
Скачать МАТЛАБ
Загрузите файл MATLAB .
Извлеките файл и найдите
Effect1NEffect2_V1p0_2020PM.m
(для Эффекта 1 и Эффекта 2) иEffect3_V1p0_2020PM.m
(для Эффекта 3).
Установите тестовое приложение на телефоне
В этом разделе описывается, как настроить тестовое приложение на телефоне.
Подготовьтесь к тестированию приложения
- Скопируйте исходный код из блоков кода Java и Kotlin ниже. Выбирайте тот, который лучше всего подходит для вас.
- Напишите свой собственный код, следуя параметрам графического интерфейса, показанным на рисунке 3. При необходимости настройте детали исходного кода макета в соответствии с вашим телефоном.
Убедитесь, что ваш графический интерфейс включает три интерактивные кнопки и визуальный индикатор для определения области расположения акселерометра.
- Область расположения акселерометра представляет собой площадь экрана устройства, к которой обычно прикасаются рукой.
- Во время этого измерения вы можете перемещать акселерометр в бирюзовой области, чтобы найти область экрана, которая улавливает самый сильный сигнал.
Установите код на Android-устройство.
Настоятельно рекомендуется установить режим навигации системы на режим жестов, если режим по умолчанию установлен в виде кнопок.
- Установив режим жестов, вы можете максимально разместить акселерометр в нижней части телефона, не отвлекаясь на графический интерфейс навигации системы телефона.
Исходный код 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. Крепление акселерометра в области, рекомендованной в графическом интерфейсе