Files
XYParser/XYParserDataFlow.md
2026-06-08 22:58:58 +08:00

18 KiB
Raw Blame History

XYParser 数据流与接口时序说明

1. 参与角色

  • 64导EEG采集设备
    • 持续输出原始 EEG 字节流。
  • 上位机
    • 负责接收设备数据、调用 XYParser 库、对接算法模块。
  • XYParser 库
    • 负责帧解析、阻抗计算、算法数据回灌后的 Welch/PSD 计算。
  • 算法
    • 接收上位机送入的算法数据,并输出用于 PSD/Welch 计算的数据。

2. 总体链路

当前流程可以分为两个阶段:

  • 阶段一:阻抗检测阶段

    • 设备连接后,首先下发采样率和增益配置命令。
    • 然后下发阻抗开启命令。
    • 在该阶段持续接收设备数据,并通过 XYParser_ReadImpedance 读取阻抗结果。
    • 阻抗检测结束后,下发阻抗关闭命令。
  • 阶段二:常规采集与算法阶段

    • 基于 XYParser_Feed 解析得到的帧数据继续做常规采集。
    • 帧数据先转换为算法数据,再送入算法模块。
    • Welch/PSD 不再直接基于帧解析结果计算,而是基于算法数据,通过 XYParser_FeedAlgorithmData 输入后计算。

3. 接口时序图

3.1 64导初始化连接阶段

%%{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导阻抗阶段

%%{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导算法阶段

%%{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导训练打标阶段

%%{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导初始化连接阶段

%%{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导阻抗阶段

%%{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导算法阶段

%%{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导推荐调用顺序

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导推荐调用顺序

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