中值滤波的原理就是对固定数量的信号值进行排序后选择中值作为过滤后的信号点,举例:如果是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_tDataBuffer[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; } } 滤波算法就写好了,下面看看如何使用 //测试代码 #define TEST_LENGTH_SAMPLES 100 //测试点数 uint16_t testdata[TEST_LENGTH_SAMPLES] = { 104, 104, 101, 103, 102, 104, 103, 102, 102, 104, 102, 104, 101, 103, 102, 101, 102, 102, 103, 104, 101, 103, 102, 104, 130, 132, 102, 105, 104, 103, 103, 102, 103, 101, 104, 103, 105, 104, 102, 102, 103, 101, 104, 104, 104, 101, 104, 101, 103, 105, 103, 105, 104, 104, 102, 102, 103, 104, 104, 104, 102, 104, 104, 103, 101, 101, 102, 103, 103, 102, 104, 101, 103, 80, 80, 102, 101, 104, 105, 102, 104, 104, 103, 103, 104, 104, 102, 103, 104, 102, 105, 104, 104, 103, 103, 105, 105, 102, 103, 105 }; uint16_t DstDate[TEST_LENGTH_SAMPLES] ={0}; /* ***************************************************************************************** *函 数 名:MidFilterBlockTest *功能说明: 整块数据的中值滤波测试 *形 参: 无 *返 回 值: 无 ***************************************************************************************** */ void MidFilterBlockTest(void) { MidFilterBlock(testdata,DstDate,TEST_LENGTH_SAMPLES); for(int i = 0; i <TEST_LENGTH_SAMPLES; i++) { printf("%d%d\r\n", testdata, DstDate); } } /* ***************************************************************************************** *函 数 名:MidFilterOneByOneTest *功能说明: 逐个数据滤波测试 *形 参: 无 *返 回 值: 无 ***************************************************************************************** */ void MidFilterOneByOneTest(void) { /* 从头开始,先滤第1个数据 */ MidFilterRT(testdata,DstDate, 1); /* 逐次滤波后续数据 */ for(int i = 1; i <TEST_LENGTH_SAMPLES; i++) { MidFilterRT(&testdata , &DstDate, 0); } for(int i = 0; i <TEST_LENGTH_SAMPLES; i++) { printf("%d %d\r\n", testdata, DstDate); } }
|
滤波算法很有用