移動平均,濾波,平滑等,這些概念其實都大同小異,其作用都是希望能把信號數值中的毛刺、噪點,給去掉抹平捋順,留下真值。
這類的程序和工作做了不少,一直沒有機會總結歸納整理下。趁着這次空擋的時間,寫了一個算法調試工具,順便寫篇博客總結一下。
至於寫了算法調試工具的目的,主要是爲了提高效率。
我們一般調試算法的步驟是:
如果使用算法調試工具,那我們的流程就可以變成這樣
按照之前的流程,可能要走很多遍,效率不高。
有了算法調試工具後,理想情況下,一次搞定。
當然這種效率的提高,也是因爲前期工作的準備(算法調試工具的開發)。
目前市面上有很多類似的,且更好用的工具,不過自己還是想要結合自身所學,綜合考慮,自己開發一個算法調試工具。如下,目前功能還不多,慢慢增加。
簡單移動平均
原理
若依次得到一組原始測定值時,按順序取一定數量的數據並算得其全部算術平均值,得到的數據就叫做移動平均值。
假設:
原始測定值爲:
一定數量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();
效果圖
分析
不需要很大的窗口,就能有很好的平滑效果,且遲滯性很低。
這次分享到此結束,這類博客還有很多可以寫的,後面希望能寫出一個系列,分享更多更優更好的算法,迭代功能更強的算法調試工具。