Flutter神经网络处理插件neurosdk2的使用

Flutter神经网络处理插件neurosdk2的使用

概览

Neurosdk是一个强大的工具,用于与神经传感器BrainBit、BrainBitBlack、Callibri和Kolibri一起工作。SDK允许你连接设备、读取设备参数以及从选定的设备接收各种类型的信号。

支持的平台:

  • Android
  • Windows

安装

(安装指南将稍后发布)

错误

在使用SDK时可能会遇到以下异常情况。你需要根据这些信息来理解在执行特定方法过程中发生的情况。

代码 描述
100 指定的扫描参数无效
101 指定的传感器类型搜索无效
102 无法创建传感器扫描器
103 无法启动传感器扫描器
104 无法停止传感器扫描器
105 无法获取传感器列表
106 无法获取传感器列表
107 创建传感器的参数无效
108 无法创建传感器
109 未找到传感器
110 无法连接传感器
111 无法断开传感器连接
112 无法获取传感器功能列表
113 获取传感器功能列表的参数无效
114 获取传感器命令列表的参数无效
115 无法获取传感器命令列表
116 获取传感器参数列表的参数无效
117 无法获取传感器参数列表
118 无法执行传感器命令
119 无法读取传感器参数
120 无法读取传感器参数
121 无法写入传感器参数
122 无法写入传感器参数
123 无法添加传感器回调
124 无法添加传感器回调

使用

扫描器

扫描器允许你在附近查找设备,并负责首次创建设备。无论你使用哪种类型的设备,扫描器的使用方式都是相同的。

创建扫描器

创建扫描器时,需要指定要搜索的设备类型。可以是一个设备或多个设备。这里是一个示例,搜索两种类型的设备——BrainBit和Callibri。

Scanner sc = await Scanner.create([FSensorFamily.leBrainBit, FSensorFamily.leCallibri]);
订阅事件

在搜索过程中,你可以通过回调获取找到的设备列表。为此,你需要订阅接收事件,并在搜索完成后取消订阅:

StreamSubscription<List<FSensorInfo>>? scannerSubscription = scanner.sensorsStream.listen((foundedSensors) {
  for (FSensorInfo info in foundedSensors) {
    print("${info.name}");
  }
});
// 取消订阅
scannerSubscription.cancel();
开始搜索
await scanner.start();
停止搜索
await scanner.stop();
获取已发现设备列表
List<FSensorInfo?> sensors = await scanner.getSensors();
设备信息

SensorInfo 包含设备的信息:

字段 类型 描述
name String 设备名称
address String 设备的MAC地址(iOS/MacOS为UUID)
serialNumber String 设备序列号
sensFamily SensorFamily 设备类型
sensModel int 设备型号的数值
pairingRequared bool 设备是否需要配对
rssi int 当前信号强度,范围[-127, 126]

重要! 在搜索过程中,Callibri和Kolibri的序列号不会出现在 SensorInfo 中。要获取该值,你需要连接到设备并手动请求序列号:

String serialNumber = await sensor.serialNumber.value;
清理资源

在完成与扫描器的工作后,需要清理使用的资源。

scanner.dispose();

重要! 当重新开始搜索时,回调只会被调用当有新设备被发现。如果你需要获取当前扫描器实例找到的所有设备,请调用相应的方法。

设备管理

创建设备时,需要使用扫描器和接收到的设备信息。所有与设备的操作都必须在设备连接的情况下进行。创建设备时,设备会自动连接。未来,可以通过传感器对象控制连接状态。传感器允许你监控设备状态、设置参数并接收各种类型的信号。

// 从列表检索信息或从回调中检索存储的信息
List<FSensorInfo?> sensors = await scanner.getSensors();
FSensorInfo? sensorInfo = sensors[0];

// BrainBit
BrainBit? sensor = await scanner.createSensor(info!) as BrainBit;

// BrainBit 2 / Flex / Flex Pro
BrainBit2? sensor = await scanner.createSensor(info!) as BrainBit2;

// Callibri
Callibri? sensor = await scanner.createSensor(info!) as Callibri;

重要! 设备创建是一个阻塞方法,因此必须从单独的线程调用。

