4. 流式数据采集与处理

任务说明

本案例实现一个两核流水线:核0通过ADC连续采集数据,将原始采样值通过流接口发送至核1;核1执行滑动平均滤波后,将结果通过另一个流接口输出。最终在仿真环境中验证滤波后的数据波形符合预期。

硬件连接与数据流

拓扑: ADC(12位,单通道)→ 核0(采集)→ 流接口c_adc → 核1(滤波)→ 流接口c_out → 输出观测点
ADC 12-bit 1kHz采样 核0 采集任务 adc_sample() 发送至流接口 核1 滤波任务 filter_task() 滑动平均(4点) 输出 滤波后数据 模拟输入 c_adc c_out 流式数据: 每周期1个采样值 滤波窗口: [n-3, n]

代码实现

// main.xc - 双核ADC采集与滑动平均滤波流水线
#include <xs1.h>
#include <platform.h>
#include <stdio.h>

// 流接口定义
// c_adc: 核0 → 核1,传输原始ADC采样值
// c_out: 核1 → 外部,传输滤波结果
interface adc_filter_if {
    void send_sample(unsigned sample);
    unsigned receive_filtered();
};

// 模拟ADC采样函数(12位精度,范围0-4095)
// 实际项目中替换为硬件ADC驱动
unsigned adc_read(void) {
    // 模拟正弦波采样:100Hz信号,1kHz采样率
    static unsigned phase = 0;
    phase = (phase + 1) % 10;  // 每周期10个采样点
    // 生成正弦波:2048 + 1500*sin(2π*phase/10)
    // 使用查找表简化计算
    static const int sin_table[10] = {0, 951, 1819, 2378, 2499, 2378, 1819, 951, 0, -951};
    int val = 2048 + (1500 * sin_table[phase]) / 2500;
    if (val < 0) val = 0;
    if (val > 4095) val = 4095;
    return (unsigned)val;
}

// 核0任务:ADC采集并发送
void adc_task(server interface adc_filter_if c_adc) {
    unsigned sample;
    while (1) {
        sample = adc_read();          // 读取ADC
        c_adc.send_sample(sample);    // 发送到核1
        delay_ticks(1000);            // 模拟1kHz采样率(100MHz时钟下1000 ticks)
    }
}

// 核1任务:滑动平均滤波(窗口大小4)
void filter_task(client interface adc_filter_if c_adc,
                 client interface adc_filter_if c_out) {
    unsigned buffer[4] = {0, 0, 0, 0};
    int idx = 0;
    unsigned sum = 0;
    unsigned filtered;
    
    while (1) {
        // 从核0接收原始采样值
        unsigned raw;
        c_adc.send_sample(raw);  // 实际为接收,见下方select逻辑
        
        // 更新滑动窗口
        sum -= buffer[idx];
        buffer[idx] = raw;
        sum += buffer[idx];
        idx = (idx + 1) % 4;
        
        // 计算平均值(右移2位等价于除以4)
        filtered = sum >> 2;
        
        // 输出滤波结果
        c_out.receive_filtered();  // 实际为发送,见下方select逻辑
    }
}

// 主函数:并行运行两个核
int main(void) {
    interface adc_filter_if c_adc;
    interface adc_filter_if c_out;
    
    par {
        // 核0:ADC采集
        on tile[0]: adc_task(c_adc);
        // 核1:滤波处理
        on tile[1]: filter_task(c_adc, c_out);
    }
    return 0;
}

接口方向修正说明

上述代码中filter_task的接口方向标注有误。流接口必须明确区分server(提供者)与client(调用者)。修正后的正确实现如下:

// 正确版本:接口方向明确
interface adc_filter_if {
    unsigned get_sample();      // 核1调用,从核0获取采样值
    void put_result(unsigned v); // 核1调用,向输出端发送滤波结果
};

// 核0:ADC采集(server端,提供get_sample)
void adc_task(server interface adc_filter_if c_adc) {
    unsigned sample;
    while (1) {
        sample = adc_read();
        select {
            case c_adc.get_sample() > int result:
                result = sample;
                break;
        }
        delay_ticks(1000);
    }
}

// 核1:滤波(client端,调用get_sample和put_result)
void filter_task(client interface adc_filter_if c_adc,
                 client interface adc_filter_if c_out) {
    unsigned buffer[4] = {0, 0, 0, 0};
    int idx = 0;
    unsigned sum = 0;
    
    while (1) {
        unsigned raw = c_adc.get_sample();  // 从核0获取
        sum -= buffer[idx];
        buffer[idx] = raw;
        sum += buffer[idx];
        idx = (idx + 1) % 4;
        unsigned filtered = sum >> 2;
        c_out.put_result(filtered);          // 发送结果
    }
}

// 输出端任务(核2或外部接口)
void output_task(server interface adc_filter_if c_out) {
    while (1) {
        select {
            case c_out.put_result(unsigned v):
                printf("滤波输出: %u\n", v);
                break;
        }
    }
}

int main(void) {
    interface adc_filter_if c_adc;
    interface adc_filter_if c_out;
    
    par {
        on tile[0]: adc_task(c_adc);
        on tile[1]: filter_task(c_adc, c_out);
        on tile[0]: output_task(c_out);
    }
    return 0;
}

编译与运行

# 编译(xTIMEcomposer工具链)
xcc -target=XCORE-200-EXPLORER main.xc -o pipeline.xe

# 运行(仿真模式)
xsim pipeline.xe --io

验证方法

在output_task中打印滤波结果。输入为模拟正弦波(幅度±1500,偏置2048),预期滤波输出满足:

  • 波形形状:仍为正弦波,幅值略减(4点滑动平均对10点/周期正弦的衰减约0.9倍);
  • 相位延迟:输出相对输入延迟约1.5个采样周期;
  • 数值范围:始终在0~4095之间。

判定标准:观察串行输出,滤波后相邻采样值变化率小于原始采样值变化率(即高频分量被抑制),且波形周期与输入一致(10个采样点完成一个完整正弦周期)。

关键点说明

  • 流接口方向:server端使用select等待client调用,client端直接调用接口函数;
  • 流水线时序:核0采集与核1滤波并行执行,通过流接口同步,核0的采样率由delay_ticks控制;
  • 滑动平均:窗口大小4,使用环形缓冲区避免数据搬移,右移2位实现除法。