Design eines Bandpasses

Gast #3533808
Hallo :)

Ich versuche grade einen Digitalen Bandpass in C zu implementieren. 
Leider klappt das nicht ganz so wie gewünscht.

Ich versuche folgende Schaltung nachzubauen:
1
 Uin     ____          Uout
2
 o------|____|---+----+--o
3
           R     |    |
4
                 L   _|_C
5
                 L   ___
6
                 L    |
7
                 |    |
8
                 +----+
9
                      |
10
                     _|_
11
                      -

Die Übertragungsfunktion für das System ist:

wobei meine Resonanzfrequenz
ist und meine Bandbreite
Damit habe ich eine Null bei
und 2 Pole bei

Jetzt will ich diesen Filter in die Z-Ebene bringen.

Dieser Seite [1] habe ich die Transformation
entnommen, wobei T die Periodendauer meiner Abtastung ist.

Damit bekomme ich für die Nullstelle
und für die erste Polstelle:
Die zweite Polstelle ist entsprechend komplex konjugiert.

Nun multipliziere ich den Nenner aus:

Jetzt erhalte ich für mein ganzes Polynom:

Das nurnoch kürzen:

Erstmal, ist das soweit richtig?

Als nächstes habe ich einen konkreten Fall gewählt, und zwar
und

und das ganze in C++ implementiert. Als Umsetzung der Filterstruktur
habe ich die Direktform 2 gewählt [2].

Hier der dazugehörige Code:
1
#define _USE_MATH_DEFINES
2
#include <math.h>
3
#include <iostream>
4

5
int main()
6
{
7
  double w0 = 100 * 2 * M_PI; // 100Hz
8
  double w_band = 2 * M_PI * 10; // 10Hz -3db
9
  double samplerate = 1000; // abtastrate in Hz
10

11
  double w_res_sq = w0 * w0;
12
  
13
  double pol_real = -w_band / 2; // realteil des pols
14
  double pol_img = sqrt(w_res_sq - w_band * w_band / 4); // imaginärteil des pols
15
  double exp_real = pol_real / samplerate; // mit T skaliert
16
  double exp_img = pol_img / samplerate;
17
  // e^(a+bi) = e^a * e^(bi) = e^a * (cos(b)+i*sin(b))
18
  double x = exp(exp_real) * cos(exp_img); // lage des pols in der z-ebene
19
  double y = exp(exp_real) * sin(exp_img);
20

21
  // zähler
22
  double b0 = 0;
23
  double b1 = 1;
24
  double b2 = -1;
25
  // nenner
26
  double a0 = 1;
27
  double a1 = -2 * x;
28
  double a2 = x * x + y * y;
29

30
  double val0 = 0, val1 = 0, val2 = 0;
31
  double time = 0;
32
  for (unsigned i = 0; i < 1000; ++i)
33
  {
34
    double newval = sin(time * w0);
35
    time += 1 / samplerate;
36
    val2 = val1;
37
    val1 = val0;
38
    val0 = newval + b1 * val1 + b2 * val2;
39

40
    double out = a0 * val0 + a1 * val1 + a2 * val2;
41

42
    std::cout << "in = " << newval << std::endl;
43
    std::cout << "out = " << out << std::endl;
44
  }
45
}