重要! 对于所有类型的设备,你可以使用相同的方法来控制设备的连接状态、执行命令并检查功能。

连接状态管理

连接状态可以通过两种方式获得。第一种是使用传感器属性 State

第二种是在实时中使用回调:

StreamSubscription<FSensorState>? stateSubscription = sensor.sensorStateStream.listen((state) => print("State: $state"));
...
stateSubscription.cancel();

重要! 状态更改回调在设备创建后不会出现,只有在断开连接(设备丢失或使用方法)后再连接时才会出现。设备不会自动重新连接。

你可以手动连接和断开设备,通过方法 connect()disconnect()。为了实时接收连接状态,需要订阅 stateChanged 事件。也可以通过传感器的属性获取连接状态。

await sensor.disconnect();
...
await sensor.connect();
设备最终化

当你完成设备操作后,建议断开连接并清理所占用的资源。

await sensor.disconnect();
sensor.dispose();
设备参数管理
电池

你还可以通过传感器属性 BattPower 或实时回调获取每个设备的电源值:

StreamSubscription<int>? powerSubscription = sensor.batteryPowerStream.listen((power) => print("Battery: $power"));
...
powerSubscription.cancel();
参数

每个设备都有自己的设置,其中一些可以按你的需求进行配置。不是所有的设置都可以更改,并且不是每个设备都支持所有的设置。

首先,你需要找出设备支持哪些参数以及这些参数是否可以更改:

List<FParameterInfo?> pInfos = await sensor.parameters.value;

参数信息包括两个字段:

FParameterInfo

字段 类型 描述
param FSensorParameter 参数名称,表示为枚举
paramAccess FSensorParamAccess 参数可用性

FSensorParamAccess

字段 描述
read 0 只读
readWrite 1 参数可以更改
readNotify 2 参数随时间更新

你还可以检查参数是否受支持,例如 Gain

if(await sensor.isSupportedParameter(FSensorParameter.gain)){
  ...
}
参数描述
名称

设备名称。

String name = await sensor.name.value;
...
await sensor.name.set("newName").onError((error, stackTrace) => print(error)); // <- 捕获异常
状态

设备连接状态信息。可以取两个值:

  • InRange - 设备连接
  • OutOfRange - 设备关闭或超出范围
SensorState state = await sensor.state.value;
if (state == SensorState.inRange) {
  print("connected");
} else {
  print("disconnected");
}
地址

设备的MAC地址。对于iOS/MacOS表示为UUID。字符串值。

String address = await sensor.address.value;
序列号

设备的序列号。字符串值。

对于Callibri设备系列,在搜索时此字段为空,你可以在连接后立即使用此属性获取它。

String serialNumber = await sensor.serialNumber.value;
固件模式

设备固件当前运行模式的信息。它可以处于两种状态之一:

  • ModeBootloader - 设备处于引导加载程序模式
  • ModeApplication - 正常运行
FSensorFirmwareMode mode = await sensor.firmwareMode.value;

// 仅适用于Callibri/ Kolibri
await sensor.firmwareMode.set(FSensorFirmwareMode.modeApplication);
采样频率

用于设置或获取生理信号采样率的属性。值越高,从设备到应用程序的数据流越多,这意味着更高的功耗,但也有更宽的测量频率范围。物理通信通道(BLE)在带宽方面也有限制。

选择值的建议:

  • 对于EEG信号不小于250 Hz;
  • 对于ECG信号125 Hz;
  • 对于EMG不小于1000 Hz。同时处理多个设备时,不建议超过1000 Hz;
  • 呼吸通道的采样率为固定20赫兹。MEMS通道的采样率为固定100赫兹。

对于BrainBit和BrainBitBlack,它是不变的,为250 Hz。可以改变Callibri/Kolibri MF的采样频率,可取值为:

  • 125 Hz
  • 250 Hz
  • 500 Hz
  • 1000 Hz
  • 2000 Hz

如果尝试为设备设置不受支持的值,将会抛出异常。

FSensorSamplingFrequency samplingFrequency = await sensor.samplingFrequency.value;

// 仅适用于Callibri/Kolibri MF
await callibri.samplingFrequency.set(FSensorSamplingFrequency.hz1000);
增益

