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数字滤波器(保姆级教程)的更多相关文章

  1. 【保姆级】利用Github搭建自己的个人博客,看完就会

    大家好,我是辰哥~ 作为一名喜欢技术的爱好者,平时喜欢把自己学习技术的心得或者一些踩坑.易错的过程记录下来,首选的是技术平台(博客),今天辰哥来教大家如何利用Github来搭建一个自己的个人博客平台. ...

  2. 【玩转单片机系列002】 如何使用STM32提供的DSP库进行FFT

    前些日子,因为需要在STM32F103系列处理器上,对采集的音频信号进行FFT,所以花了一些时间来研究如何高效并精确的在STM32F103系列处理器上实现FFT.在网上找了很多这方面的资料做实验并进行 ...

  3. STM32系列ARM单片机介绍

    STM32系列基于专为要求高性能.低成本.低功耗的嵌入式应用专门设计的ARM Cortex-M3内核.按性能分成两个不同的系列:STM32F103"增强型"系列和STM32F101 ...

  4. 基于HAL库的STM32的DSP库详解(附FFT应用)

    1 . 建立工程,生成代码时选择包含所有库.   2. 打开 option for target 选择 Target 标签,在code generatio中,将floating point hardw ...

  5. stm32开发笔记(二):stm32系列使用V3.5固件库的帮助文件以及GPIO基本功能(一)

    前言   stm32系列是最常用的单片机之一,不同的版本对应除了引脚.外设.频率.容量等'不同之外,其开发的方法是一样的.  本章讲解使用库函数使用GPIO引脚功能.   补充   本文章为多年前学习 ...

  6. 【DSP开发】【Linux开发】基于ARM+DSP进行应用开发

    针对当前应用的复杂性,SOC芯片更好能能满足应用和媒体的需求,集成众多接口,用ARM做为应用处理器进行多样化的应用开发和用户界面和接口,利用DSP进行算法加速,特别是媒体的编解码算法加速,既能够保持算 ...

  7. Keil MDK STM32系列(一) 基于标准外设库SPL的STM32F103开发

    Keil MDK STM32系列 Keil MDK STM32系列(一) 基于标准外设库SPL的STM32F103开发 Keil MDK STM32系列(二) 基于标准外设库SPL的STM32F401 ...

  8. Keil MDK STM32系列(二) 基于标准外设库SPL的STM32F401开发

    Keil MDK STM32系列 Keil MDK STM32系列(一) 基于标准外设库SPL的STM32F103开发 Keil MDK STM32系列(二) 基于标准外设库SPL的STM32F401 ...

  9. Keil MDK STM32系列(四) 基于抽象外设库HAL的STM32F401开发

    Keil MDK STM32系列 Keil MDK STM32系列(一) 基于标准外设库SPL的STM32F103开发 Keil MDK STM32系列(二) 基于标准外设库SPL的STM32F401 ...

  10. Keil MDK STM32系列(三) 基于标准外设库SPL的STM32F407开发

    Keil MDK STM32系列 Keil MDK STM32系列(一) 基于标准外设库SPL的STM32F103开发 Keil MDK STM32系列(二) 基于标准外设库SPL的STM32F401 ...

随机推荐

  1. vite vue3 全局批量注册组件

    方式1-使用import.meta.glob 同webpack的 require.context一样,这个是vite提供的一个方法 import { createApp, defineAsyncCom ...

  2. AtCoder Beginner Contest 184 ABCDE 题解

    A - Determinant 签到. B - Quizzes 签到. C - Super Ryuma 贪心,同时分情况讨论: 1.本身就在范围里面,就1次(特判起始点和终点重合). 2.在两步范围内 ...

  3. 迁移学习&在线学习

    简介 英文: transfer learning 以已训练好的模型A为起点,在新场景中,根据新数据建立模型B 目的:将某个领域或任务上学习到的知识或模式,应用到不同但相关的领域或问题中. 特征提取 使 ...

  4. FT 面试 记录

    冬天的时候呼气呼到玻璃上,出现水雾的质量?? 我们简单的算了一下  是  40mg

  5. ubuntu 安装flash

    安装一直失败 转载 ubuntu 14.04安装flash无效的解决方法 144 作者 Devid 关注 2015.11.20 20:44* 字数 350 阅读 1701评论 1喜欢 0 原文出处:h ...

  6. P9713 「QFOI R1」抱抱 题解

    P9713 「QFOI R1」抱抱 题解 Sol 前置知识:长方体体积公式:\(V = abh\). 我们知道,切割掉 \(x \le k\) 的部分就是把 \(a\) 减去 \(k\),切割掉 \( ...

  7. English-英语发音舌位唇形图

    英语发音舌位唇形图 图0 梯形图 图1 图2 图3

  8. IP: dns-lookup : 查询域名的公网IP地址 解决 DNS域名解析绑架的问题例如访问 raw.githubusercontent.com 的文件

    示例:https://github.com/orgs/community/discussions/42655 https://github.com/mwaskom/seaborn-data/blob/ ...

  9. OS-MacOS-MacBook Pro 的电源管理 + 主动切换独立 或 集成显卡的 gpuswitch 选项;

    通过 MacOS 的: System Information可以查看显卡以及所有的硬件和软件的情况: Activity Monitor 可以监控系统的Energy / CPU / Memory / N ...

  10. 从硬盘爆满到 GitHub 封号,一位前端开发者的开源历险记

    前段时间,我结识了一位前端工程师「1024小神」.他的"战友"是一台 MacBook Air M3(8G+256GB),原本用来开发网页.小程序,绰绰有余. 然而,他的噩梦始于老板 ...