Die Idee war dass ich ein Sinussignal auf den Eingang gebe, welches 
exakt die Resonanzfrequenz des Filters hat. An sich sollte der Filter 
langsam anfangen zu schwingen und am Schluss identisch zum Signal 
aussehen. Leider nimmt der Filter aber werte größer als 1 an, was bei 
diesem Eingangssignal nicht möglich ist. Daher scheine ich wohl irgentwo 
ein Fehler zu haben :(

Die Filterkoeffizienten sind:
1
b0 = 0
2
b1 = 1
3
b2 = -1
4
a0 = 1
5
a1 = -1.5688869346931174
6
a2 = 0.93910136742429273

Grüße,
Resonanzkatastrophe

Quellen:
[1] 
http://www.dummies.com/how-to/content/working-across-domains-example-take-the-rc-lowpass.html
[2] 
http://de.wikipedia.org/wiki/Filter_mit_unendlicher_Impulsantwort#Direkt-Form_2_.28DF2.29
Gast
Ich habe deine Übertragungsfunktion nur mal kurz durch Matlab gejagt. 
Deine Filterkoeffizienten stimmen auf jeden Fall, der Frequenzgang hat 
auch die gewollte Spitze bei 100Hz und zeigt das von dir erwartete 
Verhalten.

Das Problem ist, dass du deinen Filter noch auf eine bestimmte 
Verstärkung normieren musst. Das wird in deinem Link [1] auch unter 
"Fine-tune the design for implementation" erklärt.

In deinem Fall wäre es wohl am Einfachsten sich die Verstärkung im 
kontinuierlichen Filter bei der Resonanzfrequenz und im diskreten Filter 
bei der Resonanzfrequenz anzuschauen und dann den Gainfactor 
entsprechend zu wählen, dass es passt.
Gast
Hallo abcd

Du hast Recht, der Verstärkungsfaktor fehlt tatsächlich. Aber auch nach 
einfügen selbigens hatte der Filter ein komisches Verhalten, die 
eigentliche Ursache war im Code. Die Filterkoeffizienten waren 
vertauscht.

vorher:
1
val2 = val1;
2
val1 = val0;
3
val0 = newval + b1 * val1 + b2 * val2;
4

5
double out = a0 * val0 + a1 * val1 + a2 * val2;

nachher:
1
val2 = val1;
2
val1 = val0;
3
val0 = newval - a1 * val1 - a2 * val2;
4

5
double out = (b0 * val0 + b1 * val1 + b2 * val2) / scale;

Zum einen waren nenner und zählerkoeffizienten falsch und zum anderen 
muss ich subtrahieren statt addieren. So funktioniert der Filter wie 
gewünscht, nur weiß ich leider nicht warum das sorum sein muss. Bei der 
Abbildung auf Wikipedia waren die koeffizienten schließlich anders rum.

Viele Grüße,
Resonanzkatastrophe
Gast
Resonanzkatastrophe schrieb:
> Bei der
> Abbildung auf Wikipedia waren die koeffizienten schließlich anders rum

In der Literatur ist man sich uneins, ob b die Zähler- und a die 
Nenner-Koeffizienten oder andersrum sind.

Bei dem Wikipedia-Artikel haben sie bei den Gleichungen b im Zähler so 
wie du, aber mit den Bildern waren sie dann ein bisschen inkonsequent:

Ersteres erklärt dein Vertauschen der Koeffizienten, zweiteres das 
nötige Subtrahieren.

Antwort schreiben

Eine eigene Frage? Dieser Thread ist über 12 Jahre alt. Stell sie in einem eigenen Thread – dort lesen mehr Leute mit, und sie wird öfter und schneller beantwortet.

Neuen Thread starten

Eine Lösung, Ergänzung oder Rückmeldung zu diesem Thread? Dann antworte hier.

Formatierung
  • [c]C-Code[/c]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] – Link zu einem Artikel
  • Verweis auf einen anderen Beitrag: Rechtsklick auf dessen Beitrags-ID (#8078628), „Adresse kopieren“, in den Text einfügen

Mehr zur Formatierung

Längeren Sourcecode als Anhang, nicht in den Text. JPG nur für Fotos und Scans; Zeichnungen und Screenshots als PNG oder GIF. Siehe Bildformate.

Schon registriert? Anmelden

Wird nicht angezeigt. Wir schicken dir einen Link; sobald du damit bestätigst, erscheint dein Beitrag.

Mit dem Abschicken legst du einen kostenlosen Account an und erkennst die Nutzungsbedingungen und die Datenschutzerklärung an.