ADC信号增益。输入信号增益越高,噪声越小,但输入信号的最大幅度也越低。对于Callibi/Kolibri,你可以设置所需的值。Callibri/Kolibri EMS不支持此功能。

设备使用24位ADC,但最后3位未使用(丢弃)以优化无线电通道上的数据流。一个位的权重计算公式为 Wbit = (2*2.4) / ( (pow(2,21) - 1) * Gain ) 伏特

Callibri MF和BrainBit的可用值为:

  • 1
  • 2
  • 3
  • 4
  • 6
  • 8
  • 12
FSensorGain gain = await sensor.gain.value;
...
await sensor.gain.set(FSensorGain.gain6);

如果尝试为设备设置不受支持的值,将会抛出异常。

偏移

信号偏移。对于BrainBit和BrainBitBlack是不变的,为0。对于Callibri/Kolibri MF,你可以设置所需的值。Callibri/Kolibri EMS不支持此功能。

Callibri MF的可用值为:

  • 0
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
FSensorDataOffset offset = await sensor.dataOffset.value;

// 仅适用于Callibri/Kolibri MF
await sensor.dataOffset.set(FSensorDataOffset.dataOffset3);

如果尝试为设备设置不受支持的值,将会抛出异常。

固件版本

设备固件版本信息。

FSensorVersion version = await sensor.version.value;

FSensorVersion:

字段 类型 描述
fwMajor int 固件主版本
fwMinor int 固件次版本
fwPatch int 固件补丁版本
hwMajor int 硬件主版本
hwMinor int 硬件次版本
hwPatch int 硬件补丁版本
extMajor int 扩展主版本
电池电量

电池电量值。整数值。

int battery = await sensor.battPower.value;
设备家族

设备类型。枚举。

FSensorFamily sensFamily = await sensor.sensFamily.value;
功能

每个设备都有特定的一组模块。你可以使用 Feature 属性找出设备有哪些模块:

Set<FSensorFeature> features = await sensor.features.value;

你还可以检查设备是否支持特定功能,例如 Signal

if (await callibri.isSupportedFeature(FSensorFeature.signal)) {
  ...
}
命令

设备可以执行某些命令。可以使用以下方式获取支持的命令列表:

Set<FSensorCommand> commands = await sensor.commands.value;

你还可以检查设备是否可以执行所需命令:

if(await sensor.isSupportedCommand(FSensorCommand.startSignal)){
  ...              
}
BrainBit, BrainBitBlack

BrainBit和BrainBitBlack是一款带有4个电极和4个数据通道(O1、O2、T3、T4)的头带。设备的频率为250 Hz,这意味着每个通道每秒将收到250个样本。你只能更改信号的 增益。其他参数不能更改,尝试更改会引发异常。

重要! 你可以通过 固件版本号 来区分BrainBit设备和Flex:如果 SensorVersion.FwMajor 大于100,则为Flex;如果小于则为BrainBit。

重要! BrainBitBlack不同于BrainBit,需要与PC/移动设备配对。因此,在连接到BrainBitBlack之前,必须将其置于配对模式。SDK会自动开始配对过程。

接收信号

要接收信号数据,需要订阅相应的回调。值将以四个通道的数据包形式接收,这将避免它们之间的失步。值以伏特为单位。为了让设备开始传输数据,需要使用 execute 命令启动信号。该方法也建议在单独的线程中运行。

StreamSubscription<List<BrainBitSignalData>>? signalSubscription = sensor.signalDataStream.listen((data) => print("Signal values: $data"));
await sensor.execute(FSensorCommand.startSignal);
...
signalSubscription.cancel();
await sensor.execute(FSensorCommand.stopSignal);

你接收的信号值是一个包含以下字段的样本列表:

字段 类型 描述
packNum int 数据包编号
marker int 如果设备支持此功能,则为样本标记
o1 double O1通道的值(伏特)
o2 double O2通道的值(伏特)
t3 double T3通道的值(伏特)
t4 double T4通道的值(伏特)

重要! PackNum 不得超过2047。

Ping信号

一些设备支持使用信号ping检查信号质量的功能。你可以向设备发送特定值(标记),设备将在下一个信号数据包中返回该标记。标记是一个大小为一个字节的小值。

