Forum: Digitale Signalverarbeitung / DSP / Machine Learning FIR - Tiefpass-Filter - Was mache ich falsch


Announcement: there is an English version of this forum on EmbDev.net. Posts you create there will be displayed on Mikrocontroller.net and EmbDev.net.
von Michael H. (overthere)


Bewertung
0 lesenswert
nicht lesenswert
Hallo zusammen,

ich habe einen Zwischenkreis, den ich kontinuiertlich messe mit ~50kHz. 
Dann teile ich die Werte runter (Alle Werte addieren und dann Teilen) 
auf ca. 500Hz. Das ganze füttere ich dann in einen Ringpuffer.
1
void dclink_submit_value(float v){
2
  dclink_ringbuffer_pos=dclink_ringbuffer_pos+1;
3
  if(dclink_ringbuffer_pos>(DCLINK_FIR_TABS-1)){
4
    dclink_ringbuffer_pos=0;
5
  }
6
  dclinkfirbuffer[dclink_ringbuffer_pos]=v;
7
}

Eine weitere Rutine rechnet dann den FIR Filter. Der Code ist angepasst 
und auf dem Computer vorgetestet. Er basiert auf einem FIR-YouTube 
Tutorial.
1
float dclink_fir(void){
2
  const float *coeff     = dclinkfircoeff;
3
  const float *coeff_end = dclinkfircoeff + DCLINK_FIR_TABS;
4
5
  float *buf_val = dclinkfirbuffer + dclink_ringbuffer_pos;
6
7
  float output_ = 0;
8
9
  while(buf_val >= dclinkfirbuffer){
10
    output_ += *buf_val * *coeff;
11
    //printf("[b%li]*[c%li]\n",buf_val-dclinkfirbuffer,coeff-dclinkfircoeff);
12
    buf_val--;
13
    coeff++;
14
  }
15
16
  buf_val = dclinkfirbuffer + DCLINK_FIR_TABS-1;
17
18
  while(coeff < coeff_end){
19
    output_ += *buf_val * *coeff;
20
    //printf("[b%li]*[c%li]\n",buf_val-dclinkfirbuffer,coeff-dclinkfircoeff);
21
    buf_val--;
22
    coeff++;
23
  }
24
  return output_;
25
}

Das ganze läuft auf einem Cotex M4.


Jetzt ist das Problem, dass ich irgendwie keine Tiefpasswirkung habe. 
Gewünscht ist, dass alle Störungen ab 60 Hz durchkommen, ab 80 Hz alles 
weggefiltert wird. Der FIR Filter hat 100 Taps.
1
//f=[0, 30/500, 40/500, 1]; m=[1, 1, 0, 0];
2
const float dclinkfircoeff[]={
3
  -3.2494e-04,  -3.3376e-04,  -3.3278e-04,  -3.1865e-04,  -2.8648e-04,  -2.3028e-04,
4
  -1.4361e-04,  -2.0530e-05,   1.4332e-04,   3.4949e-04,   5.9556e-04,   8.7411e-04,
5
   1.1721e-03,   1.4704e-03,   1.7443e-03,   1.9643e-03,   2.0975e-03,   2.1096e-03,
6
   1.9679e-03,   1.6441e-03,   1.1174e-03,   3.7774e-04,  -5.7099e-04,  -1.7089e-03,
7
  -2.9984e-03,  -4.3835e-03,  -5.7900e-03,  -7.1280e-03,  -8.2943e-03,  -9.1769e-03,
8
  -9.6599e-03,  -9.6305e-03,  -8.9844e-03,  -7.6335e-03,  -5.5117e-03,  -2.5812e-03,
9
   1.1633e-03,   5.6914e-03,   1.0935e-02,   1.6789e-02,   2.3115e-02,   2.9742e-02,
10
   3.6478e-02,   4.3112e-02,   4.9429e-02,   5.5213e-02,   6.0262e-02,   6.4394e-02,
11
   6.7461e-02,   6.9348e-02,   6.9984e-02,   6.9348e-02,   6.7461e-02,   6.4394e-02,
12
   6.0262e-02,   5.5213e-02,   4.9429e-02,   4.3112e-02,   3.6478e-02,   2.9742e-02,
13
   2.3115e-02,   1.6789e-02,   1.0935e-02,   5.6914e-03,   1.1633e-03,  -2.5812e-03,
14
  -5.5117e-03,  -7.6335e-03,  -8.9844e-03,  -9.6305e-03,  -9.6599e-03,  -9.1769e-03,
15
  -8.2943e-03,  -7.1280e-03,  -5.7900e-03,  -4.3835e-03,  -2.9984e-03,  -1.7089e-03,
16
  -5.7099e-04,   3.7774e-04,   1.1174e-03,   1.6441e-03,   1.9679e-03,   2.1096e-03,
17
   2.0975e-03,   1.9643e-03,   1.7443e-03,   1.4704e-03,   1.1721e-03,   8.7411e-04,
18
   5.9556e-04,   3.4949e-04,   1.4332e-04,  -2.0530e-05,  -1.4361e-04,  -2.3028e-04,
19
  -2.8648e-04,  -3.1865e-04,  -3.3278e-04,  -3.3376e-04,  -3.2494e-04};

