【STM32系列】利用MATLAB配合ARM-DSP库设计IIR数字滤波器(保姆级教程)
ps.源码放在最后面
设计FIR数字滤波器可以看这里:利用MATLAB配合ARM-DSP库设计FIR数字滤波器(保姆级教程)
设计IIR滤波器
MATLAB配置
设计步骤
首先在命令行窗口输入"filterDesigner",接着就会跳出以下界面,并跟着以下步骤设置:

滤波器幅频响应图像
按下设计滤波器后,接着就可得到以下FIR滤波器及其幅频响应图像:

导出滤波器系数
根据以下步骤,导出MATLAB滤波器的系数(千万不要用"目标"->"生成C头文件"来导出,主要是为了后面操作方便):

最后得到的浮窗是这样的,选择一个合适的位置导出即可。

导出后的系数转换
导出后大概率会出现这样一个MATLAB窗口(可知导出后的文件也可在MATLAB中打开,在打开这类文件的时候,记得选择文件类别为“全部文件”),IIR没FIR那么简单,多了一些步骤:

系数转换
也是像FIR滤波器一样,把这些数据复制给AI,让AI给你整合好就行,这里图片就不放出来了。
STM32部分
DSP库添加
详细请看硬汉哥的这篇文章,讲的十分清晰:ARM DSP源码和库移植方法(MDK5的AC5和AC6)
IIR代码部分
变量参数定义
以下就是需要的变量参数定义,值得注意的是,图中圈起来的两个部分,在IIR滤波器发生变化的时候,即参数改变的时候需要修改的参数(修改部分一看注释中的公式修改;修改部分二看数组中有多少行,根据行数修改;修改部分三根据数组参数变化修改):

主要代码

(打印处i初始等于9是为了显示较好的波形,滤波后的波形在前一段还未完全稳定)
也是千篇一律,主要是对导出的IIR滤波器的系数进行处理,还有修改在定义部分的一些变量值,代码在这里就不多说了。
程序现象
使用串口打印到VOFA+这个软件上
信号频率:4500Hz
采样频率:48000Hz
通带频率:4000Hz
阻带频率:5000Hz
红色:原始信号波形
绿色:滤波后信号波形