可用:BrainBitBlack和BrainBit2 / Flex / Pro

await sensor.pingNeuroSmart(5);
接收电阻

BrainBit和BrainBitBlack还允许你获取电阻值。借助这些值,你可以确定电极与皮肤接触的质量。初始电阻值为无穷大。当BB放在头上时,值会发生变化。

对于BrainBit,电阻的上限为2.5欧姆。

StreamSubscription<BrainBitResistData>? resistSubscription = sensor.resistDataStream.listen((data) => print("resist values: $data"));
await sensor.execute(FSensorCommand.startResist);
...
resistSubscription.cancel();
await sensor.execute(FSensorCommand.stopResist);

你接收的电阻值结构为每个通道的样本结构:

字段 类型 描述
o1 double O1通道的值(欧姆)
o2 double O2通道的值(欧姆)
t3 double T3通道的值(欧姆)
t4 double T4通道的值(欧姆)
BrainBit 2/Flex/Pro

BrainBit2类设计用于与多个设备家族一起工作:BrainBit 2、BrainBit Pro、BrainBit Flex、BrainBit Flex Pro。所有设备的采样频率均为250Hz。所有设备可以分别在信号和电阻模式下工作。这些设备具有不同数量的通道——BrainBit2、BrainBit Flex各有4个通道,而BrainBitPro、BrainBit FlexPro各有8个通道。与第一版BrainBit的主要区别在于,它们不支持增益属性,但可以使用 BrainBit2AmplifierParam 结构为每个通道单独设置增益。此外,这些类型的设备支持 ping命令

通道信息

设备可以有4个或8个通道。通道的数量可以通过以下方式确定:

List<FEEGChannelInfo?> channels = await sensor.supportedChannels.value;

FEEGChannelInfo 包含一些信息:

字段 类型 描述
id EEGChannelId 电极的物理位置。你会收到 o1o2t3t4unknown 的值。unknown 表示特定电极的位置是空的。
chType EEGChannelType 通道类型,可能的值为 singleA1singleA2differentialref
name String 通道名称
num int 通道编号。按此编号,通道将位于信号或电阻值数组中的位置

你也可以只检查通道数量而不获取信息:

int channelsCount = await sensor.channelsCount.value;
放大器模式

该设备可以显示其当前放大器模式。它可以处于以下状态之一:

  • Invalid
  • PowerDown
  • Idle
  • Signal
  • Resist

你可以通过两种方式检查放大器模式:

  1. 通过回调:
StreamSubscription<FSensorAmpMode>? ampModeSubscription = sensor.ampModeStream.listen((mode) => print("Amp mode: $mode"));
...
ampModeSubscription.cancel();
  1. 在任何时候获取值:
FSensorAmpMode mode = await sensor.ampMode.value;

对于BrainBit2设备来说,这是一个非常重要的参数,因为只有在设备处于 PowerDownIdle 模式时才能设置放大器参数。

放大器参数

你可以通过设置放大器参数来配置每个通道和整个设备的设置。

int chCount = await sensor.channelsCount.value;
BrainBit2AmplifierParam param = BrainBit2AmplifierParam(
    chSignalMode: List.filled(chCount, FBrainBit2ChannelMode.chModeNormal),
    chResistUse: List.filled(chCount, true),
    chGain: List.filled(chCount, SensorGain.gain3),
    current: GenCurrent.genCurr6nA);
await sensor.amplifierParam.set(param);

BrainBit2AmplifierParam 包含:

字段 类型 描述
chSignalMode List 输入类型
chResistUse List 当前版本未使用
chGain List 每个通道的ADC信号增益
current GenCurrent 设置探针电流发生器的参数

Current 的可能值:

  • 0nA
  • 6nA
  • 12nA
  • 18nA
  • 24nA

信号模式:

  • Short - 短路输入
  • Normal - 差分输入模式(用于EEG)

Gain 的可能值:

  • 1
  • 2
  • 3
  • 4
  • 6
  • 8
  • 12
接收信号

要接收信号数据,需要订阅相应的回调。值以伏特为单位。为了让设备开始传输数据,需要使用 execute 命令启动信号。该方法也建议在单独的线程中运行。

