# 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导数据。**