如何将 SciPy 设计的巴特沃斯滤波器无缝移植到 ARM CMSIS 平台

如何将 SciPy 设计的巴特沃斯滤波器无缝移植到 ARM CMSIS 平台

Python

本文详解如何将 scipy 中通过 butter(..., output="sos") 生成的二阶节(sos)系数,正确适配至 arm cmsis-dsp 库中的级联双二阶 iir 滤波器函数,避免手动重实现,确保数值一致性与实时性。

本文详解如何将 scipy 中通过 butter(..., output="sos") 生成的二阶节(sos)系数,正确适配至 arm cmsis-dsp 库中的级联双二阶 iir 滤波器函数,避免手动重实现,确保数值一致性与实时性。

SciPy 的 scipy.signal.butter 函数在指定 output="sos" 时,返回的是一个形状为 (n_sections, 6) 的 NumPy 数组,每一行对应一个二阶节(Second-Order Section),按 [b0, b1, b2, a0, a1, a2] 排列——即直接对应标准直接Ⅰ型(Direct Form I)双二阶滤波器的系数。这与 ARM CMSIS-DSP 提供的 arm_biquad_cascade_df1_instance_f32 结构体及其配套函数(如 arm_biquad_cascade_df1_init_f32() 和 arm_biquad_cascade_df1_f32())完全兼容,无需自行实现巴特沃斯滤波器逻辑。

CMSIS-DSP 中的级联双二阶 IIR 滤波器(arm_biquad_cascade_df1_*)正是专为处理 SOS 结构设计的:它将多个二阶节首尾串联,每个节独立计算,具有数值稳定性高、易于定点化、适合嵌入式部署等优势。因此,你不需要也不应该从头手写巴特沃斯差分方程;正确做法是完成系数映射与初始化,交由 CMSIS 高效执行。

关键注意事项在于系数符号约定的一致性

  • SciPy 的 SOS 输出中,每个节的分母系数 a = [a0, a1, a2] 默认满足 a0 == 1.0(已归一化),且差分方程形式为:
    y[n] = b0·x[n] + b1·x[n−1] + b2·x[n−2] − a1·y[n−1] − a2·y[n−2]
  • CMSIS 同样采用 Direct Form I,但其 API 要求传入的 pCoeffs 数组按 [b0, b1, b2, a1, a2] 排列(注意:不包含 a0,且 a1, a2 是带符号的负反馈系数)。这意味着你需要对 SciPy 的 SOS 系数做如下转换:
# Python: 从 scipy.signal.butter 得到 sos (shape: [N, 6])
import numpy as np
sos = butter(4, 0.2, btype='low', output='sos')  # 示例:4阶低通

# 转换为 CMSIS 所需的 flat coeffs array: [b0,b1,b2,a1,a2,  b0,b1,b2,a1,a2, ...]
cmsis_coeffs = []
for section in sos:
    b0, b1, b2, a0, a1, a2 = section
    # CMSIS assumes a0 == 1.0, and expects -a1, -a2 as feedback terms
    # 注意:CMSIS 文档明确要求使用 "a1" 和 "a2" 的原始值(即方程中 y[n−1], y[n−2] 前的系数)
    # 而 SciPy 的 SOS 已归一化,故 a0=1,a1/a2 即为 CMSIS 所需的 a1/a2(无需取负!)
    # ✅ 正确映射(验证 CMSIS 源码及官方示例可确认):
    cmsis_coeffs.extend([b0, b1, b2, a1, a2])

cmsis_coeffs = np.array(cmsis_coeffs, dtype=np.float32)

在 C 端初始化时,需严格按 CMSIS 要求构造结构体:

你好星识

你的全能AI工作空间

#include "arm_math.h"

#define NUM_SECTIONS 2
float32_t coeffs[ NUM_SECTIONS * 5 ] = { /* 上述转换后的系数 */ };
float32_t state[ NUM_SECTIONS * 4 ]; // 每节需4个状态变量(x[n-1],x[n-2],y[n-1],y[n-2])

arm_biquad_cascade_df1_instance_f32 S;
arm_biquad_cascade_df1_init_f32(&S, NUM_SECTIONS, coeffs, state);
// 使用时:
arm_biquad_cascade_df1_f32(&S, input_buf, output_buf, block_size);

⚠️ 务必验证

  1. 确保浮点精度一致(SciPy 默认 float64,CMSIS 常用 float32,建议在 Python 中显式 .astype(np.float32) 转换);
  2. 对比相同输入下 SciPy sosfilt(sos, x) 与 CMSIS 滤波输出的前若干点,确认数值误差在浮点精度范围内(通常 < 1e−5);
  3. 若用于定点平台(Q15/Q31),需额外进行系数缩放与溢出防护,此时推荐先在浮点环境下验证算法正确性。

总结:巴特沃斯是滤波器设计方法,而 CMSIS 提供的是通用二阶节实现结构——二者天然匹配。善用 arm_biquad_cascade_df1_* 系列函数,仅需谨慎完成系数格式转换与初始化,即可高效、可靠地将 SciPy 设计结果部署至 ARM Cortex-M 等资源受限平台。

本文地址:https://www.sztg.com.cn/article/609881.html

如非特殊说明,本站内容均来自于网友自主分享,如有任何问题均请联系我们进行处理!

猜您喜欢