StreamSubscription<List<SignalChannelsData>>? signalSubscription = sensor.signalDataStream.listen((data) => print("Signal values: $data"));
await sensor.execute(FSensorCommand.startSignal);
...
signalSubscription.cancel();
await sensor.execute(FSensorCommand.stopSignal);

你接收的信号值是一个样本列表 (SignalChannelsData),每个包含:

字段 类型 描述
packNum int 数据包编号
marker int 样本标记
samples List
接收电阻

BrainBit2还可以让你获取电阻值。借助这些值,你可以确定电极与皮肤接触的质量。初始电阻值为无穷大。当设备在头上时,值会发生变化。

StreamSubscription<List<ResistRefChannelsData>>? resistSubscription = sensor.resistDataStream.listen((data) => print("resist values: $data"));
await sensor.execute(FSensorCommand.startResist);
...
resistSubscription.cancel();
await sensor.execute(FSensorCommand.stopResist);

你接收的电阻值结构为每个通道的样本结构 (ResistRefChannelsData):

字段 类型 描述
packNum int 数据包编号
samples List 样本数组。每个样本编号与 FEEGChannelInfoNum 值一致。
referents List 参考通道的值数组。对于BrainBit2传感器现在为空。
Callibri MF/ Kolibri MF

Callibri设备系列拥有广泛内置模块。对于每个模块,SDK包含自己的处理区域。在使用任何模块之前,建议使用 IsSupportedFeatureIsSupportedCommandIsSupportedParameter 方法检查模块是否受设备支持。

参数
运动计数器参数包

运动计数器参数。

// 检查是否受支持
if (await sensor.isSupportedParameter(FSensorParameter.motionCounterParamPack)) {
  // 获取
  FCallibriMotionCounterParam param = await sensor.motionCounterParam.value;  
  // 设置
  await sensor.motionCounterParam.set(CallibriMotionCounterParam(insenseThresholdMG: 100, insenseThresholdSample: 200));
}

CallibriMotionCounterParam:

字段 类型 描述
insenseThresholdMG int Insense阈值mg。0…500
insenseThresholdSample int 算法Insense阈值(以MEMS采样率的样本数表示)。0…500
运动计数器

包含运动次数。此参数仅适用于Callibi/Kolibri。一个不可更改的数值。

// 检查是否受支持
if (await sensor.isSupportedParameter(FSensorParameter.motionCounter)) {
  // 获取
  int = await sensor.motionCounter.value;
}
硬件滤波器

设备信号滤波器活动状态。如果参数受设备支持,则可以通过 HardwareFilters 属性设置所需的滤波器。可用的滤波器如下:

  • HPFBwhLvl1CutoffFreq1Hz - 1Hz截止频率的高通滤波器
  • HPFBwhLvl1CutoffFreq5Hz - 5Hz截止频率的高通滤波器
  • BSFBwhLvl2CutoffFreq45_55Hz - 50Hz陷波滤波器
  • BSFBwhLvl2CutoffFreq55_65Hz - 60Hz陷波滤波器
  • HPFBwhLvl2CutoffFreq10Hz - 10Hz截止频率的高通滤波器
  • LPFBwhLvl2CutoffFreq400Hz - 400Hz截止频率的低通滤波器(仅适用于1000Hz采样)
  • HPFBwhLvl2CutoffFreq80Hz - 80Hz截止频率的高通滤波器

启用滤波器之前,请检查设备是否支持所需的滤波器。

注意! 设置包含 LPFBwhLvl2CutoffFreq400Hz 的硬件滤波器列表不会发生在Callibri MF传感器上,除非采样频率为1000Hz。

// 支持的滤波器
Set<FSensorFilter> filters = await sensor.supportedFilters.value;

// 读取启用的滤波器
Set<FSensorFilter> filtersOn = await sensor.hardwareFilters.value;

// 启用滤波器
if(await sensor.isSupportedFilter(FSensorFilter.BSFBwhLvl2CutoffFreq45_55Hz)){
  await sensor.hardwareFilters.set({FSensorFilter.BSFBwhLvl2CutoffFreq45_55Hz});                
}
外部开关状态

