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

439 lines
18 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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导数据。**