Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Учебное пособие 2232

.pdf
Скачиваний:
28
Добавлен:
30.04.2022
Размер:
14.85 Mб
Скачать

Рис. 4.6. Электропитание платы

4.5. Начало использования программы Open BCI GU для сбора данных с платы Ganglion

Сначала необходимо подключить графический интерфейс к плате Ganglion. Для этого надо убедиться, что функция Bluetooth на ПК включена. В меню программы OpenBCI GUI необходимо выбрать “LIVE (from Ganglion)” (рис. 4.7) из первого раскрывающегося списка.

Рис. 4.7. Выбор источника данных

Далее выбрать ”Bluetooth (BLED112 Dongle)” в качестве протокола передачи (рис. 4.8).

Рис. 4.8. Выбор протокола передачи

90

Программа автоматически начнет поиск устройств Ganglion. Каждое устройство Ganglion имеет свой уникальный 4-х символьный идентификатор (в шестнадцатеричном формате), и он будет отображен в окне “BLE DEVICES” списком. Если устройства Ganglion не обнаружены, необходимо убедиться, что к устройству Ganglion подключена батарея, плата включена и синий светодиод на плате мигает. Если в зоне действия радиомодуля Bluetooth находится несколько работающих плат Ganglion, то можно найти необходимое устройство, нажав кнопку “REFRESH LIST” и записав 4-х-значный ID устройства. Далее, зная ID просто подключить необходимое устройство путем выбора устройства Ganglion из выпадающего списка (рис. 4.9).

Рис. 4.9. Выбор устройства

Программа OpenBCI GUI автоматически сгенерирует имя файла, в который будет осуществлена запись данных. В этот момент можно создать собственное имя файла в окне “DATA LOG FILE” (рис. 4.10).

Рис. 4.10. Изменение имени файла

Далее надо нажать кнопку “START SYSTEM” для начала потоковой передачи. Когда графический интерфейс будет запущен, то он будет открыт в макете окон по умолчанию (рис. 4.11).

91

Рис. 4.11. Макет окна графического интерфейса

Для выбора другого вида окон графического интерфейса надо нажать кнопку “Layout” в выпадающем меню и выбрать необходимый вид (рис. 4.12).

Рис. 4.12. Выбор вида окон

Если акселерометр выключен, то его можно включить, нажав кнопку

“Turn Accel. On” (рис. 4.13).

Рис. 4.13. Включение акселерометра

92

Затем надо нажать “Start Data Stream” для начала потоковой передачи данных с платы Ganglion (рис. 4.14).

Рис. 4.14. Начало потоковой передачи

После начала передачи данных появятся графики данных “Time Series”, окно“FFT Plot” покажет вам уровень мощности сигналов на разных частотах, окно “Accelerometer” покажет данные с акселерометра (рис. 4.15).

Рис. 4.15. Регистрируемые данные

93

При изменении положения платы Ganglion данные в окне “Accelerometer” также будут изменяться, и если дотронутся до входных контактов платы, то можно будет увидеть изменение шумоподобных сигналов в других окнах программы.

4.6. Формат данных платы Ganglion

Плата регистрации содержит микроконтроллер Simblee, который может быть запрограммирован как через Arduino IDE, так и через метод программирования OTA. У Simblee есть встроенный радиомодуль. Формат данных платы, отображаемый на ПК, определяется комбинацией кода Arduino на плате и программного обеспечения на компьютере. Модуль Simblee устроен так, что нельзя отправлять более 100 пакетов BLE в секунду. Для получения дополнительной информации о разборе потока байтов на стороне компьютера можно рассмотреть драйвер “node js”.

4.6.1. Стандартная настройка Bluetooth 4.n BLE

OpenBCI Ganglion использует стандартное соединение Bluetooth 4.n (BLE). Необходимо на ПК разрешить подключение к любому BLEсовместимому устройству. Все устройства BLE имеют специальные службы (прием, отправка и отключение) для модуля Simblee (табл. 4.1).

Таблица 4.1

Режим

Значение

 

 

Сервис

fe84

 

 

Получить

2d30c082f39f4ce6923f3484ea480596

 

 

Послать

2d30c083f39f4ce6923f3484ea480596

 

 

Отключить

2d30c084f39f4ce6923f3484ea480596

 

 

4.6.2. Запуск платы и инициирование бинарной трансформации

Плата Ganglion проходит цикл сброса при открытии соединения BLE. Изза этого невозможно подключиться / отключиться от усредненного потока платы Ganglion.

Как только плата Ganglion инициализируется с помощью соединения BLE, она ожидает команды. Плата не отправляет данные, пока не получит указание начать отправку данных. Чтобы начать передачу данных, необходимо передать один символ “b” в формате ASCII. После получения платой символа