切换信号源。此参数仅适用于Callibi/Kolibri。它可取以下值之一:

  • ExtSwInElectrodesRespUSB - 呼吸通道数据源为USB连接。肌电信道数据源为终端。
  • ExtSwInElectrodes - 终端是肌电信道数据源。呼吸通道未使用。
  • ExtSwInUSB - 肌电信道数据源为USB连接。呼吸通道未使用。
  • ExtSwInRespUSB - 呼吸通道数据源为USB连接。肌电信道未使用。
// 检查是否受支持参数
if (await sensor.isSupportedParameter(FSensorParameter.externalSwitchState)) {
  // 获取
  FSensorExternalSwitchInput sensorExternalSwitchInput = await sensor.extSwInput.value;

  // 设置
  await sensor.extSwInput.set(FSensorExternalSwitchInput.electrodesRespUSB);
}
ADC输入状态

ADC(模拟到数字转换器)输入的状态值。此属性仅适用于Callibi/Kolibri。它可取以下值之一:

  • Electrodes - 电极输入。此模式设计用于从应用点接收生理信号。
  • Short - 输入短路。此模式设计用于关闭输出。输出会有基线噪声或0伏电压水平。
  • Test - ADC测试输入。此模式用于检查ADC操作的正确性。输出应为频率为1Hz、幅值为+/- 1mV的方波信号。
  • Resistance - 测量电极间电阻的输入。此模式设计用于测量电极间电阻以及获取生理信号。这是推荐的默认模式。
// 检查是否受支持参数
if (await sensor.isSupportedParameter(FSensorParameter.adcInputState)) {
  // 获取
  FSensorADCInput sensorAdcInput = await sensor.adcInput.value;

  // 设置
  await sensor.adcInput.set(FSensorADCInput.electrodes);
}
加速度计灵敏度

加速度计的灵敏度值,如果设备支持的话。此属性仅适用于Callibi/Kolibri。在使用之前建议检查MEMS模块的存在。它可以取以下值之一:

  • 2g - 正常灵敏度。最小值。适合实际使用。
  • 4g - 提高灵敏度。
  • 8g - 高灵敏度。
  • 16g - 最大灵敏度。
// 检查是否受支持参数
if (await sensor.isSupportedParameter(FSensorParameter.accelerometerSens)) {

  // 获取  
  FSensorAccelerometerSensitivity sensorAccelerometerSensitivity = await sensor.accSens.value;

  // 设置
  await sensor.accSens.set(FSensorAccelerometerSensitivity.accSens2g);
}
陀螺仪灵敏度

陀螺仪增益值,如果设备支持的话。建议在使用前检查MEMS模块的存在。它可以取以下值之一:

  • 250Grad - 测量角速度的值范围为0到2000度/秒。推荐用于角度测量。
  • 500Grad - 测量角速度的值范围为0到1000度/秒。
  • 1000Grad - 测量角速度的值范围为0到500度/秒。
  • 2000Grad - 测量角速度的值范围为0到250度/秒。
// 检查是否受支持参数
if (await sensor.isSupportedParameter(FSensorParameter.gyroscopeSens)) {

  // 获取  
  FSensorGyroscopeSensitivity gyroSens = await sensor.gyroSens.value;

  // 设置
  await sensor.gyroSens.set(FSensorGyroscopeSensitivity.gyroSens250Grad);
}
MEMS校准状态

MEMS传感器的校准状态。仅适用于Callibri/Kolibri MF。条件类型。

// 检查是否受支持参数
if (await sensor.isSupportedParameter(FSensorParameter.memsCalibrationStatus)) {
  // 获取  
  if(await sensor.memsCalibrateState.value){
    ...
  }
}
MEMS采样频率

更新MEMS值的频率。不变值。适用于支持MEMS的Callibri/Kolibri。

// 检查是否受支持参数
if (await sensor.isSupportedParameter(FSensorParameter.samplingFrequencyMEMS)) {
  // 获取  
  FSensorSamplingFrequency memsFrequency = await sensor.samplingFrequencyMEMS.value;
}
呼吸采样频率

更新呼吸值的频率。不变值。适用于支持呼吸的Callibri/Kolibri。

