历史上的今天
今天是:2025年08月01日(星期五)
2019年08月01日 | STM32实战七 数字滤波
2019-08-01 来源:eefocus
数字滤波是数据处理是常用、灵活、有效的方法。前面的按键程序已经用到了滤波,属于开关量滤波,这里要讨论的是模拟量滤波程序,包括最常用的两种方法,中值滤波和平均值滤波。
中值滤波的原理是,每次取最近几个数的中间值作为输出数据,每个波形的最高和最低几个数被滤掉,优点是基本保留原有数据,能有效抑制大幅值低频尖峰干扰,俗称椒盐噪声。
平均值滤波,就是对最近一些数求平均,是最常用最简单的方法,对高频低幅值随机噪声有效,缺点是会损失原始数据中的高频分量,对高幅值干扰会扩大影响。下面的程序中应用了移位平均算法,效率高,且不受求平均的数据数目大小的影响。两种滤波方式都有一定延时。
AverageFilter.h
#ifndef __AVERAGEFILTER__
#define __AVERAGEFILTER__
extern "C" { // 兼容C,按C语言编译,Keil5中的包含文件已经加入了C++兼容,不用再加这一段
#pragma diag_remark 368 //消除 warning: #368-D: class " #include "stm32f10x.h" #pragma diag_default 368 // 恢复368号警告 } #define AF_MAXWINDOW 150 // 最大窗宽150 class AverageFilter { // Construction public: AverageFilter( s32 ini, u16 nNum ); // Properties public: u16 m_number; // 指定平均的个数,最多150 u16 m_seek; // 游标 s32 m_summation; // 指定数组的总和 s32 m_input[AF_MAXWINDOW]; // 数据缓存 private: // Methods public: s32 filter( s32 vi ); // 滤波算法 // Overwrite public: }; #endif AverageFilter.cpp /** ****************************************************************************** * @file AverageFilter.cpp * @author Mr. Hu * @version V1.0.0 STM32F103VET6 * @date 06/06/2019 * @brief 均值滤波 ****************************************************************************** * @remarks * 采用移位平均法,大大提高效率,不受数据数量的影响 */ /* Includes ------------------------------------------------------------------*/ extern "C" { // 兼容C,按C语言编译,Keil5中的包含文件已经加入了C++兼容,不用再加这一段 #pragma diag_remark 368 //消除 warning: #368-D: class " #pragma diag_default 368 // 恢复368号警告 } #include "AverageFilter.h" /** * @date 06/06/2019 * @brief 均值滤波 * @param ini 初始值,避免前几个输出数偏差太大 * @param nNum 滤波数量,最大150,越大效果越好,但延时较多 * @retval None */ AverageFilter::AverageFilter( s32 ini, u16 nNum ) : m_number(nNum) , m_seek(0) , m_summation(0) { if( m_number > AF_MAXWINDOW ) // 控制在数组范围内 m_number = AF_MAXWINDOW; // 初始化数组 for( int i = 0; i < AF_MAXWINDOW; i++ ) { m_input[i] = ini; } // 初始化总和 m_summation = ini * m_number; } /** * @date 06/06/2019 * @brief 滤波算法,采用移位算法,减去第一个,加上最后一个。 * @param vi 输入数据 * @retval 滤波后输出数据 */ s32 AverageFilter::filter( s32 vi ) { m_summation += ( vi - m_input[m_seek] ); // 总和中减去最早的数,加上新数 // 用循环方法记录输入数据 assert_param(m_number <= AF_MAXWINDOW); m_input[m_seek] = vi; if (++m_seek >= m_number) m_seek = 0; // 返回平均值 return m_summation / m_number; } MedianFilter.h #ifndef __MEDIANFILTER__ #define __MEDIANFILTER__ extern "C" { // 兼容C,按C语言编译,Keil5中的包含文件已经加入了C++兼容,不用再加这一段 #pragma diag_remark 368 //消除 warning: #368-D: class " #include "stm32f10x.h" #pragma diag_default 368 // 恢复368号警告 } #define DF_MAXWINDOW 21 // 最大窗宽,奇数,太大了反而不好 class MedianFilter { // Construction public: MedianFilter( s32 ini, u16 nNum ); // Properties public: u16 m_dfMedian; // 半窗宽,最大10 u16 m_seek; // 输入数据指针 s32 m_input[DF_MAXWINDOW]; // 输入数据,循环使用,不用移位,提高效率 s32 m_sort[DF_MAXWINDOW]; // 排序数据,最近输入的数据排序,取中间值输出 private: // Methods public: s32 filter( s32 vi ); // 滤波算法 // Overwrite public: }; #endif MedianFilter.cpp /** ****************************************************************************** * @file MedianFilter.cpp * @author Mr. Hu * @version V1.0.0 STM32F103VET6 * @date 06/05/2019 * @brief 中值滤波 ****************************************************************************** * @remarks * 中值滤波的原理是,每次取最近几个数的中间值作为输出数据,每个波形的最高和最低 * 几个数被滤掉,优点是基本保留原有数据,相当于去掉几个最高数,去掉几个最低数,能有 * 效抑制大幅值低频尖峰干扰,俗称椒盐噪声。 */ /* Includes ------------------------------------------------------------------*/ extern "C" { // 兼容C,按C语言编译,Keil5中的包含文件已经加入了C++兼容,不用再加这一段 #pragma diag_remark 368 //消除 warning: #368-D: class " #pragma diag_default 368 // 恢复368号警告 } #include "MedianFilter.h" /** * @date 06/05/2019 * @brief 中值滤波 * @param ini 初始值,前几个输出数都是这个值 * @param nNum 滤波数,最大10,越大效果越好,但延时较多 * @retval None */ MedianFilter::MedianFilter( s32 ini, u16 nNum ) : m_dfMedian(nNum) , m_seek(0) { if( m_dfMedian > (DF_MAXWINDOW - 1) / 2 ) // 中值限制在数组范围内 m_dfMedian = (DF_MAXWINDOW - 1) / 2; // 初始化两个数组 for( int i = 0; i < DF_MAXWINDOW; i++ ) { m_input[i] = ini; m_sort[i] = ini; } } /** * @date 06/05/2019 * @brief 滤波算法 * @param vi 输入数据 * @retval 滤波后输出数据 */ s32 MedianFilter::filter( s32 vi ) { u8 w1 = m_dfMedian * 2; // 窗宽-1 assert_param(w1 < DF_MAXWINDOW); // 计算将要移除的值在排序数组中的位置 u8 j = 0; for (; j <= w1 && m_input[m_seek] != m_sort[j]; j++); // 移除最早的数据并把新数据插入到适当的位置 // 如果新数据在较小半段,数据后移,否则数据前移,实现排序 // 只处理大于和小于情况,等于时不动 if (vi < m_input[m_seek]) { // 向前移 while (j > 0 && vi < m_sort[j-1]) { j--; m_sort[j + 1] = m_sort[j]; } } else if (vi > m_input[m_seek]) { // 向后移 while (j < w1 && vi > m_sort[j+1]) { j++; m_sort[j - 1] = m_sort[j]; } } // 加入新值 assert_param(j >= 0 && j < w); m_sort[j] = vi; // 用循环方法记录输入数据,高效 m_input[m_seek] = vi; if (++m_seek > w1) m_seek = 0; // 返回中间值 return m_sort[m_dfMedian]; }
下一篇:STM32实战八 DAC/ADC
史海拾趣
|
赛灵思公司(Xilinx)今天宣布获得汽车行业质量标准ISO/TS 16949认证。ISO/TS 16949标准使赛灵思公司能够为整个汽车供应链提供质量和可靠性最高的电子元器件。赛灵思公司在此之前已经满足了其它世界级质量标准的严格要求,包括ISO 9 ...… 查看全部问答> |
|
所有代码均在Keil C51 7.0以上版本编译通过。只需要能够运行Windows 98 以上版本的操作系统、并能够安装Keil C51 7.0以上版本的软件即可。… 查看全部问答> |
|
1、阅读了一下i.MX51 ARM Cortex A8的datasheet,对于IOMUX还是不清楚, 2、还有一些缩写如:PAD、ALTn(n=0, 1, 2...)等等很多,配置一个引脚做很多工作。 3、感觉freescale的比较难理解,以前做三星的一看寄存器就知道是干什么的。 ...… 查看全部问答> |
|
定制系统时加入了微软拼音中文输入法,结果运行时,只出声母,不出韵母,打不出中文来,请问有人遇到过没,怎么解决? 1、设置了环境变量SET LOCALE=0804; 2.在platform settings中选择了中文(中国),英文(美国),默认语言设为中文; 3.在P ...… 查看全部问答> |
|
不知道大家对于调试的看法怎么样。一般你在调试的时候是release还是debug的。我每次都基本上时release的。因为是经理教的。只有在调试一些流层性,我们不知道架构的东西我才用debug。反正基本上不用。。用过几次也很懊恼。。点个屏漫天的打印信息。 ...… 查看全部问答> |
|
求助:料仓里的白石灰粉,当放料后,形成如图(四周高,中间低的料位情况)。 这时候测量仪表无法准确测了料位高度。 求助解决方法:如何能让料仓里的料位处于相对水平状态;或者采用什么样的仪表才能够做到精确测量?… 查看全部问答> |




