【瑞萨AI挑战赛】(RT-Thread + 瑞萨 FFT)板卡多种频率算法比较
## 一、工程整体思路在一个 `while(1)` 循环里,对**同一组模拟信号**依次执行:
1. **原始信号**(作为基准)
2. **滑动平均滤波**(简单时域平滑)
3. **FFT + 频域滤波**(频域处理,保留指定频率)
4. **阈值检测**(简单异常点剔除)
5. **峰值检测**(找信号波峰)
并在每次处理后打印:
* 算法名称
* 耗时(us)
* 部分结果
## 二、完整代码示例
```
#include "rtthread.h"
#include "r_fft.h" // 瑞萨 FFT 库,若用 CMSIS-DSP 可替换为 arm_math.h
#include "math.h"
/* ================= 通用配置 ================= */
#define FFT_POINTS 256 // FFT点数,2的幂
#define SAMPLE_FREQ 1000 // 1kHz采样
#define DATA_LEN FFT_POINTS// 算法统一输入长度
/* 输入信号:混合正弦波 + 噪声(模拟传感器信号) */
static void generate_test_signal(rt_int16_t *buf, rt_uint32_t len)
{
rt_uint32_t i;
for (i = 0; i < len; i++)
{
// 50Hz + 150Hz 正弦波 + 少量随机噪声
float t = (float)i / SAMPLE_FREQ;
float s = 3000.0f * sinf(2 * RT_PI *50 * t)
+ 2000.0f * sinf(2 * RT_PI * 150 * t)
+ (float)rand() / RAND_MAX * 200.0f - 100.0f;
// 限幅到 16 位范围
if (s > 32767.0f) s = 32767.0f;
if (s < -32768.0f) s = -32768.0f;
buf = (rt_int16_t)s;
}
}
/* ================= 1. 滑动平均滤波(时域平滑) ================= */
static void moving_average_filter(rt_int16_t *in, rt_int16_t *out, rt_uint32_t len, rt_uint8_t window)
{
rt_uint32_t i, j;
rt_int32_t sum;
for (i = 0; i < len; i++)
{
sum = 0;
rt_uint32_t start = (i < window / 2) ? 0 : (i - window / 2);
rt_uint32_t end = (i + window / 2 < len - 1) ? (i + window / 2) : (len - 1);
for (j = start; j <= end; j++)
{
sum += in;
}
out = (rt_int16_t)(sum / (end - start + 1));
}
}
/* ================= 2. FFT 频域滤波(保留 0~100Hz) ================= */
static void fft_bandpass_filter(rt_int16_t *in, rt_int16_t *out, rt_uint32_t len)
{
rt_uint16_t i;
rt_int16_t fft_in, fft_out; // 实部+虚部
// 1. 实部赋值,虚部补0
for (i = 0; i < len; i++)
{
fft_in = in;
fft_in = 0;
}
// 2. 执行 FFT
r_fft_execute(fft_in, fft_out, len);
// 3. 置零 100Hz 以上的频点(简单低通)
rt_uint32_t cutoff_bin = (rt_uint32_t)(100.0f * len / SAMPLE_FREQ);
for (i = cutoff_bin; i < len / 2; i++)
{
fft_out = 0;
fft_out = 0;
}
// 4. 逆 FFT 转回时域
r_fft_execute(fft_out, fft_in, len); // 这里可换为 r_ifft_execute,视库而定
// 5. 取实部作为输出(虚部理论接近0)
for (i = 0; i < len; i++)
{
out = fft_in;
}
}
/* ================= 3. 阈值滤波(简单剔除异常点) ================= */
static void threshold_filter(rt_int16_t *in, rt_int16_t *out, rt_uint32_t len, rt_int16_t threshold)
{
rt_uint32_t i;
for (i = 0; i < len; i++)
{
if (in > threshold || in < -threshold)
{
// 异常点用前一个值替代(第一个点保留原值)
out = (i > 0) ? out : in;
}
else
{
out = in;
}
}
}
/* ================= 4. 峰值检测(找波峰位置与幅值) ================= */
static void peak_detection(rt_int16_t *in, rt_uint32_t len, rt_uint8_t min_height, rt_uint32_t *peak_num, rt_uint32_t *peak_pos, rt_int16_t *peak_val)
{
rt_uint32_t i;
*peak_num = 0;
for (i = 1; i < len - 1; i++)
{
if (in > in && in > in && in > min_height)
{
peak_pos[*peak_num] = i;
peak_val[*peak_num] = in;
(*peak_num)++;
if (*peak_num >= 10) break; // 最多记录10个峰
}
}
}
/* ================= 统一入口:hal_entry ================= */
void hal_entry(void)
{
rt_kprintf("\nHello RT-Thread!\n");
rt_kprintf("==================================================\n");
rt_kprintf("Algorithm Comparison Demo on FPB-RA6E2\n");
rt_kprintf("Sample Freq: %dHz, FFT Points: %d\n", SAMPLE_FREQ, FFT_POINTS);
rt_kprintf("==================================================\n");
// 缓冲区
rt_int16_t sig_in;
rt_int16_t sig_avg;
rt_int16_t sig_fft;
rt_int16_t sig_th;
rt_uint32_t t1, t2; // 用于计时
do
{
// 1. 生成统一测试信号
generate_test_signal(sig_in, DATA_LEN);
// ================ 算法 A:原始信号(基准) ================
t1 = rt_hw_us_tick_get();
// 无处理,直接使用 sig_in
t2 = rt_hw_us_tick_get();
rt_kprintf("\n Cost: %d us", t2 - t1);
rt_kprintf(" | Sample: %d, %d, %d, %d\n",
sig_in, sig_in, sig_in, sig_in);
// ================ 算法 B:滑动平均滤波 ================
t1 = rt_hw_us_tick_get();
moving_average_filter(sig_in, sig_avg, DATA_LEN, 5); // 窗口5
t2 = rt_hw_us_tick_get();
rt_kprintf(" Cost: %d us", t2 - t1);
rt_kprintf(" | Sample: %d, %d, %d, %d\n",
sig_avg, sig_avg, sig_avg, sig_avg);
// ================ 算法 C:FFT 频域滤波 ================
t1 = rt_hw_us_tick_get();
fft_bandpass_filter(sig_in, sig_fft, DATA_LEN);
t2 = rt_hw_us_tick_get();
rt_kprintf(" Cost: %d us", t2 - t1);
rt_kprintf(" | Sample: %d, %d, %d, %d\n",
sig_fft, sig_fft, sig_fft, sig_fft);
// ================ 算法 D:阈值滤波 ================
t1 = rt_hw_us_tick_get();
threshold_filter(sig_in, sig_th, DATA_LEN, 4000); // 阈值4000
t2 = rt_hw_us_tick_get();
rt_kprintf(" Cost: %d us", t2 - t1);
rt_kprintf(" | Sample: %d, %d, %d, %d\n",
sig_th, sig_th, sig_th, sig_th);
// ================ 算法 E:峰值检测(以FFT滤波结果为例) ================
rt_uint32_t peak_num;
rt_uint32_t peak_pos;
rt_int16_tpeak_val;
t1 = rt_hw_us_tick_get();
peak_detection(sig_fft, DATA_LEN, 2000, &peak_num, peak_pos, peak_val);
t2 = rt_hw_us_tick_get();
rt_kprintf(" Cost: %d us", t2 - t1);
rt_kprintf(" | Peak Num: %d\n", peak_num);
for (rt_uint8_t k = 0; k < peak_num; k++)
{
rt_kprintf("Peak %d: pos=%d, val=%d\n", k + 1, peak_pos, peak_val);
}
rt_thread_mdelay(1000); // 1秒循环一次
} while (1);
}
```
## 三、算法横向对比分析
| 算法 | 处理域 | 主要用途 | 资源占用(RAM/ROM) | 耗时(256 点) | 优点 | 缺点 |
| -------------- | -------- | ---------------------------- | --------------------- | ---------------- | ------------------------------------ | ----------------------------------------- |
| 原始信号 | 时域 | 基准对比 | 极低 | ≈0 us | 无处理,完全保留原始信息 | 噪声、异常点全部保留,不实用 |
| 滑动平均滤波 | 时域 | 平滑随机噪声、低频信号 | 低 | \~ 几十 us | 简单、快、抗随机噪声 | 对突变信号有延迟,窗口过大滞后明显 |
| FFT 频域滤波 | 频域 | 滤除指定频带、抑制谐波干扰 | 中 | \~ 几百 us | 频带控制精确,适合特定频带噪声抑制 | 需整段缓存、RAM/ROM 大,实时性略差 |
| 阈值滤波 | 时域 | 剔除异常点 / 毛刺 | 极低 | \~ 几十 us | 极快,专门对付单点异常 | 阈值难定,对连续异常 / 密集噪声效果有限 |
| 峰值检测 | 时域 | 提取特征峰、变化点 | 低 | \~ 几十 us | 可给出特征点信息,便于特征分析 | 对噪声敏感,必须配合滤波 |
## 四、各种算法分析
### 1. 原始信号(基准)
* **功能**:不做任何处理,仅打印前几个采样点。
* **用途**:作为所有算法的 “原始输入” 参考,便于对比其他算法对信号的改变程度。
* **耗时**:几乎为 0 us(仅拷贝 / 打印)。
* **特点**:无处理,噪声和异常点全部保留。
### 2. 滑动平均滤波(时域平滑)
* **功能**:用局部邻域平均值替代当前值,平滑高频噪声。
* **适用场景**:缓慢变化的传感器信号(温度、压力、缓慢振动)。
* **耗时(RA6E2 @ 100MHz)**:
* 窗口 5,256 点:约 **几十 us** 级。
* **优点**:
* 实现简单,资源占用低;
* 对**随机噪声**有明显平滑效果。
* **缺点**:
* 对**突变信号**会产生延迟与 “抹平”;
* 窗口越大,延迟越大。
### 3. FFT频域滤波(时域平滑)
* **功能**:把信号转到频域,把**高于某频率**的成分置零,再逆变换回时域。
* **适用场景**:需要**精确滤除特定频带**噪声(如工频干扰、高频振动噪声)。
* **耗时**:
* 256 点 FFT + IFFT:约 **几百 us** 级(视库优化程度)。
* **优点**:
* 可以**精确控制保留 / 滤除哪些频率**;
* 对周期性噪声、特定频带干扰效果好。
* **缺点**:
* 嵌入式 RAM/ROM 开销较大(需要复数缓冲区、FFT 工作区);
* 非实时性稍差(需要整段数据缓存)。
### 4.阈值滤波
* **功能**:把明显超出正常范围的 “尖峰 / 毛刺” 替换为邻近值。
* **适用场景**:传感器偶尔跳变、强干扰造成的单帧异常。
* **耗时**:
* 256 点:约 **几十 us** 级。
* **优点**:
* 对**单点异常**剔除非常快;
* 实现简单,几乎不占资源。
* **缺点**:
* 对**连续异常**或噪声分布不均匀的情况效果有限;
* 阈值选得不好会误删正常信号。
### 5.峰值检测
* **功能**:从信号中识别 “波峰”,记录位置和幅值。
* **适用场景**:
* 脉搏波、心率检测;
* 振动信号特征提取;
* 寻找信号中的显著变化点。
* **耗时**:
* 256 点扫描:约 **几十 us** 级。
* **优点**:
* 可以给出**特征点信息**(频率、幅值),便于**判断;
* 结合 FFT 结果,可做**频域 + 时域联合分析**。
* **缺点**:
* 对噪声敏感,必须配合滤波使用;
* 简单算法容易 “漏检 / 误检” 峰。
## 五、结论
本次多种算法并行可以观察出来,板卡的计算处理功能还是很强大的。
页:
[1]