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


von Michael H. (overthere)


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)


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)


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)


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:

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)



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.

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
Noch kein Account? Hier anmelden.