目录
开发嵌入式产品时,通常会用到平均值采样法,降低采集数据的误差,提高准确性。
平均值采样法指在一定时间内对采样的数据进行累加,用累加和除以采样的次数,得到平均数,将计算出来的平均值作为有效数据使用。
简要介绍直接计算法和递推法,了解两者的差别。
1、传统方法:直接法
直接法,直接进行加和求平均,方法简单直接,数学公式如下所示:
该方法缺点是在内存比较小的单片机系统中,若需要计算大样本集的场合,就捉襟见肘。例如几万样本时,内存可能就不够了。实现代码如下所示:
-
float mean(float *pSample,int size)
-
{
-
if(pSample==
NULL || size<=
0)
-
return NAN;
-
-
float sum =
0;
-
for(
int i=
0;i<size;i++)
-
{
-
sum += *pSample;
-
pSample++;
-
}
-
-
return (sum/size);
-
}
2、高效方法:递推法
递推法是对直接法的简化。
因为n个样本均值计算公式如下所示:
则前n-1个样本的均值计算公式如下所示:
简化得出:
进而简化:
所以递推法实现代码如下所示:
-
float recursive_mean(float xn,int size)
-
{
-
static
int index =
0;
-
static
float last_mean =
0.0f;
-
float mean =
0.0f;
-
-
if(index<size
-1)
-
{
-
index++;
-
mean = last_mean+(xn-last_mean)/index;
-
}
-
else
-
{
-
mean = last_mean+(xn-last_mean)/size;
-
index =
0;
-
last_mean =
0.0f;
-
}
-
-
last_mean = mean;
-
return mean;
-
}
当在样本窗未满时,按实际传入样本大小递推,在样本窗满后,按实际传入样本大小递推,并复位索引。
在嵌入式应用中,如果所需要统计的样本非常大时,这种算法将非常有实用价值,只需要极小的内存开销。尤其在一些传感器测量应用中,该方法非常有价值。
3、实践
随机生成一组数据,使用这两种方法,实现平均值采样,代码如下所示:
-
#include <stdio.h>
-
#include <stdbool.h>
-
#include <math.h>
-
-
float mean(float *pSample,int size)
-
{
-
if(pSample==
NULL || size<=
0)
-
return NAN;
-
float sum =
0;
-
for(
int i=
0;i<size;i++)
-
{
-
sum += *pSample;
-
pSample++;
-
}
-
-
return (sum/size);
-
}
-
-
float recursive_mean(float xn,int size)
-
{
-
static
int index =
0;
-
static
float last_mean =
0.0f;
-
float mean =
0.0f;
-
-
if(index<size
-1)
-
{
-
index++;
-
mean = last_mean+(xn-last_mean)/index;
-
}
-
else
-
{
-
mean = last_mean+(xn-last_mean)/size;
-
index =
0;
-
last_mean =
0.0f;
-
}
-
-
last_mean = mean;
-
return mean;
-
}
-
-
#define N (1000)
-
#define SAMPLE_SIZE (100)
-
-
int main(int argc, char *argv[])
-
{
-
float sim[N];
-
float out[N/SAMPLE_SIZE];
-
-
for(
int i=
0;i<N;i++)
-
{
-
sim[i]=i*
5+rand()%
10;
-
}
-
printf(
"\n\n");
-
-
int j=
0;
-
for(
int i=
0;i<N;i=i+SAMPLE_SIZE)
-
{
-
out[j] = mean(&sim[i],SAMPLE_SIZE);
-
j++;
-
}
-
-
for(j=
0;j<N/SAMPLE_SIZE;j++)
-
{
-
printf(
"%.2f,",out[j]);
-
}
-
printf(
"\n");
-
-
j =
0;
-
for(
int i=
0;i<N;i++)
-
{
-
out[j]=recursive_mean(sim[i],SAMPLE_SIZE);
-
-
if((i+
1)%SAMPLE_SIZE==
0)
-
j++;
-
}
-
for(j=
0;j<N/SAMPLE_SIZE;j++)
-
{
-
printf(
"%.2f,",out[j]);
-
}
-
printf(
"\n");
-
-
return
0;
-
}
结果如下所示:
-
252.
14,
752.
38,
1251.
85,
1751.
82,
2252.
57,
2752.
25,
3251.
78,
3751.
58,
4252.
06,
4752.
02,
-
252.
14,
752.
38,
1251.
85,
1751.
82,
2252.
57,
2752.
25,
3251.
78,
3751.
58,
4252.
06,
4752.
02,
两种计算方法效果一样,但是第二种方法消耗极小的内存。当然这增加了函数调用次数,在大样本计算时非常有利。
整理来源于:数学之美:均值计算的两种算法(C实现)
转载:https://blog.csdn.net/m0_38106923/article/details/108962236
查看评论