Hallo, hat von euch schon mal jemand einen Medianfilter auf einen STM32F4 programmiert? Ich benötige diesen um aus einer Datenreihe Ausreißer zu entfernen. Meinen derzeitigen Medianfilter habe ich mit for-schleifen gelöst. mit einer Filterlänge von 5 Punkte. kennt ihr eine DSP-Funktion des Cortex-M4 einen Median-Filter zu optimieren? Mein Ziel ist es, eine bessere Performance zu erreichen. Derzeit benötigt mein Medianfilter bei einer Datenlänge von ca. 1000Punkte ungefähr 6ms. LG Michael
Michael Höller schrieb: > Meinen derzeitigen Medianfilter habe ich mit for-schleifen gelöst. Dass da irgendwo ne Schleife ist, sollte klar sein. Wenn etwas optimiert werden soll, brauchen wir den code. Ansonsten findet man sogar auf dieser Seite Implementierungen in c
Wenn man den Ist-Zustand nicht kennt, dann kann man keine brauchbaren Tipps zur Optimierung geben. Beispiel für völlig unbrachbaren Tipp: :) Du schreibst >Derzeit benötigt mein Medianfilter bei einer Datenlänge von ca. >1000Punkte ungefähr 6ms. Dann schreib ich einfach: Verzehnfache deine Taktfrequenz, dann brauchst Du nur noch 0.6ms.
:) Okay!
hier mein derzeitiger Programmcode:
static void MedianFilter(void)
{
// TODO
//
static unsigned short z = 0, y = 0, x = 0, v = 0, min = 0, temp = 0;
static unsigned short window[5];
for(z = 2; z < (buffer_index - 2); z++)
{
for(y = 0; y < 5; y++)
{
window[y] = FilterData.D_Buf_CACHE[y+z];
}
for(x = 0; x < 3; x++)
{
min = x;
for((v = x +1); v < 5; v++)
{
if(window[v] < window[min])
min = v;
}
temp = window[x];
window[x] = window[min];
window[min] = temp;
}
// get result --> middle element
FilterData.D_MF_Buf[z - 2] = window[2];
}
}
Fertige DSP - Funktionen gibt es ja anscheinend nicht, ähnliche wie bei
den FIR-Filtern zum beispiel!
vielen Dank
Auf der Seite http://stackoverflow.com/questions/480960/code-to-calculate-median-of-five-in-c-sharp findet sich einiges genau dazu. Die Antwort von answered Jan 26 '09 at 21:20 erscheint nachvollziehbar, während das von answered Jan 22 '10 at 12:00 doch ziemlich heftig ist. Gruss
Erster Gedanke: Muss der Filter nachträglich laufen oder ginge das auch direkt beim Eintreffen von genügend (Fenstergröße) Daten? Zweiter Gedanke: Das Sortieren ist in dieser Form nicht nötig. Stichwort ist find-k-smallest-element / Blum-Floyd-Pratt-Rivest-Tarjan-Algorithmus 1) was den Aufwand an dieser Stelle auf O(n) senken würde (bei dieser Fenstergröße eigentlich nicht nötig). Dritter Gedanke: Warum braucht der jetzige Algorithmus so lange? Grob überschlagen bei 1000 Elementen: - 1000 * 5 Lesezugriffe auf das Ausgangsarray, 5000 - 1000 * 5 Schreibzugriffe auf das Fenster, 5000 - 1000 * (18 Schreib- und 6 Lesezugriffe und 9 Vergleiche), 33000 - 1000 * (1 Schreib- und Lesezugriff zum Zurückschreiben), 2000 Grob 45000 Operationen in 6 ms also 7.5 MHz... 1) http://people.csail.mit.edu/rivest/pubs/BFPRT73.pdf (wer mal Info oder ähnliches studiert (hat), wird wahrscheinlich mehr als einen der Autoren wiedererkennen ;))
Ich werfe mal etwas Wahrscheinlichkeit mit in die Auswertung. Die Auswertung dauert also ca. 33 Cycles. Bei
1 | for(z = 2; z < (buffer_index - 2); z++) |
2 | {
|
3 | for(y = 0; y < 5; y++) |
4 | {
|
5 | window[y] = FilterData.D_Buf_CACHE[y+z]; |
6 | }
|
wird ja im Endeffekt Daten[y] bis Daten[y+4] untersucht. Beim nächsten Durchlauf untersucht man Daten[y+1] bis Daten[y+5]. Es wird also nur Datenpunkt Data[y] mit Data[y+5] ersetzt, der Rest bleibt erhalten. Ist also der Datenpunkt Data[y] der herausfällt, nicht der Median, gibt es zwei Möglichkeiten: Er ist entweder größer als der Median oder kleiner. Trifft auf Data[y+5] das selbe zu (Also beide sind größer/kleiner als der Median) ändert sich der Median nicht. Also:
1 | if((Data[y] > Median_alt) && (Data[y+5] > Median_alt)) |
2 | Median_neu = Median_alt; |
Das selbe gilt auch für Data[y] < Median_alt Fügt man also zusätzliche 4 Vergleiche zu den 33 Cycles der Auswertung, hat man 37 Cycles. Zu 40% (Bei statistischen Zahlen) trifft aber der Fall ein, dass Data[y] und Data[y+5] im selben Verhältnis zum Median stehen, wodurch sich der Durchlauf für diese Daten auf 4 Cycles reduziert. Das ergibt im Durchschnitt: 0,4* 4 Cycles + 0,6 * 37 = 23,8 Cycles. Man reduziert also die 45000 Cycles auf 35800 Cycles, also von 6ms auf 4,77ms Das wäre so meine Idee, ohne jetzt groß den Auswertealgorhithmus zu ändern :D
"Fieser" Trick: Wenn die ersten 5 Werte sortiert sind, braucht bei den nächsten 5 Werten nur noch geschaut werden wo sich der neue einsortiert.
1 | for (int i = 1; i < 1000 - 5; i++) { |
2 | // value to be deleted from window
|
3 | unsigned short vd = array[i - 1]; |
4 | // value to be added to window
|
5 | unsigned short va = array[i + 4]; |
6 | for (int j = 0; j < 5; j++) { |
7 | if (window[j] == vd) { |
8 | // total operations in k-loop: 5 + 5 comparisons + 4 read and 4 + 1 write operation
|
9 | for (int k = 0; k < 5; k++) { |
10 | if (k == j) continue; |
11 | if (va < window[k]) { |
12 | // now insert va...
|
13 | // d, v1, v2, v3, v4
|
14 | // v0, d, v2, v3, v4
|
15 | // v0, v1, d, v3, v4
|
16 | // v0, v1, v2, d, v4
|
17 | // v0, v1, v2, v3, d
|
18 | }
|
19 | }
|
20 | break; |
21 | }
|
22 | }
|
23 | }
|
Das sollten, falls der Algorithmus so stimmt, dann 1000 * (5 + 5 + 5 + 4 + 5) = 1000 * 24 = 24000 Operationen sein (da fehlen noch die Vergleiche, um die passenden Verschiebungen im Fenster zu erledigen)
vielen Dank für Eure Denkanstöße, werde jetzt einmal ein paar Vorschläge testen! Danke!!! Michael.
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.