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 | 电极的物理位置。你会收到 o1 、o2 、t3 、t4 或 unknown 的值。unknown 表示特定电极的位置是空的。 |
chType | EEGChannelType | 通道类型,可能的值为 singleA1 、singleA2 、differential 或 ref |
name | String | 通道名称 |
num | int | 通道编号。按此编号,通道将位于信号或电阻值数组中的位置 |
你也可以只检查通道数量而不获取信息:
int channelsCount = await sensor.channelsCount.value;
放大器模式
该设备可以显示其当前放大器模式。它可以处于以下状态之一:
- Invalid
- PowerDown
- Idle
- Signal
- Resist
你可以通过两种方式检查放大器模式:
- 通过回调:
StreamSubscription<FSensorAmpMode>? ampModeSubscription = sensor.ampModeStream.listen((mode) => print("Amp mode: $mode"));
...
ampModeSubscription.cancel();
- 在任何时候获取值:
FSensorAmpMode mode = await sensor.ampMode.value;
对于BrainBit2设备来说,这是一个非常重要的参数,因为只有在设备处于 PowerDown
或 Idle
模式时才能设置放大器参数。
放大器参数
你可以通过设置放大器参数来配置每个通道和整个设备的设置。
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 | 样本数组。每个样本编号与 FEEGChannelInfo 的 Num 值一致。 |
referents | List | 参考通道的值数组。对于BrainBit2传感器现在为空。 |
Callibri MF/ Kolibri MF
Callibri设备系列拥有广泛内置模块。对于每个模块,SDK包含自己的处理区域。在使用任何模块之前,建议使用 IsSupportedFeature
、IsSupportedCommand
或 IsSupportedParameter
方法检查模块是否受设备支持。
参数
运动计数器参数包
运动计数器参数。
// 检查是否受支持
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
更多关于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'),
),
],
),
),
),
);
}
}
在这个示例中:
MyApp
是一个Flutter应用的主类,它包含一个NeuroSDK
实例。- 在
initState
方法中,我们初始化NeuroSDK
并加载模型。 _performInference
方法用于执行推理,并将结果显示在屏幕上。
请注意:
- 替换
YOUR_LICENSE_KEY
为你的实际许可证密钥。 - 替换
path/to/your/model.tflite
为你的实际模型文件路径。 - 输入数据
inputData
需要根据你的模型输入格式进行预处理。
这个示例提供了一个基本的框架,你可能需要根据实际的模型输入和输出格式进行进一步的处理和调整。