赞
踩
数字滤波是数据处理是常用、灵活、有效的方法。前面的按键程序已经用到了滤波,属于开关量滤波,这里要讨论的是模拟量滤波程序,包括最常用的两种方法,中值滤波和平均值滤波。
中值滤波的原理是,每次取最近几个数的中间值作为输出数据,每个波形的最高和最低几个数被滤掉,优点是基本保留原有数据,能有效抑制大幅值低频尖峰干扰,俗称椒盐噪声。
平均值滤波,就是对最近一些数求平均,是最常用最简单的方法,对高频低幅值随机噪声有效,缺点是会损失原始数据中的高频分量,对高幅值干扰会扩大影响。下面的程序中应用了移位平均算法,效率高,且不受求平均的数据数目大小的影响。两种滤波方式都有一定延时。
AverageFilter.h
- #ifndef __AVERAGEFILTER__
- #define __AVERAGEFILTER__
-
- extern "C" { // 兼容C,按C语言编译,Keil5中的包含文件已经加入了C++兼容,不用再加这一段
- #pragma diag_remark 368 //消除 warning: #368-D: class "<unnamed>" defines no constructor to initialize the following:
-
- #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 "<unnamed>" defines no constructor to initialize the following:
-
- #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 "<unnamed>" defines no constructor to initialize the following:
-
- #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 "<unnamed>" defines no constructor to initialize the following:
-
- #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实战系列源码,按键/定时器/PWM/ADC/DAC/DMA/滤波
STM32实战一 初识单片机
STM32实战二 新建工程
STM32实战三 C++ IO.cpp
STM32实战四 定时器和按键
STM32实战五 板载LED显示数据
STM32实战六 PWM加移相正交
STM32实战七 数字滤波
STM32实战八 DAC/ADC
STM32实战九 编码器
STM32开发过程的常见问题
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。