中值滤波在数据处理中的角色就是一个和事佬,把数据中的“刺头”剔除出去。如下图所示:
实际的信号就会伴随一些随机噪声和一些强干扰信号,而平均滤波无法滤除强干扰,但随机噪声的滤波效果是不错的,这是平均滤波擅长的,让数据变得平滑,如果能确保需要处理的信号不会有阶跃型的干扰可以上,但是实际使用中是无法保证的,再来看中值滤波后的结果,颇有一种“他强任他强,清风拂山岗”的佛系表现,滤波器很好的过滤了大的“刺头”,也让信号看起来较为平稳。
看到这想必大家也能看出中值滤波的过人之处,那大家可能会有疑惑,到底怎么中值滤波呢?
中值滤波的原理就是对固定数量的信号值进行排序后选择中值作为过滤后的信号点,举例:如果是3阶中值滤波,就是取源信号的三个数的中间值作为滤波后的值,细心的小伙伴可能会发现,那取三个数,第一、二个值怎么取3个数? 事实就是它要采到 阶数个数的值 才能滤波。原理大概讲完了,下面直接上代码:
//中值滤波在使用时一般有两种情况
//1 先采集好数据再进行滤波处理
//2 边采集数据边处理数据
//阶数怎么确定后面会解释 一般来说可以试出来
#define ORDER 10 //阶数
#define N ((ORDER) / 2) //判断中值位置的值
//第一种 先采集好数据再进行滤波处理
/*
*********************************************************************************************************
*函 数 名: MidFilterBlock
*功能说明: 对已经采集好的一段数据进行中值滤波
*形 参: pSrc 源数据地址
* pDst 滤波后数据地址
* blockSize 数据个数,至少为3
* ORDER 至少3阶。
* 注 意:阶数不给设置2是因为我认为2的话就是平均值了,两个值取中值就只能是平均了
* 类型可以根据自己需要进行修改
*返 回 值: 无
*********************************************************************************************************
*/
void MidFilterBlock(uint16_t *pSrc, uint16_t *pDst, uint16_t blockSize)
{
uint16_t i, in; //in 是用来记录放进数据缓冲的位置 相当于环形Fifo
uint16_t DataBuffer[ORDER];//数据缓冲 设置成阶数大小就行了,不需要设置成数据量大小,会造成浪费
uint16_t SortData[ORDER];//排序后的数据
//这里需要判断值得有效性
//assert(pSrc);
//assert(pDst);
//assert(blockSize);
/* 数据幅值给临时缓冲 这里要先填充ORDER个数据才能滤波 也可以用for*/
//for(i = 0; i < blockSize; i++)
//{
//DataBuffer = pSrc;
//}
memcpy(DataBuffer,pSrc,sizeof(DataBuffer));
/* 求每个数据点的中值 为什么blocksize要减去阶数呢?因为采集够10个数据才能开始滤波,滤出来的第一个数据其实要放在10/2=5的位置才能对的上相位,同理可得数据只能过滤到倒数5个的位置,所以数据过滤后比过滤前数据其实会少阶乘个,因为前后5个都是没有足够的数据进行滤波的,实际采样可以多采集ORDER个数据就能得到想要长度的滤波数据*/
for(i =0; i < blockSize-ORDER; i++)
{
/* 排序 排序算法可以自己选择 这里就不放排序代码了 排序里面做的就是把DataBuffer数据copy一份后排序到SortData*/
sort(DataBuffer, SortData, ORDER);
//下面这个判断应该很好理解 就是判断ORDER阶数的中值位置,排序后直接取到中值
/* 奇数 */
if(N)
{
pDst = SortData[N];
}
/* 偶数 */
else
{
pDst = (SortData[N] + SortData[N-1])/2;
}
/* 更新数据缓冲区 */
DataBuffer[i % ORDER] = pSrc[i+ORDER];
}
}
//第二种 边采集数据边处理数据
/*
*********************************************************************************************************
*函 数 名: MidFilterRT
*功能说明: 逐个数据实时滤波的中值滤波器。
*形 参: pSrc 源数据地址。
* pDst 滤波后数据地址。
* ucFlag 1表示首次滤波,后面继续滤波,需将其设置为0。
* ORDER 至少3阶。
* 注 意:阶数不给设置2是因为我认为2的话就是平均值了,两个值取中值就只能是平均了
* 类型可以根据自己需要进行修改
*返 回 值: 无
*********************************************************************************************************
*/
void MidFilterRT(uint16_t *pSrc, uint16_t *pDst, uint8_t ucFlag)
{
uint16_t i;
static uint32_t Count = 0;//这里要注意溢出的时候 可能会出问题
static uint16_t DataBuffer[ORDER];//数据缓冲 设置成阶数大小就行了,不需要设置成数据量大小,会造成浪费
uint16_t SortData[ORDER];//排序后的数据
//这里需要判断值得有效性
//assert(pSrc);
//assert(pDst);
/* 首次滤波先清零 */
if(ucFlag == 1)
{
//这个函数最开始的ORDER/2个数据返回值是0 如果介意可以先在这个部分先传入大于ORDER/2个数据
memset(DataBuffer, 0, sizeof(DataBuffer));
Count = 0;
}
/* 填充数据 这个填充数据后面有图来解释 不懂得话可以先知道这个就是把数据放进来后面去看为什么*/
//DataBuffer[Count++ % ORDER] = pSrc[0];
DataBuffer[Count] = pSrc[0];
if(++Count == ORDER)//这里处理32位数溢出问题
Count = 0;
/* 排序 排序算法可以自己选择 这里就不放排序代码了 排序里面做的就是把DataBuffer数据copy一份后排序到SortData*/
sort(DataBuffer, SortData, ORDER);
//下面这个判断应该很好理解 就是判断ORDER阶数的中值位置,排序后直接取到中值
/* 奇数 */
if(N)
{
pDst[0] = SortData[N];
}
/* 偶数 */
else
{
pDst[0] = (SortData[N] + SortData[N-1])/2;
}
}
|