实用单片机采集数据时,往往需要对一些采集的数据进行计算,常用的计算方式比如求平均值、加权平均算法等;本次也记录几个学习过的算法。
1、缓冲滤波算法
算法原理:将数据缓存在一个数组中,每次插入一个数据,就移除最早进入的数据,然后对该数组的数据进行排列后,取中间的部分数据求平均值;
优点:对于采集的数据动态变化较快情况,该算法能够很好的滤除波动误差,使数据趋近一个比较稳定的值。该滤波算法适用于静态数据变化;
缺点:数据计算过程繁多,需要一定的数据进行缓存;
算法实现:C语言
/********************************************************************
*@函数名:BubbleSort(uint16_t *arr, uint16_t n)
*@功 能:冒泡排序算法,将数据按照从小到大的顺序进行排列
*@形 参:arr 指向数据缓存区的指针 n 数据个数
*@返回值:NULL
*@备 注:NULL
********************************************************************/
void BubbleSort(uint16_t *arr, uint16_t n)
{
uint16_t i, j;
uint16_t temp;
for(i=0; i<n; i++)
{
for(j=i+1; j<n; j++)
{
if(arr[i] > arr[j])
{
temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
}
}
}
/********************************************************************
*@函数名:GetSum(uint16_t *buff, uint16_t start, uint16_t num)
*@功 能:数据求和
*@形 参:buff 指向数据缓存区的指针 num 数据个数
*@返回值:求和结果
*@备 注:NULL
********************************************************************/
uint32_t GetSum(uint16_t *buff, uint16_t start, uint16_t num)
{
uint16_t i;
uint32_t sum = 0;
num = num+start;
for(i=start; i<num; i++)
{
sum += buff[i];
}
return sum;
}
#define FIFO_SIZE 10
uint16_t FiftBuff[FIFO_SIZE];
/********************************************************************
*@函数名:Fift
*@功 能:缓冲滤波算法
*@形 参:value 需要滤波的数据
*@返回值:滤波后的结果
*@备 注:NULL
********************************************************************/
uint16_t Fift(uint16_t value)
{
uint8_t i;
uint32_t sum;
static uint16_t buf[FIFO_SIZE];
static uint8_t num=0;
if(num >= FIFO_SIZE)
{
num = 0;
}
FiftBuff[num++] = value;
for(i=0; i<FIFO_SIZE; i++)
{
buf[i] = PhCheckBuff[i];
}
BubbleSort(buf, FIFO_SIZE);
sum = GetSum(buf, FIFO_SIZE/4, FIFO_SIZE/2);
return sum/(FIFO_SIZE/2);
}
2、一阶滞后滤波算法
一阶滞后滤波算法数学计算公式为:
式中:是输出结果,α是滤波系数,是本次采样值,是上一次的输出结果
一阶滤波相当于是将新的采样值与上次的滤波结果计算一个加权平均值,算法的效果就是滞后于系统变化,可以滤除数据的各种干扰,使得系统收敛。a的取值决定了算法的灵敏度,α越大,新采集的值占的权重越大,算法越灵敏,但平顺性差;相反,α越小,新采集的值占的权重越小,灵敏度差,但平顺性好。,其效果图如下所示:蓝色为原始数据,红色为滤波数据;
图1:一阶滞后滤波算法效果图
/********************************************************************
*@函数名:FirstOrderFilter(float newdata, float lastdata, float k)
*@功 能:一阶滤波算法
*@形 参:newdata 新数据 lastdata 上次数据 k 滤波系数
*@返回值:滤波后数据
*@备 注:k : 0.0~1.0
********************************************************************/
float FirstOrderFilter(float newdata, float lastdata, float k)
{
lastdata = k*newdata + (1-k)*lastdata;
return(lastdata);
}
由于上述的算法具有浮点型运算,所以为了计算效率,在实际计算过程中使用整形进行计算的方式如下:
/********************************************************************
*@函数名:FOL_Filter(uint16_t newdata, uint16_t olddata, uint8_t k)
*@功 能:一阶滞后滤波算法
*@形 参:newdata 新数据 olddata 上次数据 k 滤波系数
*@返回值:滤波后数据
*@备 注:k : 1~255 为减小滤波计算
********************************************************************/
uint16_t FOL_Filter(uint16_t newdata, uint16_t olddata, uint8_t k)
{
uint32_t result;
if(newdata < olddata)
{
result = olddata - newdata;
result = result * k;
result = result + 128;
result = result>>8; //除以256
result = olddata - result;
}
else if(newdata > olddata)
{
result = newdata - olddata;
result = result * k;
result = result + 128;
result = result>>8; //除以256
result = olddata + result;
}
else result = olddata;
return(result);
}
3、卡尔曼滤波算法
什么是卡尔曼滤波?百度解释为:卡尔曼滤波(Kalman filtering)是一种利用线性系统状态方程,通过系统输入输出观测数据,对系统状态进行最优估计的算法。
具体的原理可以自行百度,本次只提供相关的实现代码:
/********************************************************************
*@函数名:KalmanFilter(float newdata)
*@功 能:卡尔曼滤波
*@形 参:newdata 新数据
*@返回值:滤波后数据
*@备 注:要定义过程噪声和测量噪声
********************************************************************/
/*
Q: 过程噪声,Q增大,动态响应变快,收敛稳定性变坏
R: 测量噪声,R增大,动态响应变慢,收敛稳定性变好
其中p的初值可以随便取,但是不能为0(为0的话卡尔曼滤波器就认为已经是最优滤波器了)
q,r的值需要我们试出来,讲白了就是(买的破温度计有多破,以及你的超人力有多强)
r参数调整滤波后的曲线与实测曲线的相近程度,r越小越接近。
q参数调滤波后的曲线平滑程度,q越小越平滑。
*/
//过程噪音
#define P_Q 0.1
//测量噪声
#define M_R 0.01
float KalmanFilter(float newdata)
{
static float lastdata=0;
//其中p的初值可以随便取,但是不能为0(为0的话卡尔曼滤波器就认为已经是最优滤波器了)
static float p=0.01;
float q = P_Q, r = M_R, kGain = 0;
p = p+q;
kGain = p/(p+r); //卡尔曼滤波系数
newdata = lastdata + (kGain*(newdata-lastdata));
p = (1-kGain)*p;
lastdata = newdata;
return newdata;
}
|