移动平均,滤波,平滑等,这些概念其实都大同小异,其作用都是希望能把信号数值中的毛刺、噪点,给去掉抹平捋顺,留下真值。
这类的程序和工作做了不少,一直没有机会总结归纳整理下。趁着这次空挡的时间,写了一个算法调试工具,顺便写篇博客总结一下。
至于写了算法调试工具的目的,主要是为了提高效率。
我们一般调试算法的步骤是:
如果使用算法调试工具,那我们的流程就可以变成这样
按照之前的流程,可能要走很多遍,效率不高。
有了算法调试工具后,理想情况下,一次搞定。
当然这种效率的提高,也是因为前期工作的准备(算法调试工具的开发)。
目前市面上有很多类似的,且更好用的工具,不过自己还是想要结合自身所学,综合考虑,自己开发一个算法调试工具。如下,目前功能还不多,慢慢增加。
简单移动平均
原理
若依次得到一组原始测定值时,按顺序取一定数量的数据并算得其全部算术平均值,得到的数据就叫做移动平均值。
假设:
原始测定值为:
一定数量L 为:(移动平均的窗口长度)
则:
移动平均值:
代码(C#)
int len = (int)simpleLenUpDown.Value; //移动平均的窗口长度
simpleList.Clear();//移动平均值队列
List<double> bufferList = new List<double>();//移动平均窗口队列
for (int i = 0; i < len; i++)
{
if (i >= sourceList.Count)
break;
bufferList.Add(sourceList[i]);
simpleList.Add(sourceList[i]);
}
for (int i = len; i < sourceList.Count; i++)
{
simpleList.Add(bufferList.Average());
bufferList.RemoveAt(0);
bufferList.Add(sourceList[i]);//移动
}
//刷新结果
chartControl.BeginInit();
Series series = new Series(simpleStr, ViewType.Line);
series.Label.ResolveOverlappingMode = ResolveOverlappingMode.HideOverlapped;
for (int i = 0; i < simpleList.Count; i++)
{
SeriesPoint seriesPoint = new SeriesPoint(i, simpleList[i]);
series.Points.Add(seriesPoint);
}
chartControl.Series.Add(series);
series.ArgumentScaleType = ScaleType.Numerical;
chartControl.EndInit();
效果图
移动平均的窗口长度L=5
移动平均的窗口长度L=50
分析
两张效果图已经很明细了,窗口L如果太小,则平滑效果不好。
窗口L如果太大,则会有明显的迟滞效应。
所以这种简单移动平均的应用很有局限性,需要你小心的调整这个窗口L的大小。
加权移动平均
原理
主要方法是,通过给较近的数值分配较高的权重,给较远的数值分配较低的权重。
主要目的是,在有不错的平滑效果情况下,尽量的减少其迟滞效应,更能反映当前的真值和未来的预测值。
权重分配的方法有很多,用的比较多的是线性法和指数法。以下以线性加权移动平均为例。
假设:
原始测定值为:
一定数量L 为:(移动平均的窗口长度)
则:
线性加权移动平均值:
代码(C#)
private double getWeightListAverage(List<double> bufferList)
{
double sum = 0;
int sumIndex = 0;
for (int i = 0; i < bufferList.Count; i++)
{
sumIndex += i;
sum += (i * bufferList[i]);
}
return sum / sumIndex;
}
private void weightUpdateBtn_Click(object sender, EventArgs e)
{
removeSeries(weightStr);
int len = (int)weightLenUpDown.Value;
weightList.Clear();
List<double> bufferList = new List<double>();
for (int i = 0; i < len; i++)
{
if (i >= sourceList.Count)
break;
bufferList.Add(sourceList[i]);
weightList.Add(sourceList[i]);
}
for (int i = len; i < sourceList.Count; i++)
{
weightList.Add(getWeightListAverage(bufferList));
bufferList.RemoveAt(0);
bufferList.Add(sourceList[i]);
}
chartControl.BeginInit();
Series series = new Series(weightStr, ViewType.Line);
series.Label.ResolveOverlappingMode = ResolveOverlappingMode.HideOverlapped;
for (int i = 0; i < weightList.Count; i++)
{
SeriesPoint seriesPoint = new SeriesPoint(i, weightList[i]);
series.Points.Add(seriesPoint);
}
chartControl.Series.Add(series);
series.ArgumentScaleType = ScaleType.Numerical;
chartControl.EndInit();
}
效果图
卡夫曼自适应移动平均
原理
卡夫曼自适应移动不同于以上两种的移动平均算法,它既能快速反应当前的真值和预测值,又能又较好的平滑效果。
原始测定值为:
窗口长度:
短(快)周期长度:
长(慢)周期长度:
波动性
方向性
效率系数
短周期均线系数
长周期均线系数
平滑系数
公式
代码(C#)
int len = (int)amaLenUpDown.Value;
int fastLen = (int)amaFastLenUpDown.Value;
int slowLen = (int)amaSlowLenUpDown.Value;
amaList.Clear();
double ama=0, lastAma=0;
for (int i = 0; i < len; i++)
{
if (i >= sourceList.Count)
break;
lastAma = sourceList[i];
ama = lastAma;
amaList.Add(ama);
}
for (int i = len; i < sourceList.Count; i++)
{
double direction = 0, er = 0, smooth= 0, c = 0, vol = 0;
double fastest = 2.0 / (fastLen + 1);
double slowest = 2.0 / (slowLen + 1);
for (int j = i-len; j < i-1; j++)
vol += Math.Abs(sourceList[j] - sourceList[j + 1]);
if (vol != 0)
{
direction = Math.Abs(sourceList[i] - sourceList[i - len]);
er = direction / vol;
smooth1 = er * (fastest - slowest) + slowest;
c = smooth * smooth;
ama = lastAma + c * (sourceList[i] - lastAma);
if (c>1000)
{ //防止大跳跃,大突变
ama = sourceList[i];
}
lastAma = ama;
}
else
{
ama = lastAma;
}
amaList.Add(ama);
}
chartControl.BeginInit();
Series series = new Series(amaStr, ViewType.Line);
series.Label.ResolveOverlappingMode = ResolveOverlappingMode.HideOverlapped;
for (int i = 0; i < amaList.Count; i++)
{
SeriesPoint seriesPoint = new SeriesPoint(i, amaList[i]);
series.Points.Add(seriesPoint);
}
chartControl.Series.Add(series);
series.ArgumentScaleType = ScaleType.Numerical;
chartControl.EndInit();
效果图
分析
不需要很大的窗口,就能有很好的平滑效果,且迟滞性很低。
这次分享到此结束,这类博客还有很多可以写的,后面希望能写出一个系列,分享更多更优更好的算法,迭代功能更强的算法调试工具。