This commit is contained in:
2026-06-08 22:58:58 +08:00
parent c8d8f24bf0
commit 256d00f42d
5 changed files with 533 additions and 0 deletions

View File

@@ -146,6 +146,20 @@ void MinimalExampleFor8ChImpedanceCommand()
}
}
void MinimalExampleForTriggerCommand()
{
std::array<std::uint8_t, 3> command{};
const int command_size = XYParser_SerializeTriggerCommand(
XYPARSER_TRIGGER_TRAIN_0,
command.data(),
command.size());
if (command_size == static_cast<int>(command.size())) {
const std::uint8_t event_code = command[2];
(void)event_code;
}
}
void MinimalExampleForImpedanceOutput()
{
XYParserHandle parser = XYParser_CreateParser(8);

View File

@@ -18,6 +18,7 @@ namespace {
constexpr std::uint8_t kCommandFrameHeader = 0xAA;
constexpr std::uint8_t kCommandFrameTail = 0x55;
constexpr std::size_t k8ChImpedanceCommandSize = 7;
constexpr std::size_t kTriggerCommandSize = 3;
constexpr int k8ChLeadCount = 8;
constexpr int k64ChLeadCount = 64;
constexpr std::uint8_t kAlgorithmChannelCount = 64;
@@ -51,6 +52,23 @@ std::array<std::uint8_t, k8ChImpedanceCommandSize> Build8ChImpedanceCommand(bool
kCommandFrameTail};
}
bool IsSupportedTriggerType(std::uint8_t trigger_type)
{
switch (trigger_type) {
case XYPARSER_TRIGGER_NONE:
case XYPARSER_TRIGGER_TRAIN_0:
case XYPARSER_TRIGGER_TRAIN_1:
return true;
default:
return false;
}
}
std::array<std::uint8_t, kTriggerCommandSize> BuildTriggerCommand(std::uint8_t trigger_type)
{
return {0x00, 0x00, trigger_type};
}
constexpr std::array<XYParserLeadChannelNumber, k8ChLeadCount> k8ChLeadMap = {
LeadChannel_PO5, LeadChannel_POZ, LeadChannel_PO6, LeadChannel_PO7,
LeadChannel_O1, LeadChannel_OZ, LeadChannel_O2, LeadChannel_PO8};
@@ -383,6 +401,24 @@ std::size_t XYParser_Get64ImpedanceCommandSize(void)
return XYEegParser64::kImpedanceCommandSize;
}
std::size_t XYParser_GetTriggerCommandSize(void)
{
return kTriggerCommandSize;
}
int XYParser_SerializeTriggerCommand(std::uint8_t trigger_type,
std::uint8_t* out_command,
std::size_t command_size)
{
if (out_command == nullptr || command_size < kTriggerCommandSize || !IsSupportedTriggerType(trigger_type)) {
return 0;
}
const auto command = BuildTriggerCommand(trigger_type);
std::copy(command.begin(), command.end(), out_command);
return static_cast<int>(command.size());
}
std::size_t XYParser_Get64GainSampleRateCommandSize(void)
{
return XYEegParser64::kGainSampleRateCommandSize;

View File

@@ -30,6 +30,12 @@ enum XYParser8ChImpedanceSwitch : std::uint8_t {
XYPARSER_8CH_IMPEDANCE_OPEN = 0xA1
};
enum XYParserTriggerType : std::uint8_t {
XYPARSER_TRIGGER_NONE = 0x00,
XYPARSER_TRIGGER_TRAIN_0 = 0xBB,
XYPARSER_TRIGGER_TRAIN_1 = 0xBC
};
enum XYParserLeadChannelNumber {
LeadChannel_FP1 = 0,
LeadChannel_FP2,
@@ -213,6 +219,20 @@ XYPARSER_API int XYParser_Serialize8ChImpedanceCommand(int open,
std::uint8_t* out_command,
std::size_t command_size);
// Get trigger command size.
// @return Size in bytes of the trigger command.
XYPARSER_API std::size_t XYParser_GetTriggerCommandSize(void);
// Serialize a trigger command.
// Packet layout matches WirelessEEG TriggerEventStruct: 2 reserved bytes + 1 trigger byte.
// @param trigger_type Trigger code to send. Prefer values from XYParserTriggerType.
// @param out_command Output buffer for serialized bytes.
// @param command_size Size of output buffer in bytes.
// @return Number of bytes written on success, or 0 on failure.
XYPARSER_API int XYParser_SerializeTriggerCommand(std::uint8_t trigger_type,
std::uint8_t* out_command,
std::size_t command_size);
// 获取 64 导阻抗命令的字节长度。
// @return 64 导阻抗命令的字节长度。
XYPARSER_API std::size_t XYParser_Get64ImpedanceCommandSize(void);

View File

@@ -223,6 +223,31 @@ TEST(XYParserApiTests, Get8ChImpedanceCommandSizeMatchesSerializedLength)
EXPECT_EQ(XYParser_Get8ChImpedanceCommandSize(), static_cast<std::size_t>(7));
}
TEST(XYParserApiTests, SerializeTriggerCommandMatchesWirelessEegPacket)
{
std::array<std::uint8_t, 8> command{};
const int command_size = XYParser_SerializeTriggerCommand(
XYPARSER_TRIGGER_TRAIN_0,
command.data(),
command.size());
ASSERT_EQ(command_size, static_cast<int>(XYParser_GetTriggerCommandSize()));
const std::array<std::uint8_t, 3> expected = {0x00, 0x00, 0xBB};
EXPECT_TRUE(std::equal(expected.begin(), expected.end(), command.begin()));
}
TEST(XYParserApiTests, SerializeTriggerCommandRejectsUnsupportedTriggerType)
{
std::array<std::uint8_t, 8> command{};
EXPECT_EQ(XYParser_SerializeTriggerCommand(0xAA, command.data(), command.size()), 0);
}
TEST(XYParserApiTests, SerializeTriggerCommandRejectsSmallBuffer)
{
std::array<std::uint8_t, 2> command{};
EXPECT_EQ(XYParser_SerializeTriggerCommand(XYPARSER_TRIGGER_TRAIN_1, command.data(), command.size()), 0);
}
TEST(XYParserApiTests, GetAlgorithmDataValueCountMatchesFrameLayout)
{
EXPECT_EQ(XYParser_GetAlgorithmDataValueCount(),

438
XYParserDataFlow.md Normal file
View File

@@ -0,0 +1,438 @@
# XYParser 数据流与接口时序说明
## 1. 参与角色
- **64导EEG采集设备**
- 持续输出原始 EEG 字节流。
- **上位机**
- 负责接收设备数据、调用 XYParser 库、对接算法模块。
- **XYParser 库**
- 负责帧解析、阻抗计算、算法数据回灌后的 Welch/PSD 计算。
- **算法**
- 接收上位机送入的算法数据,并输出用于 PSD/Welch 计算的数据。
## 2. 总体链路
当前流程可以分为两个阶段:
- **阶段一:阻抗检测阶段**
- 设备连接后,首先下发采样率和增益配置命令。
- 然后下发阻抗开启命令。
- 在该阶段持续接收设备数据,并通过 `XYParser_ReadImpedance` 读取阻抗结果。
- 阻抗检测结束后,下发阻抗关闭命令。
- **阶段二:常规采集与算法阶段**
- 基于 `XYParser_Feed` 解析得到的帧数据继续做常规采集。
- 帧数据先转换为算法数据,再送入算法模块。
- Welch/PSD 不再直接基于帧解析结果计算,而是基于算法数据,通过 `XYParser_FeedAlgorithmData` 输入后计算。
## 3. 接口时序图
### 3.1 64导初始化连接阶段
```mermaid
%%{init: {'theme': 'default', 'sequence': {'diagramMarginX': 80, 'diagramMarginY': 30, 'actorMargin': 80, 'width': 220, 'height': 80, 'messageMargin': 35}}}%%
sequenceDiagram
participant Dev as 64导EEG采集设备
participant Host as 上位机
participant Lib as XYParser库
Dev-->>Host: 设备连接成功
Host->>Lib: parser64 = XYParser_CreateParser(64)
Host->>Lib: XYParser_SetAdcParams(parser64, 4.5, 6.0)
Host->>Lib: XYParser_SetSampleRate(parser64, 250)
Host->>Lib: XYParser_SetBypassChecksum(parser64, 0)
Host->>Lib: gain_cmd_size = XYParser_Get64GainSampleRateCommandSize()
Lib-->>Host: gain_cmd_size
Host->>Lib: gain_cmd_bytes = XYParser_Serialize64GainSampleRateCommand(6, 250, gain_cmd_buf, gain_cmd_size)
Lib-->>Host: gain_cmd_bytes
Host->>Dev: 下发采样率250、增益6命令
```
### 3.2 64导阻抗阶段
```mermaid
%%{init: {'theme': 'default', 'sequence': {'diagramMarginX': 80, 'diagramMarginY': 30, 'actorMargin': 80, 'width': 220, 'height': 80, 'messageMargin': 35}}}%%
sequenceDiagram
participant Dev as 64导EEG采集设备
participant Host as 上位机
participant Lib as XYParser库
Host->>Lib: XYParser_SetImpedanceDetection(parser64, 1)
Host->>Lib: impedance_gain_cmd_size = XYParser_Get64GainSampleRateCommandSize()
Lib-->>Host: impedance_gain_cmd_size
Host->>Lib: impedance_gain_cmd_bytes = XYParser_Serialize64GainSampleRateCommand(24, 250, impedance_gain_cmd_buf, impedance_gain_cmd_size)
Lib-->>Host: impedance_gain_cmd_bytes
Host->>Dev: 下发采样率250、增益24命令
Host->>Lib: impedance_cmd_size = XYParser_Get64ImpedanceCommandSize()
Lib-->>Host: impedance_cmd_size
Host->>Lib: open_impedance_bytes = XYParser_Serialize64ImpedanceCommand(1, impedance_cmd_buf, impedance_cmd_size)
Lib-->>Host: open_impedance_bytes
Host->>Dev: 下发阻抗开启命令
loop 持续获取阻抗
Dev-->>Host: 原始EEG字节流
Host->>Lib: frame_count = XYParser_Feed(parser64, raw_data, raw_size, frame_summaries, max_frames)
Lib-->>Host: frame_count + frame_summaries
Host->>Lib: impedance_count = XYParser_ReadImpedance(parser64, impedance_summaries, max_impedance)
Lib-->>Host: impedance_count + impedance_summaries
end
Host->>Lib: close_impedance_bytes = XYParser_Serialize64ImpedanceCommand(0, impedance_cmd_buf, impedance_cmd_size)
Lib-->>Host: close_impedance_bytes
Host->>Dev: 下发阻抗关闭命令
Host->>Lib: restore_gain_cmd_size = XYParser_Get64GainSampleRateCommandSize()
Lib-->>Host: restore_gain_cmd_size
Host->>Lib: restore_gain_cmd_bytes = XYParser_Serialize64GainSampleRateCommand(6, 250, restore_gain_cmd_buf, restore_gain_cmd_size)
Lib-->>Host: restore_gain_cmd_bytes
Host->>Dev: 下发采样率250、增益6命令
Host->>Lib: XYParser_SetImpedanceDetection(parser64, 0)
```
### 3.3 64导算法阶段
```mermaid
%%{init: {'theme': 'default', 'sequence': {'diagramMarginX': 80, 'diagramMarginY': 30, 'actorMargin': 80, 'width': 220, 'height': 80, 'messageMargin': 35}}}%%
sequenceDiagram
participant Dev as 64导EEG采集设备
participant Host as 上位机
participant Lib as XYParser库
participant Algo as 算法
Host->>Lib: XYParser_SetWelchDetection(parser64, 1)
loop 持续采集
Dev-->>Host: 原始EEG字节流
Host->>Lib: frame_count = XYParser_Feed(parser64, raw_data, raw_size, frame_summaries, max_frames)
Lib-->>Host: frame_count + frame_summaries
Host->>Lib: value_count = XYParser_GetAlgorithmDataValueCount()
Lib-->>Host: value_count
Host->>Lib: ok = XYParser_ConvertSampleFramesToAlgorithmData(frame_summary, algorithm_input_data)
Lib-->>Host: ok + algorithm_input_data
Host->>Algo: 输入算法数据 algorithm_input_data
Algo-->>Host: 算法输出数据 algorithm_output_bytes
Host->>Lib: alg_frame_count = XYParser_FeedAlgorithmData(parser64, algorithm_output_bytes, algorithm_output_size, algorithm_frames, max_algorithm_frames)
Lib-->>Host: alg_frame_count + algorithm_frames
Host->>Lib: welch_count = XYParser_ReadWelch(parser64, welch_summaries, max_welch)
Lib-->>Host: welch_count + welch_summaries
end
opt 结束时处理尾数据
Host->>Lib: flushed = XYParser_FlushAlgorithmData(parser64, tail_frame_summary)
Lib-->>Host: flushed + tail_frame_summary
Host->>Lib: welch_count = XYParser_ReadWelch(parser64, welch_summaries, max_welch)
Lib-->>Host: welch_count + welch_summaries
end
Host->>Lib: XYParser_DestroyParser(parser64)
```
### 3.4 64导训练打标阶段
```mermaid
%%{init: {'theme': 'default', 'sequence': {'diagramMarginX': 80, 'diagramMarginY': 30, 'actorMargin': 80, 'width': 220, 'height': 80, 'messageMargin': 35}}}%%
sequenceDiagram
participant Port as 64导EEG设备串口
participant Host as 上位机
participant Lib as XYParser库
participant Time as 时间
Host->>Lib: trigger_cmd_size = XYParser_GetTriggerCommandSize()
Lib-->>Host: trigger_cmd_size
Host->>Lib: train0_bytes = XYParser_SerializeTriggerCommand(XYPARSER_TRIGGER_TRAIN_0, trigger_cmd_buf, trigger_cmd_size)
Lib-->>Host: train0_bytes
Host->>Port: 发送 TRAIN_0 打标
Host->>Time: 开始训练计时
Time-->>Host: 训练时间到
Host->>Lib: train1_bytes = XYParser_SerializeTriggerCommand(XYPARSER_TRIGGER_TRAIN_1, trigger_cmd_buf, trigger_cmd_size)
Lib-->>Host: train1_bytes
Host->>Port: 发送 TRAIN_1 打标
```
### 3.5 8导初始化连接阶段
```mermaid
%%{init: {'theme': 'default', 'sequence': {'diagramMarginX': 80, 'diagramMarginY': 30, 'actorMargin': 80, 'width': 220, 'height': 80, 'messageMargin': 35}}}%%
sequenceDiagram
participant Dev as 8导EEG采集设备
participant Host as 上位机
participant Lib as XYParser库
Dev-->>Host: 设备连接成功
Host->>Lib: parser8 = XYParser_CreateParser(8)
Host->>Lib: XYParser_SetAdcParams(parser8, vref, gain)
Host->>Lib: XYParser_SetSampleRate(parser8, sample_rate)
Host->>Lib: XYParser_SetBypassChecksum(parser8, 0)
```
### 3.6 8导阻抗阶段
```mermaid
%%{init: {'theme': 'default', 'sequence': {'diagramMarginX': 80, 'diagramMarginY': 30, 'actorMargin': 80, 'width': 220, 'height': 80, 'messageMargin': 35}}}%%
sequenceDiagram
participant Dev as 8导EEG采集设备
participant Host as 上位机
participant Lib as XYParser库
Host->>Lib: XYParser_SetImpedanceDetection(parser8, 1)
Host->>Lib: impedance_cmd_size = XYParser_Get8ChImpedanceCommandSize()
Lib-->>Host: impedance_cmd_size
Host->>Lib: open_impedance_bytes = XYParser_Serialize8ChImpedanceCommand(1, impedance_cmd_buf, impedance_cmd_size)
Lib-->>Host: open_impedance_bytes
Host->>Dev: 下发阻抗开启命令
loop 持续获取阻抗
Dev-->>Host: 原始EEG字节流
Host->>Lib: frame_count = XYParser_Feed(parser8, raw_data, raw_size, frame8_summaries, max_frames)
Lib-->>Host: frame_count + frame8_summaries
Host->>Lib: impedance_count = XYParser_ReadImpedance(parser8, impedance_summaries, max_impedance)
Lib-->>Host: impedance_count + impedance_summaries
end
Host->>Lib: close_impedance_bytes = XYParser_Serialize8ChImpedanceCommand(0, impedance_cmd_buf, impedance_cmd_size)
Lib-->>Host: close_impedance_bytes
Host->>Dev: 下发阻抗关闭命令
Host->>Lib: XYParser_SetImpedanceDetection(parser8, 0)
```
### 3.7 8导算法阶段
```mermaid
%%{init: {'theme': 'default', 'sequence': {'diagramMarginX': 80, 'diagramMarginY': 30, 'actorMargin': 80, 'width': 220, 'height': 80, 'messageMargin': 35}}}%%
sequenceDiagram
participant Dev as 8导EEG采集设备
participant Host as 上位机
participant Lib as XYParser库
participant Algo as 算法
Host->>Lib: XYParser_SetWelchDetection(parser8, 1)
loop 持续采集
Dev-->>Host: 原始EEG字节流
Host->>Lib: frame_count = XYParser_Feed(parser8, raw_data, raw_size, frame8_summaries, max_frames)
Lib-->>Host: frame_count + frame8_summaries
Host->>Lib: converted = XYParser_Convert8ChFramesTo64Ch(frame8_summary, 1, frame64_summary, 1)
Lib-->>Host: converted + frame64_summary
Host->>Lib: value_count = XYParser_GetAlgorithmDataValueCount()
Lib-->>Host: value_count
Host->>Lib: ok = XYParser_ConvertSampleFramesToAlgorithmData(frame64_summary, algorithm_input_data)
Lib-->>Host: ok + algorithm_input_data
Host->>Algo: 输入算法数据 algorithm_input_data
Algo-->>Host: 算法输出数据 algorithm_output_bytes
Host->>Lib: alg_frame_count = XYParser_FeedAlgorithmData(parser8, algorithm_output_bytes, algorithm_output_size, algorithm_frames, max_algorithm_frames)
Lib-->>Host: alg_frame_count + algorithm_frames
Host->>Lib: welch_count = XYParser_ReadWelch(parser8, welch_summaries, max_welch)
Lib-->>Host: welch_count + welch_summaries
end
opt 结束时处理尾数据
Host->>Lib: flushed = XYParser_FlushAlgorithmData(parser8, tail_frame_summary)
Lib-->>Host: flushed + tail_frame_summary
Host->>Lib: welch_count = XYParser_ReadWelch(parser8, welch_summaries, max_welch)
Lib-->>Host: welch_count + welch_summaries
end
Host->>Lib: XYParser_DestroyParser(parser8)
```
## 4. 关键接口职责
### 4.1 设备参数配置
- `XYParser_SetAdcParams`
- 设置库内使用的 ADC 参考电压和增益参数。
- 该参数影响原始采样值到微伏值的换算。
- `XYParser_SetSampleRate`
- 设置库内处理逻辑使用的采样率。
- 该参数影响阻抗、Welch/PSD 等后续处理。
- `XYParser_Get64GainSampleRateCommandSize`
- 获取 64 导设备增益和采样率配置命令所需的缓冲区大小。
- `XYParser_Serialize64GainSampleRateCommand`
- 根据目标增益和采样率生成下发给 64 导设备的命令字节流。
- 上位机拿到该命令后发送给 EEG 设备,使设备端采样参数与库内配置保持一致。
- 当前推荐流程中:
- `vref` 固定为 `4.5`
- 设备连接成功后,先下发 `250Hz + 增益6`
- 开启阻抗前,下发 `250Hz + 增益24`,同时调用 `XYParser_SetImpedanceDetection(handle, 1)`,使库内 gain 自动切到 `24`
- 关闭阻抗后,再下发 `250Hz + 增益6`,同时调用 `XYParser_SetImpedanceDetection(handle, 0)`,使库内 gain 自动恢复到 `6`
- `XYParser_Get64ImpedanceCommandSize`
- 获取 64 导阻抗开关命令所需的缓冲区大小。
- `XYParser_Serialize64ImpedanceCommand`
- 生成下发给 64 导设备的阻抗开关命令字节流。
- `open = 1` 表示开启阻抗检测,`open = 0` 表示关闭阻抗检测。
- `XYParser_Get8ChImpedanceCommandSize`
- 获取 8 导阻抗开关命令所需的缓冲区大小。
- `XYParser_Serialize8ChImpedanceCommand`
- 生成下发给 8 导设备的阻抗开关命令字节流。
- `open = 1` 表示开启阻抗检测,`open = 0` 表示关闭阻抗检测。
- 8 导流程中,设备连接后**不需要**额外下发增益和采样率命令。
### 4.2 原始数据解析
- `XYParser_Feed`
- 输入设备原始字节流。
- 输出解析后的 `XYParserFrameSummary` 数组。
- 该接口当前仍负责驱动阻抗相关计算。
- 该接口当前**不再驱动 Welch/PSD 计算**。
### 4.3 阻抗读取
- `XYParser_SetImpedanceDetection`
- 控制是否启用阻抗检测。
- 启用时,库内 ADC 增益自动切换到 `24`
- 关闭时,库内 ADC 增益自动恢复到 `6`
- 该接口只修改库内解析参数,不会自动给设备发送控制命令。
- `XYParser_ReadImpedance`
- 读取当前已经累计完成的阻抗结果。
- 阻抗结果来源于阻抗检测阶段的帧解析链路。
### 4.4 帧转算法数据
- `XYParser_ConvertSampleFramesToAlgorithmData`
- 将单帧 `XYParserFrameSummary` 转为算法需要的连续数组。
- 上位机通常在拿到帧数据后调用此接口,再把结果送入算法模块。
- `XYParser_Convert8ChFramesTo64Ch`
- 将 8 导帧转换为 64 导帧,未映射导联补 0。
- 8 导流程中,在送算法数据前,需要先把 8 导帧转换为 64 导帧,再调用 `XYParser_ConvertSampleFramesToAlgorithmData`
### 4.5 算法数据回灌
- `XYParser_FeedAlgorithmData`
- 输入算法数据字节流。
- 内部先按采样缓存,再按每 5 个采样组装为一帧。
- 同时驱动 Welch/PSD 计算。
- 可选输出重新组装后的 `XYParserFrameSummary`
- `XYParser_ResetAlgorithmDataCache`
- 清空算法数据缓存。
- 适合在切换任务、重置状态时调用。
- `XYParser_FlushAlgorithmData`
- 将缓存中不足 5 个采样的尾数据补齐为 1 帧输出。
- 用于结束阶段处理残留数据。
### 4.6 Welch/PSD 读取
- `XYParser_SetWelchDetection`
- 控制是否启用基于算法数据的 Welch 检测。
- `XYParser_ReadWelch`
- 读取当前已累计完成的 Welch/PSD 结果。
- Welch 结果当前仅来源于 `XYParser_FeedAlgorithmData`
## 5. 当前设计结论
### 5.1 阻抗数据来源
- 阻抗在独立的阻抗检测阶段获取。
- 即:
- 设备连接成功
- 下发采样率250和增益6命令
- `XYParser_SetImpedanceDetection(handle, 1)`
- 下发采样率250和增益24命令
- 下发阻抗开启命令
- 设备原始字节流
- `XYParser_Feed`
- `XYParser_ReadImpedance`
- `XYParser_SetImpedanceDetection(handle, 0)`
- 下发阻抗关闭命令
- 下发采样率250和增益6命令
### 5.2 PSD 数据来源
- PSD/Welch 不再直接使用 `XYParser_Feed` 解析出来的帧数据。
- 当前流程为:
- 设备原始字节流
- `XYParser_Feed`
- `XYParser_ConvertSampleFramesToAlgorithmData`
- 算法处理
- `XYParser_FeedAlgorithmData`
- `XYParser_ReadWelch`
### 5.3 8导算法数据来源
- 8 导流程中,算法输入和 Welch/PSD 仍然按 64 导数据格式处理。
- 当前流程为:
- 8 导设备原始字节流
- `XYParser_Feed`
- `XYParser_Convert8ChFramesTo64Ch`
- `XYParser_ConvertSampleFramesToAlgorithmData`
- 算法处理
- `XYParser_FeedAlgorithmData`
- `XYParser_ReadWelch`
## 6. 推荐调用顺序
### 6.1 64导推荐调用顺序
```text
1. EEG 设备连接成功
2. CreateParser
3. SetAdcParams(4.5, 6) / SetSampleRate(250) / SetBypassChecksum
4. Get64GainSampleRateCommandSize / Serialize64GainSampleRateCommand(6, 250)
5. 上位机向设备下发采样率250、增益6命令
6. SetImpedanceDetection(1)
7. Get64GainSampleRateCommandSize / Serialize64GainSampleRateCommand(24, 250)
8. 上位机向设备下发采样率250、增益24命令
9. Get64ImpedanceCommandSize / Serialize64ImpedanceCommand(1)
10. 上位机向设备下发阻抗开启命令
11. 阻抗检测阶段循环:
11.1 Feed 原始字节流,拿到帧
11.2 ReadImpedance 读取阻抗
12. Serialize64ImpedanceCommand(0)
13. 上位机向设备下发阻抗关闭命令
14. SetImpedanceDetection(0)
15. Get64GainSampleRateCommandSize / Serialize64GainSampleRateCommand(6, 250)
16. 上位机向设备下发采样率250、增益6命令
17. SetWelchDetection
18. 常规采集阶段循环:
18.1 Feed 原始字节流,拿到帧
18.2 将帧转换为算法数据
18.3 将算法数据送入算法模块
18.4 将算法输出数据通过 FeedAlgorithmData 回灌
18.5 ReadWelch 读取 PSD/Welch 结果
19. 必要时 FlushAlgorithmData
20. DestroyParser
```
### 6.2 8导推荐调用顺序
```text
1. EEG 设备连接成功
2. CreateParser
3. SetAdcParams(vref, gain) / SetSampleRate(sample_rate) / SetBypassChecksum
4. SetImpedanceDetection(1)
5. Get8ChImpedanceCommandSize / Serialize8ChImpedanceCommand(1)
6. 上位机向设备下发阻抗开启命令
7. 阻抗检测阶段循环:
7.1 Feed 原始字节流拿到8导帧
7.2 ReadImpedance 读取阻抗
8. Serialize8ChImpedanceCommand(0)
9. 上位机向设备下发阻抗关闭命令
10. SetImpedanceDetection(0)
11. SetWelchDetection
12. 常规采集阶段循环:
12.1 Feed 原始字节流拿到8导帧
12.2 将8导帧转换为64导帧
12.3 将64导帧转换为算法数据
12.4 将算法数据送入算法模块
12.5 将算法输出数据通过 FeedAlgorithmData 回灌
12.6 ReadWelch 读取 PSD/Welch 结果
13. 必要时 FlushAlgorithmData
14. DestroyParser
```
## 7. 一句话总结
- **阻抗是独立阶段,先开阻抗、持续读取、再关阻抗。**
- **Welch/PSD 走算法数据链路。**
- **8导送算法前先转成64导数据。**