源码
变量定义部分
/*********************** IIR ***********************/
/** 采样频率:48kHz 通带频率:4kHz 阻带频率:5kHz **/
#define IIR_LENGTH 256 /* 采样点数,即要处理的采样数据的总数 */
#define IIR_BLOCK_SIZE 1 /* 调用一次 arm_biquad_cascade_df1_f32 函数处理的采样点个数 */
#define IIR_NUMTAPS_LENGTH 7 /* 2 阶 IIR 滤波的个数【滤波器阶数 = IIR_NUMTAPS_LENGTH * 2,每个 2 阶滤波器有 5 个系数】 */
static uint32_t iir_blockSize = IIR_BLOCK_SIZE; /* 每次处理的数据个数,与 IIR_BLOCK_SIZE 相同 */
static uint32_t iir_numBlocks = IIR_LENGTH / IIR_BLOCK_SIZE; /* 需要调用 arm_biquad_cascade_df1_f32 函数的次数,通过总采样点数除以每次处理的数据个数得到 */
static float32_t IIR_InputBufer[IIR_LENGTH]; /* 采样点缓存区,用于存储原始的采样数据 */
static float32_t IIR_OutputBufer[IIR_LENGTH]; /* 滤波后的输出缓存区,滤波后输出的数据个数与采样点个数相同 */
static float32_t iir_pState[13 * IIR_NUMTAPS_LENGTH]; /* 状态缓存,大小为 35 * IIR_NUMTAPS_LENGTH,直接 I 型滤波器需要 2N 个延迟器和 2N 个乘法器 */
const float32_t iir_Coeffs32LP[5 * IIR_NUMTAPS_LENGTH] = { /* IIR_NUMTAPS_LENGTH组二阶滤波系数,每组代表一个 Section二阶滤波器,有5个系数 */
1.0f, -1.581251265113648107885069293843116611242f, 1.0f, 1.64464506366406792992052032786887139082f, -0.931601507332356026935826776025351136923f,
1.0f, -1.534184978348168693074171642365399748087f, 1.0f, 1.510438012818041242368849452759604901075f, -0.798208657466401461100247161084553226829f,
1.0f, -1.418424762240857006645455840043723583221f, 1.0f, 1.348418230754467206367053222493268549442f, -0.655285433213672163788032776210457086563f,
1.0f, -1.169460742425922239462465768156107515097f, 1.0f, 1.151129772069469092699023349268827587366f, -0.493393743131744000329774735291721299291f,
1.0f, -0.608329709345672098308455133519601076841f, 1.0f, 0.930270435976758625074012343247886747122f, -0.319126063671286819278805069188820198178f,
1.0f, 0.671963013119381002979935146868228912354f, 1.0f, 0.736945396854642664763446191500406712294f, -0.169496181427103626004893044409982394427f,
1.0f, 1.0f, 0.0f, 0.328290240600095484246878640988143160939f, -0.0f
};/*【滤波器的核心选择都在这些系数里面,这些系数的生成使用MATLB进行配置】*/
arm_biquad_casd_df1_inst_f32 iir_S; /* 定义一个结构体变量,用于 IIR 滤波器的初始化 */
float32_t iir_ScaleValue; /* 定义一个变量,用于存放放缩系数 */
float32_t *iir_inputF32, *iir_outputF32; /* 定义两个指针变量,分别用于存放滤波器输入和输出缓存的地址 */
主要程序部分
iir_inputF32 = &IIR_InputBufer[0]; /* 初始化输入缓存指针 */
iir_outputF32 = &IIR_OutputBufer[0]; /* 初始化输出缓存指针 */
for (uint16_t i = 0; i < IIR_LENGTH; i++) {
IIR_InputBufer[i] = (float)ADC_DMA_ConvertedValue[i] * 3.3 / 65536.0;
}
memset(iir_pState, 0, sizeof(iir_pState)); /* 初始化前清零状态 */
//滤波器结构体初始化
arm_biquad_cascade_df1_init_f32(&iir_S, /* 初始化结构体S【S就相当于滤波器配置参数,对S结构体的各个成员变量完成初始化】*/
IIR_NUMTAPS_LENGTH, /* 初始化2阶IIR滤波的个数【滤波器阶数=IIR_NUMTAPS_LENGTH*2,每个IIR_NUMTAPS_LENGTH有5个系数】*/
(float32_t *)&iir_Coeffs32LP[0], /* 初始化S的滤波器系数地址【滤波器的核心选择都在这些系数里面】*/
(float32_t *)&iir_pState[0]); /* 初始化S的计算缓存空间 */
for(uint16_t i = 0; i < iir_numBlocks; i++){
arm_biquad_cascade_df1_f32(&iir_S, /* 使用滤波器iir_S */
iir_inputF32 + (i * iir_blockSize), /* 滤波器原始输入数据地址 */
iir_outputF32 + (i * iir_blockSize), /* 滤波器滤波后输出数据地址 */
iir_blockSize); /* 每次处理数据点的个数 */
}
//计算放缩系数
iir_ScaleValue = 0.685271189526501567357286148762796074152 *
0.617778799034633618880718586297007277608 *
0.527648329116606640276643247489118948579 *
0.412098486544746456239352028205757960677 *
0.279416489886909980011608922723098658025 *
0.161885019533814594749898674308496993035 *
0.33585487969995225787656067950592841953;
Set_Current_USART(USART1_IDX);/* 使用串口1 */
for(uint16_t i = 9; i<IIR_LENGTH; i++){//输出原始数据和滤波之后的数据【注意这里需要乘上放缩系数】
printf("%d: %f,%f\r\n",i,IIR_InputBufer[i],IIR_OutputBufer[i]*iir_ScaleValue);
}
【STM32系列】利用MATLAB配合ARM-DSP库设计IIR数字滤波器(保姆级教程)的更多相关文章
- 【保姆级】利用Github搭建自己的个人博客,看完就会
大家好,我是辰哥~ 作为一名喜欢技术的爱好者,平时喜欢把自己学习技术的心得或者一些踩坑.易错的过程记录下来,首选的是技术平台(博客),今天辰哥来教大家如何利用Github来搭建一个自己的个人博客平台. ...
- 【玩转单片机系列002】 如何使用STM32提供的DSP库进行FFT
前些日子,因为需要在STM32F103系列处理器上,对采集的音频信号进行FFT,所以花了一些时间来研究如何高效并精确的在STM32F103系列处理器上实现FFT.在网上找了很多这方面的资料做实验并进行 ...
- STM32系列ARM单片机介绍
STM32系列基于专为要求高性能.低成本.低功耗的嵌入式应用专门设计的ARM Cortex-M3内核.按性能分成两个不同的系列:STM32F103"增强型"系列和STM32F101 ...
- 基于HAL库的STM32的DSP库详解(附FFT应用)
1 . 建立工程,生成代码时选择包含所有库. 2. 打开 option for target 选择 Target 标签,在code generatio中,将floating point hardw ...
- stm32开发笔记(二):stm32系列使用V3.5固件库的帮助文件以及GPIO基本功能(一)
前言 stm32系列是最常用的单片机之一,不同的版本对应除了引脚.外设.频率.容量等'不同之外,其开发的方法是一样的. 本章讲解使用库函数使用GPIO引脚功能. 补充 本文章为多年前学习 ...
- 【DSP开发】【Linux开发】基于ARM+DSP进行应用开发
针对当前应用的复杂性,SOC芯片更好能能满足应用和媒体的需求,集成众多接口,用ARM做为应用处理器进行多样化的应用开发和用户界面和接口,利用DSP进行算法加速,特别是媒体的编解码算法加速,既能够保持算 ...
- Keil MDK STM32系列(一) 基于标准外设库SPL的STM32F103开发
Keil MDK STM32系列 Keil MDK STM32系列(一) 基于标准外设库SPL的STM32F103开发 Keil MDK STM32系列(二) 基于标准外设库SPL的STM32F401 ...
- Keil MDK STM32系列(二) 基于标准外设库SPL的STM32F401开发
Keil MDK STM32系列 Keil MDK STM32系列(一) 基于标准外设库SPL的STM32F103开发 Keil MDK STM32系列(二) 基于标准外设库SPL的STM32F401 ...
- Keil MDK STM32系列(四) 基于抽象外设库HAL的STM32F401开发
Keil MDK STM32系列 Keil MDK STM32系列(一) 基于标准外设库SPL的STM32F103开发 Keil MDK STM32系列(二) 基于标准外设库SPL的STM32F401 ...
- Keil MDK STM32系列(三) 基于标准外设库SPL的STM32F407开发
Keil MDK STM32系列 Keil MDK STM32系列(一) 基于标准外设库SPL的STM32F103开发 Keil MDK STM32系列(二) 基于标准外设库SPL的STM32F401 ...
随机推荐
- vite vue3 全局批量注册组件
方式1-使用import.meta.glob 同webpack的 require.context一样,这个是vite提供的一个方法 import { createApp, defineAsyncCom ...
- AtCoder Beginner Contest 184 ABCDE 题解
A - Determinant 签到. B - Quizzes 签到. C - Super Ryuma 贪心,同时分情况讨论: 1.本身就在范围里面,就1次(特判起始点和终点重合). 2.在两步范围内 ...
- 迁移学习&在线学习
简介 英文: transfer learning 以已训练好的模型A为起点,在新场景中,根据新数据建立模型B 目的:将某个领域或任务上学习到的知识或模式,应用到不同但相关的领域或问题中. 特征提取 使 ...
- FT 面试 记录
冬天的时候呼气呼到玻璃上,出现水雾的质量?? 我们简单的算了一下 是 40mg
- ubuntu 安装flash
安装一直失败 转载 ubuntu 14.04安装flash无效的解决方法 144 作者 Devid 关注 2015.11.20 20:44* 字数 350 阅读 1701评论 1喜欢 0 原文出处:h ...
- P9713 「QFOI R1」抱抱 题解
P9713 「QFOI R1」抱抱 题解 Sol 前置知识:长方体体积公式:\(V = abh\). 我们知道,切割掉 \(x \le k\) 的部分就是把 \(a\) 减去 \(k\),切割掉 \( ...
- English-英语发音舌位唇形图
英语发音舌位唇形图 图0 梯形图 图1 图2 图3
- IP: dns-lookup : 查询域名的公网IP地址 解决 DNS域名解析绑架的问题例如访问 raw.githubusercontent.com 的文件
示例:https://github.com/orgs/community/discussions/42655 https://github.com/mwaskom/seaborn-data/blob/ ...
- OS-MacOS-MacBook Pro 的电源管理 + 主动切换独立 或 集成显卡的 gpuswitch 选项;
通过 MacOS 的: System Information可以查看显卡以及所有的硬件和软件的情况: Activity Monitor 可以监控系统的Energy / CPU / Memory / N ...
- 从硬盘爆满到 GitHub 封号,一位前端开发者的开源历险记
前段时间,我结识了一位前端工程师「1024小神」.他的"战友"是一台 MacBook Air M3(8G+256GB),原本用来开发网页.小程序,绰绰有余. 然而,他的噩梦始于老板 ...