94

“b” будет начата непрерывная передача данных в двоичном формате. Чтобы отключить передачу, надо отправить символ “s”.

4.6.3. Двоичный формат

Каждый пакет содержит идентификатор байта, за которым следуют 19 байтов данных, что в сумме составляет 20 байтов. Идентификатор байта определяет то, как принимающее программное обеспечение или драйвер должны анализировать следующие 19 байтов данных. Плата Ganglion производит выборку биосигналов с частотой 200 Гц. Из-за ограничения передачи пакетов BLE 100 Гц введен протокол дельта-сжатия.

Образцы данных с платы Ganglion имеют 24-битный формат, в первую очередь MSB. Если бы данные не сжимались, то можно было бы разместить только одну выборку в каждом пакете BLE, потому что 24 бита - это всего 3 байта, умноженные на 4 выборки для каждого канала, по 12 байтов, что привело бы к максимальной частоте дискретизации 100 Гц. Верхний наивысший предел согласованной передачи BLE составляет где-то около 100 пакетов в секунду. Поэтому сжатие сделано для того, чтобы получить две выборки на пакет, что дает в реальном времени частоту дискретизации 200 Гц.

4.6.4. 19-битное сжатие

По умолчанию используется 19-разрядное дельта-сжатие. Но далее описано 18-битное дельта-сжатие. Проще всего воспользоваться этой схемой сжатия, представленной на рис. 4.16.

Рис. 4.16. Схема 19-битного дельта-сжатия

95