Ich habe Gleichsspannung am Zwischenkreis getestet. Perfekt, kaum 
rauschen. Ich habe 100Hz, 200Hz ... 500Hz am Zwischrenkreis mit einem 
Netzteil angelegt. Manchmal wird der Minimalwert und manchmal der 
Maximalwert zurückgegeben der Amplitude zurürckgegeben.
Da nix schaltet im Netzteil sind es keine schlechten ADC-Werte.

Ich vermute, dass ich irgendwo einen konzeptionellen Fehler habe. Darf 
ich das Mitteln vor dem FIR nicht? Ich bin einstiger in die Signalwelt 
=) Das ist meine erste FIR.

By the way: Ich habe den Code am Computer vorgetestet und da scheint es 
gut zu funktionieren.

von Joe F. (easylife)


Bewertung
0 lesenswert
nicht lesenswert
1. Läuft das denn schnell genug? Die direct form ist halt die langsamste 
aller Implementierungen...


Edit: habe Punkt 2 gestrichen (rückwärts aus dem Ringbuffer lesen), denn 
es ist richtig so.

Allerdings ist das glaube ich falsch:

float output_ = 0;

hier sollte das aktuelle Sample statt 0 genommen werden.

: Bearbeitet durch User
von Michael H. (overthere)


Bewertung
0 lesenswert
nicht lesenswert
Hallo Joe, vielen Dank für dein Feedback!

Welche Implementierung ist denn schneller?

>float output_ = 0;
Du hast, recht, dass es nicht stimmt, mit der Output_=0, wenn man sich 
das diagram anschaut.
https://de.wikipedia.org/wiki/Filter_mit_endlicher_Impulsantwort#/media/File:Fir_filter_cascade.png
Danke für den Hinweis, für sowas liebe ich das Forum!

Hinsichtlich meines Fehlers: Doing! Ich Idiot. Ich hatte das 
runterteilen Falsch implementiert.
Ich habe das runterteilen korrigiert und in die submit value funktion 
integriert. Für alle, das ist der Code, der funktioniert.
1
float dclink_div_sum=0;
2
uint16_t dclink_div_cnt=0;
3
void dclink_submit_value(float v){
4
  dclink_div_sum=dclink_div_sum+v;
5
  dclink_div_cnt=dclink_div_cnt+1;
6
  if(dclink_div_cnt>DCLINK_VALUES_COMMULATE){
7
    dclink_ringbuffer_pos=dclink_ringbuffer_pos+1;
8
    if(dclink_ringbuffer_pos>(DCLINK_FIR_TABS-1)){
9
      dclink_ringbuffer_pos=0;
10
    }
11
    dclinkfirbuffer[dclink_ringbuffer_pos]=dclink_div_sum/dclink_div_cnt;
12
    dclink_div_cnt=0;
13
    dclink_div_sum=0;
14
  }
15
}

von Joe F. (easylife)


Bewertung
0 lesenswert
nicht lesenswert
Michael H. schrieb:
> Welche Implementierung ist denn schneller?

Bei 100 Taps lohnt sich mit Sicherheit der Weg über eine FFT.

Ansonsten liegt viel Geschwindigkeitspotential darin von Float auf 
Fixpoint zu wechseln.
Da du deinen Algorithmus ja sinnvollerweise auf dem Desktop-Rechner 
überprüfst, kannst du das Ergebnis einer Fixpoint-Implementierung direkt 
mit der Float-Version vergleichen.

Alternativ könnten auch ein paar BiQuads in Reihe ausreichen.
Die haben recht wenig Rechenbedarf, und mit 3-4 Stück hintereinander 
erreicht man auch eine schöne Filtersteilheit.

: Bearbeitet durch User
von Manfred M. (bittbeisser)


Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Ich habe die Filterkoeffizienten mal an mein Testprogramm verfüttert. 
Das Ergebnis sieht eigentlich ganz gut aus. Allerdings sind das 101 
Tabs.
Da mein Programm deine Abtastrate nicht unterstützt, habe ich meinen 
Standardwert von 8000Hz eingesetzt, was man aber anhand der relativen 
Frequenz umrechnen könnte.

>> Dann teile ich die Werte runter (Alle Werte addieren und dann Teilen)...
Das hört sich für mich nach so etwas wie "gleitendem Mittelwert" an. Je 
nachdem wie der realisiert wird kann das effektiv oder eine richtige 
Performancebremse sein.

Mich würde aber mal interessieren, mit welchem Algorithmus der TP 
berechnet wurde bzw. welche Fensterfunktion verwendet wurde.

von W.S. (Gast)


Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Michael H. schrieb:
> Jetzt ist das Problem, dass ich irgendwie keine Tiefpasswirkung habe.
> Gewünscht ist, dass alle Störungen ab 60 Hz durchkommen, ab 80 Hz alles
> weggefiltert wird. Der FIR Filter hat 100 Taps.

Dein Filter sieht ja auch Sch... aus. Ich häng dir das mal als 
Testfilter_wobble dran.

Mein Rat: berechne dir deine Filter selber, dann weißt du wenigstens, 
was du kriegst. Dein Filter ist zum einen ein simpler Tiefpaß, dann 
einer mit ner Grenzfrequenz von nur 25 Hz (wenn man mal 500 Hz 
Samplefrequenz voraussetzt) und mit einem nicht guten Fenster.

So, ich hab dir mal zwei andere Filter drangehängt: beides Bandpässe von 
so etwa 45..80 Hz bei 500 Hz Fsample.

W.S.

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.