// 检查是否受支持参数
if (await sensor.isSupportedParameter(SensorParameter.samplingFrequencyResp)) {
  // 获取  
  FSensorSamplingFrequency respFrequency = await sensor.samplingFrequencyResp.value;
}
包络采样频率

更新包络值的频率。不变值。适用于支持包络的Callibri/Kolibri。

// 检查是否受支持参数
if (await sensor.isSupportedParameter(SensorParameter.samplingFrequencyEnvelope)) {
  // 获取  
  FSensorSamplingFrequency envFreq = await sensor.samplingFrequencyEnvelope.value;
}
电极状态

Callibri/Kallibri MF设备的电极状态。可以在信号接收期间检查电极状态。

// 检查是否受支持参数
if (await sensor.isSupportedParameter(SensorParameter.electrodeState)) {
  // 获取  
  FCallibriElectrodeState electrodeState = await sensor.electrodeState.value;
}
接收信号

要接收信号数据,需要订阅相应的回调。值以伏特为单位。为了让设备开始传输数据,需要使用 execute 命令启动信号。该方法也建议在单独的线程中运行。

采样率可以通过 采样频率 属性控制。例如,在1000 Hz的频率下,设备每秒将发送1000个样本。支持的频率为125/250/500/1000/2000 Hz。你还可以调整信号偏移 (数据偏移) 和信号功率 (增益)。

StreamSubscription<List<CallibriSignalData>>? signalSubscription = sensor.signalDataStream.listen((data) => print("Signal values: $data"));
await sensor.execute(FSensorCommand.startSignal);
...
signalSubscription.cancel();
await sensor.execute(FSensorCommand.stopSignal);

你接收的信号值是一个样本列表,每个包含:

字段 类型 描述
packNum int 数据包编号
samples List 样本数组(伏特)
信号设置

默认情况下,Callibri/Kolibri给出的信号没有滤波器。为了接收某种类型的信号,例如EEG或ECG,你需要以特定的方式配置设备。为此,有一个 信号类型Callibri 属性。预设的信号类型包括:

  • EEG - 参数:增益6,偏移=3,ADC输入电阻
  • EMG - 参数:增益6,偏移=3,ADC输入电阻
  • ECG - 参数:增益6,偏移=3,ADC输入电阻
  • EDA (GSR) - 参数:增益6,偏移=8,ADC输入电阻,外部开关输入电极。默认设置为终端输入。如果你想改为USB,可以使用 外部开关状态 属性。
  • TenzoBreathing - 参数:增益8,偏移=4,ADC输入电阻,外部开关输入USB
  • StrainGaugeBreathing - 参数:增益6,偏移=4,ADC输入电阻,外部开关输入USB
  • ImpedanceBreathing - 参数:增益6,偏移=4,ADC输入电阻,外部开关输入呼吸USB

硬件滤波器默认对所有信号类型禁用。你可以通过 硬件滤波器 属性启用滤波器,例如低通滤波器。

重要! 在传感器中使用低通滤波器时,你将看不到信号的直流成分。

信号类型Callibri:

字段
EEG 0
EMG 1
ECG 2
EDA 3
strainGaugeBreathing 4
impedanceBreathing 5
tenzoBreathing 6
unknown 7
// 获取
CallibriSignalType signalType = await sensor.signalType.value;
// 设置
await sensor.signalType.set(CallibriSignalType.EMG);
接收包络

要获取包络值,需要订阅特定事件并启动拾取。通道必须按照正常信号的方式配置,所有参数的作用方式相同。然后信号将被滤波并以20 Hz的频率降采样。

StreamSubscription<List<CallibriEnvelopeData>>? envelopeSubscription = sensor.envelopeDataStream.listen((data) { print(data); });
await sensor.execute(FSensorCommand.startEnvelope);
...
envelopeSubscription.cancel();
await sensor.execute(FSensorCommand.stopEnvelope);

你接收的信号值是一个样本列表,每个包含:

字段 类型 描述
packNum int 数据包编号
sample double 样本(伏特)
检查电极状态