Предположим, что плата Ganglion подключена к компьютеру, и пользователь хочет начать потоковую передачу данных. Пользователь (или управляющее программное обеспечение) отправляет “b”, и когда плата Ganglion получает “b”, она включает аппаратное обеспечение сбора данных, начинает брать выборки и отправляет данные в 20-байтных пакетах. Самый первый байт каждого пакета – это “Packet ID”, а самый первый отправленный пакет начинается с идентификатора “0x00”. Значение “0x00” указывает управляющему программному обеспечению, что пакет содержит несжатые данные, то есть 4 24-битных значения, занимающих 12 байтов после идентификатора пакета, связанного с каналом 1-4 соответственно. Эти значения являются основными данными платы Ganglion и используются для обеспечения работы алгоритма распаковки на компьютере. Плата Ganglion хранит значения в массиве с именем “lastChannelData[]”. Данный код можно найти в репозитории библиотеки Ganglion (https://github.com/OpenBCI/OpenBCI_Ganglion_Library).

void OpenBCI_Ganglion::compressData19() { int deltas[4];

int even = sampleCounter % 2; for (int i = 0; i < 4; i++) {

deltas[i] = lastChannelData[i] - channelData[i]; // subtract new from old lastChannelData[i] = channelData[i]; // keep track of the previous value bitWrite(deltas[i], 0, (bitRead(deltas[i], 31))); // store the sign bit in bit0

}

if (even == 1) { // pack odd samples first compression_ring[ringBufferLevel][0] = ((deltas[0] & 0x0007F800) >> 11); compression_ring[ringBufferLevel][1] = ((deltas[0] & 0x000007F8) >> 3); compression_ring[ringBufferLevel][2] = ((deltas[0] & 0x00000007) << 5); compression_ring[ringBufferLevel][2] |= ((deltas[1] & 0x0007C000) >> 14); compression_ring[ringBufferLevel][3] = ((deltas[1] & 0x00003FC0) >> 6); compression_ring[ringBufferLevel][4] = ((deltas[1] & 0x0000003F) << 2); compression_ring[ringBufferLevel][4] |= ((deltas[2] & 0x00060000) >> 17); compression_ring[ringBufferLevel][5] = ((deltas[2] & 0x0001FE00) >> 9); compression_ring[ringBufferLevel][6] = ((deltas[2] & 0x000001FE) >> 1); compression_ring[ringBufferLevel][7] = ((deltas[2] & 00000001) << 7); compression_ring[ringBufferLevel][7] |= ((deltas[3] & 0x0007F000) >> 12); compression_ring[ringBufferLevel][8] = ((deltas[3] & 0x00000FF0) >> 4); compression_ring[ringBufferLevel][9] = ((deltas[3] & 0x0000000F) << 4); } else { // pack even samples second compression_ring[ringBufferLevel][9] |= ((deltas[0] & 0x00078000) >> 15); compression_ring[ringBufferLevel][10] = ((deltas[0] & 0x00007F80) >> 7); compression_ring[ringBufferLevel][11] = ((deltas[0] & 0x0000007F) << 1); compression_ring[ringBufferLevel][11] |= ((deltas[1] & 0x00040000) >> 18); compression_ring[ringBufferLevel][12] = ((deltas[1] & 0x0003FC00) >> 10); compression_ring[ringBufferLevel][13] = ((deltas[1] & 0x000003FC) >> 2); compression_ring[ringBufferLevel][14] = ((deltas[1] & 0x00000003) << 6); compression_ring[ringBufferLevel][14] |= ((deltas[2] & 0x0007E000) >> 13); compression_ring[ringBufferLevel][15] = ((deltas[2] & 0x00001FE0) >> 5); compression_ring[ringBufferLevel][16] = ((deltas[2] & 0x0000001F) << 3); compression_ring[ringBufferLevel][16] |= ((deltas[3] & 0x00070000) >> 16); compression_ring[ringBufferLevel][17] = ((deltas[3] & 0x0000FF00) >> 8); compression_ring[ringBufferLevel][18] = (deltas[3] & 0x000000FF); sendCompressedPacket19(); // send on the even packet

}

}

96

Через 5 мсек Ganglion получает еще один набор из 4 выборок данных. Так как предыдущий пакет был пакетом 0, следующий пакет будет 1. В данной схеме сжатия нечетные выборки не отправляются. Вместо этого вычитаются эти новые значения канала из значений, содержащихся в массиве “lastChannelData[]”. Результатом является разница отправляемых данных. В этом случае нельзя отправить все 24 бита, поэтому вместо этого отправляется 19 LSB и разница каждого из них. При этом необходимо отслеживать знак полученной разности (отрицательная или положительная разница). Это сделано путем перемещения знакового бита результата вычитания в бит нулевой позиции. Да, это означает, что теряется один бит разрешения. Значения разницы вставляются в следующие 9,5 байтов пакета BLE. Следующая выборка - это выборка 2, и следует тот же процесс получения дельт (разниц), сохранения знака и передачи получаемых 19-битных значений, но на этот раз после того, как упаковка дельт закончена, полный пакет отправляется на радиопередатчик BLE. Каждый пакет, посланный со сжатием 19 бит, использует “Packet ID” в диапазоне от 101 до 200. Затем плата Ganglion отправляет несжатый пакет со значением 0x00 у “Packet ID”. Это означает, что раз в секунду плата Ganglion отправляет необработанный или несжатый пакет данных. Если по какой-либо причине пакет отбрасывается или возникает какая-то другая проблема с сохранением целостности данных, новый, полностью 100 % реальный несжатый пакет данных находится менее чем в секунде от битого пакета.

Все дельта-сжатия начинаются с необработанного несжатого пакета с байтовым идентификатором “0x00”, то есть 12 байтов несжатых 24-разрядных целочисленных выборок со знаком. Плата Ganglion использует 2D-буфер, вызываемый “compression-ring” для хранения пакетов BLE. Этот буфер имеет размер 101 пакет, что означает, что он может хранить до минуты последней записи данных. Это может быть использовано для возможности повторного вызова сброшенных (битых) пакетов.

18-битное и 19-битное сжатия сохраняют бит со знаком в позиции 0 или LSB. Отрицательные числа всегда присутствуют в позиции 1 или LSB, а положительные числа всегда в позиции 0 или LSB. Если сохранить бит со знаком в MSB, то будет потеряна половину динамического диапазона (плохого), и поместив бит в LSB, будет потеряна номинальная ошибка округления.

4.6.5. 18-битное сжатие

Сжатие 19 бит не оставляет места для дополнительных данных. Если необходимо отправить данные встроенного акселерометра, то необходимо еще более сильно сжать данные. В случае 18-битного сжатия используется 0x00 “Packet ID” для отправки сырых несжатых данных. Каждый следующий пакет использует “Packet ID” от 1 до 100. Таким образом, управляющее программное обеспечение, которое выполняет алгоритм распаковки, может распаковывать

97

каждый пакет без необходимости «знать», в каком состоянии находится система (рис. 4.17).

Рис. 4.17. Схема 18-битного дельта-сжатия

void OpenBCI_Ganglion::compressData18() { int deltas[4];

int even = sampleCounter % 2; for (int i = 0; i < 4; i++) {

deltas[i] = lastChannelData[i] - channelData[i]; // subtract new from old lastChannelData[i] = channelData[i]; // keep track of the previous value bitWrite(deltas[i], 0, (bitRead(deltas[i], 31))); // store the sign bit in bit0

}

if (even == 1) { // pack odd samples first compression_ring[ringBufferLevel][0] = ((deltas[0] & 0x0003FC00) >> 10); compression_ring[ringBufferLevel][1] = ((deltas[0] & 0x000003FC) >> 2); compression_ring[ringBufferLevel][2] = ((deltas[0] & 0x00000003) << 6); compression_ring[ringBufferLevel][2] |= ((deltas[1] & 0x0003F000) >> 12); compression_ring[ringBufferLevel][3] = ((deltas[1] & 0x00000FF0) >> 4); compression_ring[ringBufferLevel][4] = ((deltas[1] & 0x0000000F) << 4); compression_ring[ringBufferLevel][4] |= ((deltas[2] & 0x0003C000) >> 14); compression_ring[ringBufferLevel][5] = ((deltas[2] & 0x00003FC0) >> 6); compression_ring[ringBufferLevel][6] = ((deltas[2] & 0x0000003F) << 2); compression_ring[ringBufferLevel][6] |= ((deltas[3] & 0x00030000) >> 16); compression_ring[ringBufferLevel][7] = ((deltas[3] & 0x0000FF00) >> 8); compression_ring[ringBufferLevel][8] = (deltas[3] & 0x000000FF);

} else { // pack even samples second compression_ring[ringBufferLevel][9] = ((deltas[0] & 0x0003FC00) >> 10); compression_ring[ringBufferLevel][10] = ((deltas[0] & 0x000003FC) >> 2); compression_ring[ringBufferLevel][11] = ((deltas[0] & 0x00000003) << 6); compression_ring[ringBufferLevel][11] |= ((deltas[1] & 0x0003F000) >> 12); compression_ring[ringBufferLevel][12] = ((deltas[1] & 0x00000FF0) >> 4); compression_ring[ringBufferLevel][13] = ((deltas[1] & 0x0000000F) << 4); compression_ring[ringBufferLevel][13] |= ((deltas[2] & 0x0003C000) >> 14); compression_ring[ringBufferLevel][14] = ((deltas[2] & 0x00003FC0) >> 6);

98

compression_ring[ringBufferLevel][15] = ((deltas[2] & 0x0000003F) << 2); compression_ring[ringBufferLevel][15] |= ((deltas[3] & 0x00030000) >> 16); compression_ring[ringBufferLevel][16] = ((deltas[3] & 0x0000FF00) >> 8); compression_ring[ringBufferLevel][17] = (deltas[3] & 0x000000FF);

sendCompressedPacket18(); // send on the even packet

}

}

Когда акселерометр работает, частота дискретизации акселерометра по умолчанию составляет 10 Гц. Ganglion будет получать данные акселерометра всякий раз, когда будет готов, но он будет отправлять только значения с определенным заголовком “Packet ID”.

void OpenBCI_Ganglion::sendCompressedPacket18() {

 

radioBuffer[0] = ringBufferLevel;

 

for (int i = 0; i < 18; i++) {

 

radioBuffer[i+1] = compression_ring[ringBufferLevel][i];

 

}

 

if(useAccel){

 

if(ringBufferLevel%10 == 1){ radioBuffer[19] = axisData[0]; }

// x axis

if(ringBufferLevel%10 == 2){ radioBuffer[19] = axisData[1]; }

// y axis

if(ringBufferLevel%10 == 3){ radioBuffer[19] = axisData[2]; }

// z axis

} else if(useAux){

 

if(ringBufferLevel%10 == 1){ radioBuffer[19] = auxData[0]; }

 

if(ringBufferLevel%10 == 2){ radioBuffer[19] = auxData[1]; }

 

if(ringBufferLevel%10 == 3){ radioBuffer[19] = auxData[2]; }

 

}

 

ringBufferLevel++;

 

if (BLEconnected) {

 

SimbleeBLE.send(radioBuffer, 20);

 

}

 

}

 

Используется номер, связанный с положением буфера “compression_ring”, чтобы указать, когда необходимо передавать данные значений осей x, y и z. При передаче c использованием 18-битного сжатия пакеты данных акселерометра можно найти в числах, заканчивающихся на 1, 2 и 3 поля “Packet ID”.

Плата Ganglion также способна отправлять “auxData” данные, заданные пользователем, вместо данных акселерометра. Команда “n” в формате ASCII используется для включения акселерометра на плате Ganglion.

4.6.6. Измерение импеданса контакта кожа-электрод

На плате Ganglion имеется аппаратное обеспечение, позволяющее измерить сопротивление контакта электрода с кожей. Программное обеспечение использует управляющие команды “z” в формате ASCII, чтобы начать тестирование полного сопротивления, и команды “Z”, чтобы остановить измерение импеданса. Во время тестирования импеданса поток данных отключается. Плата Ganglion будет посылать значения измеренного импеданса

99