mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik Goertzel auf ATMega1280: Seltsames Problem


Autor: Raphael (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi,

einige hier haben ja Erfahrung mit dem Goertzel-Algorithmus bzw. DTFM. 
Ich habe den Görtzel ähnlich dem Beispiel von Helmut Lenzen in folgendem 
Thread implementiert, um eine bestimmte Frequenz in einem Audiosignal zu 
detektieren (ATMega 1280):

Beitrag "Wo Welchen DTMF Decoder"
außerdem gut zur Auffrischung:
http://www.answers.com/topic/goertzel-algorithm

Leider habe ich jetzt das Problem, dass der Algorithmus nur für eine 
bestimmte Frequenz funktioniert, egal wie ich den Koeffizienten A setze. 
Das heißt, egal ob A 3 oder 7000 ist, ich bekomme immer nur für ca. 5,5 
kHz ein Maximum.
Sample-Frequenz ist konstant bei ca. 22038 Hz (16 Bit Timer1 triggert 
ADC-Wandlung, Algorithmus ist in der ADC-Interrupt-Routine).

Ich habe den Code mal genau so in MATLAB reingehauen, da funktioniert 
er. Es muss also irgendwas 8bit-µC-Spezifisches sein, aber ich komme 
gerade echt nicht dahinter - irgendwie verscheindet die Wirkung des 
Faktors A.

So sieht mein Code aus:

#define N  200  // goertzel filter length; frequency resolution B = Fs/N
#define A  54   // filter coefficient: 2*cos(4761Hz*2*pi/Fs)*128
                // scaled with 128

[..]

// goertzel algorithm in ADC conversion complete ISR
ISR(ADC_vect) {
  uint16_t adclval, adchval;

  //read 16bit ADC value
  adclval = ADCL;
  adchval = ADCH<<8;
  adcval = adclval | adchval;

  //goertzel
  if (filtidx == N)      // outer filter
  {
    filtidx = 0;

    v1 = v1/1024;        // scaling with 1024
    v2 = v2/1024;
    y = (v1*v2*A2)/2048; // scaling with 2048
    y = v1*v1 + v2*v2 - y;

    v1 = 0;
    v2 = 0;

  }
  else                  // inner filter
  {
    v0 = A2*v1/128;     // scaling with 128
    v0 = adcval + v0 - v2;
    v2 = v1;
    v1 = v0;
    filtidx++;
  }
}


Die ganzen Divisionen/Multiplikationen mit Zweierpotenzen im Code 
bewirken nur eine Abbildung auf einen Integer-Wertebereich, wobei sie 
teilweise recht willkürlich gewählt sind. Ich habe schon ziemlich viel 
mit den Skalierfaktoren herumgespielt, an denen liegt es nicht, würde 
ich behaupten. Lasse mich aber gerne eines Besseren belehren, jegliche 
Ideen sind willkommen.

Hat jemand einen Tipp?

Danke,
Grüße
Raphael

Autor: Christian H. (netzwanze) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Weil Du in Code A2 und nicht A verwendest?

Autor: mui (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
schreib mal deine variablen definitionen mit dazu...welchen wert haben 
v1 und v2 initial? es gibt ein define von A,du verwendest aber A2...und 
man muss das bestimmt nicht alles in der ISR machen...

Autor: Raphael S. (rs073)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi,

sorry, ich habe den Code etwas lesbarer gemacht und dabei Fehler 
reingebaut :( Natürlich liegts nicht an A bzw A2, im echten Code gibt es 
aber mehrere Ax.

Anfangs gilt v0 = v1 = v2 = filtidx = 0, das ist aber relativ egal, da 
die Variablen nach dem ersten Durchlauf eh Null gesetzt werden. Und 
grundsätzlich spuckt der Algorithmus ja erwartungsgemäß was aus, nur 
lässt sich die zu suchende Frequenz nicht über den Koeffizienten A 
einstellen. Edit: Hier noch die Variablendefinition:


uint16_t adcval;    // adc conversion result
int v0 = 0;         // goertzel filter variables
int v1 = 0;
int v2 = 0;
int filtidx = 0;    // current filter step
int y = 0;          // filter result (signal power)


Da es echt nur ein paar Berechnungen pro Durchlauf sind, spricht IMHO 
nichts gegen die Verwendung der Interruptroutine. Sollte aber auch 
nichts mit dem Fehler zu tun haben.

Hat noch jemand eine Idee?


Grüße&Danke
Raphael

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hast du mathematisch untersucht, welchen Einfluss das Downscaling hier

    v1 = v1/1024;        // scaling with 1024
    v2 = v2/1024;
    y = (v1*v2*A2)/2048; // scaling with 2048

auf das Ergebnis hat. Effektiv werden dir da wohl nur ein paar von den 
höherwertigen Bits aus v1 und v2 übrig bleiben. Du wirfst du ziemlich 
viel weg.

Autor: Raphael S. (rs073)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Jetzt funktionierts, es lag tatsächlich an den Skalierfaktoren, ich 
hatte die Wirkung von A zu stark unterdrückt, wie schon vermutet

Manchmal brauchts ne Weile, auch wenns so einfach ist...

Grüße und Danke
Raphael

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]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [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.