允许确定设备电极与人体皮肤的电气接触状态。它可以处于三种状态之一:

  • Normal - 电极与皮肤正常接触。电极间的电气电阻低。这是在使用生理信号时的预期状态。
  • Detached - 电极间的电气电阻高。生理信号干扰的概率很高。
  • HighResistance - 设备电极之间没有电气接触。

要接收数据,需要订阅相应的回调并启动信号拾取。

StreamSubscription<FCallibriElectrodeState>? electrodeSubscription = callibri.electrodeStateStream.listen((state) { print(state); });
await sensor.execute(FSensorCommand.startSignal);
...
electrodeSubscription.cancel();
await sensor.execute(FSensorCommand.stopSignal);
接收呼吸

呼吸微电路是按需选配的。它的存在可以通过 IsSupportedFeature 方法检查。要接收数据,需要连接到设备,订阅数据接收通知并开始拾取。

StreamSubscription<List<CallibriRespirationData>>? respSubscription = sensor.respirationDataStream.listen((event) { print(event); });
await sensor.execute(FSensorCommand.startRespiration);
...
respSubscription.cancel()
await sensor.execute(FSensorCommand.stopRespiration);

更多关于Flutter神经网络处理插件neurosdk2的使用的实战教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter神经网络处理插件neurosdk2的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


当然,下面是一个关于如何在Flutter中使用neurosdk2插件进行神经网络处理的示例代码。这个示例将展示如何初始化插件、加载模型并进行推理。

首先,确保你已经在pubspec.yaml文件中添加了neurosdk2插件的依赖:

dependencies:
  flutter:
    sdk: flutter
  neurosdk2: ^latest_version  # 替换为实际的最新版本号

然后,运行flutter pub get来安装依赖。

接下来是示例代码:

import 'package:flutter/material.dart';
import 'package:neurosdk2/neurosdk2.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatefulWidget {
  @override
  _MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  NeuroSDK? _neuroSDK;
  String _result = "";

  @override
  void initState() {
    super.initState();
    _initNeuroSDK();
  }

  void _initNeuroSDK() async {
    // 初始化NeuroSDK
    _neuroSDK = await NeuroSDK.initialize(
      licenseKey: "YOUR_LICENSE_KEY",  // 替换为你的许可证密钥
      onError: (error) {
        print("NeuroSDK initialization error: $error");
      },
    );

    if (_neuroSDK != null) {
      // 加载模型
      await _loadModel();
    }
  }

  void _loadModel() async {
    try {
      // 替换为你的模型文件路径
      String modelPath = "path/to/your/model.tflite";
      await _neuroSDK!.loadModel(modelPath: modelPath);
      print("Model loaded successfully");
    } catch (e) {
      print("Failed to load model: $e");
    }
  }

  void _performInference() async {
    if (_neuroSDK == null) return;

    // 创建输入数据
    // 假设模型输入是一个形状为 [1, 224, 224, 3] 的图像数据
    List<List<Float32List>> inputData = [
      [Float32List.fromList(/* 输入数据,例如预处理后的图像数据 */)]
    ];

    // 执行推理
    var result = await _neuroSDK!.runInference(inputData: inputData);

    // 处理结果
    setState(() {
      _result = "Inference Result: ${result.outputs[0].toString()}";
    });
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text('NeuroSDK2 Demo'),
        ),
        body: Center(
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: <Widget>[
              Text('Neural Network Inference Result:'),
              Text(_result),
              SizedBox(height: 20),
              ElevatedButton(
                onPressed: _performInference,
                child: Text('Run Inference'),
              ),
            ],
          ),
        ),
      ),
    );
  }
}

在这个示例中:

  1. MyApp 是一个Flutter应用的主类,它包含一个NeuroSDK实例。
  2. initState方法中,我们初始化NeuroSDK并加载模型。
  3. _performInference方法用于执行推理,并将结果显示在屏幕上。

请注意:

  • 替换YOUR_LICENSE_KEY为你的实际许可证密钥。
  • 替换path/to/your/model.tflite为你的实际模型文件路径。
  • 输入数据inputData需要根据你的模型输入格式进行预处理。

这个示例提供了一个基本的框架,你可能需要根据实际的模型输入和输出格式进行进一步的处理和调整。

回到顶部