Forum: Digitale Signalverarbeitung / DSP / Machine Learning DTMF decoder


von Marcus (Gast)


Lesenswert?

Hat schon einmal jemand einen DTMF Decoder mit einer Atmega 
programmiert?
Mir scheint die Aufgabe sportlich interessant.

Als möglicher Ansatz sehe ich entweder

signal ==> mischer ==> LP ==> FFT 8 Werte

oder 8 einzelne Filter.

von Horst (Gast)


Lesenswert?

Marcus schrieb:
> oder 8 einzelne Filter.

oder einen MT8870

von Christoph db1uq K. (christoph_kessler)


Lesenswert?

Es gibt Applikationen von Analog Devices u.a. für Fixkomma-DSP und DTMF
Z.B. hier unter "Aplikace_1.pdf" ab Seite 471:
http://radio.feld.cvut.cz/courses/X37ASP/materialy.php
der Goertzel-Algorithmus ist anscheinend die übliche Methode

: Bearbeitet durch User
von Marcus (Gast)


Lesenswert?

>hier unter "Aplikace_1.pdf" ab Seite 471:

Uhh... und das wo mein Tschechisch so schlecht ist ... ich glaub, ich 
kann gar keins ;-)

Aber Scherz bei Seite. Es ist zwar für einen echten DSP ( ADSP21xx, 
24Bit MAC, bis 160MHz ) was eine ganz anderen 
Signalverarbeitungsleistungsklasse als einem Atmega entspricht, aber 
vielleicht lässt sich ja der Algorithmus auf einen AVR quetschen.

Hier gibt es zumindest ein Goerzel Beispiel:
https://github.com/jacobrosenthal/Goertzel/blob/master/Goertzel.cpp

Vielleicht lässt sich das bezüglich der Geschwindigkeit noch etwas 
optimieren ...

von Marcus (Gast)


Lesenswert?

Bisher dachte ich immer, der Goertzel Algorithums braucht mehr als eine 
Multiplikation. Aber dieser Code braucht pro Schritt nur eine:

https://github.com/jacobrosenthal/Goertzel/blob/master/Goertzel.cpp

Jetzt sehe ich auch warum:
https://www.dsprelated.com/showarticle/495.php

Die Berechnung der Amplitude ( Figure 3 ) muss man nicht für jedes 
Sample machen.

von Daniel T. (Gast)


Lesenswert?

Ich hatte mal einen Test mit einem ATMega168 gemacht:

   8 Frequenzen
8000 Samples pro Sekunde (12Bit je Sample)
  50 Durchgänge pro Sekunde (also 160 Samples je Durchgang)

Die Kernroutine ("int32_t = int32_t * uint16_t / 65535") war in 
Assembler, der Rest in GCC. Ich kam auf rund 6 Millionen Takte pro 
Sekunde. Also Kinderkram für einen ATMega. :-)

Aber selbst mit einem ATTiny@1MHz scheint das (ohne Goertzel!) zu gehen:

http://www.elo-web.de/elo/mikrocontroller-und-programmierung/avr-anwendungen/dtmf-decoder

von Holger Z. (boomboommagic)


Lesenswert?

Vor langer Zeit mit einer simplen Picaxe realisiert.

http://www.zierath-software.de/picaxe/beispiele/dtmf.html

von Bernd K. (prof7bit)


Lesenswert?

Holger Z. schrieb:
> Vor langer Zeit mit einer simplen Picaxe realisiert.
>
> http://www.zierath-software.de/picaxe/beispiele/dtmf.html

Das ist geschummelt, so kann das jeder.

von Marcus (Gast)


Lesenswert?

Marcus schrieb
>>Hat schon einmal jemand einen DTMF Decoder mit einer Atmega
>>programmiert?
Autor: Horst (Gast)
>oder einen MT8870

Eigentlich dachte ich, meine Frage sei relativ eindeutig formuliert, 
aber scheinbar kann man die Frage auch anders verstehen, nachdem es 
jetzt schon zwei solche Antworten gab.

Deshalb versuche ich das jetzt mal zu präzisieren: Es soll ein DTMF 
Dekoder im Atmega implementiert werden, also die 
Signalverarbeitungsalgorithmen in Software. Das Anschließen eines 
externen Hardware DTMF Dekoders war nicht die Frage.

von Marcus (Gast)


Lesenswert?

>Aber selbst mit einem ATTiny@1MHz scheint das (ohne Goertzel!) zu gehen:
>http://www.elo-web.de/elo/mikrocontroller-und-prog...

Aus der Überschrift:
 ohne FFT und Goertzel-Algorithmus!
- Analyse der Interferenzmuster
- 16-bit Frequenzzähler

Witzige Idee, ganz auf die Frequenzanalyse zu verzichten. Ich vermute 
aber mal, dass das Verfahren im Punkt Störanfälligkeit nicht ganz mit 
der Frequenzanalyse mithalten kann.

>Ich hatte mal einen Test mit einem ATMega168 gemacht:
>
>   8 Frequenzen
>8000 Samples pro Sekunde (12Bit je Sample)
>  50 Durchgänge pro Sekunde (also 160 Samples je Durchgang)

>Die Kernroutine ("int32_t = int32_t * uint16_t / 65535") war in
>Assembler, der Rest in GCC. Ich kam auf rund 6 Millionen Takte pro
>Sekunde. Also Kinderkram für einen ATMega. :-)

Heißt das 37%@16Mhz Auslastung?
Klingt gut. Vielleicht könnte man auch auf Assembler verzichten.

von Bernd K. (prof7bit)


Lesenswert?

Vielleicht gehts auch mit 4 IIR Bandpässen?

von Fin (Gast)


Lesenswert?

Bernd K. schrieb:

> Vielleicht gehts auch mit 4 IIR Bandpässen?

Wie stellst du dir das vor?

von Klaus (Gast)


Lesenswert?

Marcus schrieb:
> Ich vermute
> aber mal, dass das Verfahren im Punkt Störanfälligkeit nicht ganz mit
> der Frequenzanalyse mithalten kann.

Aus dem Text geht hervor, daß der Algorithmus 500ms braucht, ein DTMF 
Zeichen zu erkennen. Die minimale Länge eines Zeichens ist aber ca. 50ms 
mit einer Pause von ebenfalls 50ms (10 Zeichen pro Sekunde). Er 
funktioniert also nicht bei automatischer Wahl.

MfG Klaus

von Daniel T. (Gast)


Lesenswert?

Marcus schrieb:
> Heißt das 37%@16Mhz Auslastung?
Ja.

Marcus schrieb:
> Vielleicht könnte man auch auf Assembler verzichten.
Sicherlich. Es gäbe auch noch Optimierungsmöglichkeiten. Zum Beispiel 
könnte man statt 32 Bit nur 16 Bit für die Goertzel-Berechnung 
verwenden. Aber wozu?

von Marcus (Gast)


Lesenswert?

Könntest Du Deine Multiplikation hier posten? Das wäre nicht schlecht 
und ich könnte es mal ausprobieren.

von Bernd K. (prof7bit)


Lesenswert?

Fin schrieb:
> Bernd K. schrieb:
>
>> Vielleicht gehts auch mit 4 IIR Bandpässen?
>
> Wie stellst du dir das vor?

Naja, vier Bandpässe halt für die 4 Frequenzen und dann schaun hinter 
welchen beiden die Amplitude am höchsten (und ausreichend höher als 
hinter den anderen beiden) ist.

: Bearbeitet durch User
von Dieter F. (Gast)


Lesenswert?

Marcus schrieb:
> Eigentlich dachte ich, meine Frage sei relativ eindeutig formuliert,
> aber scheinbar kann man die Frage auch anders verstehen, nachdem es
> jetzt schon zwei solche Antworten gab.
>
> Deshalb versuche ich das jetzt mal zu präzisieren: Es soll ein DTMF
> Dekoder im Atmega implementiert werden, also die
> Signalverarbeitungsalgorithmen in Software. Das Anschließen eines
> externen Hardware DTMF Dekoders war nicht die Frage.

Ja dann mach doch und zeig mal, was herausgekommen ist :-)

von Dieter F. (Gast)


Lesenswert?

Marcus schrieb:
> Als möglicher Ansatz sehe ich entweder
>
> signal ==> mischer ==> LP ==> FFT 8 Werte
>
> oder 8 einzelne Filter

Na, dann teste da mal aus und berichte bitte über dié Ergebnisse.

von Bernd K. (prof7bit)


Lesenswert?

Oh, ich hab da was verwechselt, sind ja 8 und nicht 4 Frequenzen. Also 8 
Bandpässe. Wird eng, aber der Atmega kann doch immerhin 8*8 
Multiplikation in Hardware, vielleicht gehts ja doch.

von Marcus (Gast)


Lesenswert?

>Oh, ich hab da was verwechselt, sind ja 8 und nicht 4 Frequenzen.

Wenn man die Tasten A,B,C,D nicht braucht ( die gäbe es auf dem Telefon 
ja auch nicht), sind es nur 7 Frequenzen.

https://en.wikipedia.org/wiki/Dual-tone_multi-frequency_signaling#/media/File:DTMF_keypad_layout.svg

von Michael K. (Gast)


Lesenswert?


von Gustl B. (-gb-)


Lesenswert?

Wenn man den Rufnummernbereich etwas einschränkt kommt man sogar mit 
noch weniger Tönen aus. Man könnte nur 110 und 112 erlauben oder so.

von Bernd K. (prof7bit)


Lesenswert?

Ich hab noch ne Idee:

Es ist ja so daß wenn ich mich für eine Frequenz f interessiere und dann 
exakt mit 4f sample, also 4 Samples pro Periode dann kann ich fast ohne 
nennenswerten Aufwand einen extrem schmalbandigen IIR Bandpass für f 
bauen (die 4 Samples nennen wir mal q, i, q', i', und dann rechnen wir 
einmal

Q = q - q'

und

I = i - i'

I und Q filtern wir jeweils mit einem simplen IIR Tiefpass und der 
Betrag dieses Vektors ist die Amplitude von f.

Oder mit anderen Worten: wir haben einen I-Q-Direktmischer gebaut und es 
direkt ins Basisband (0Hz, Gleichspannung) runtergemischt und dort mit 
einem Tiefpass gefiltert.

Soweit so gut.

Wenn wir jetzt aber den ADC des ATmega bis an die Schmerzgrenze 
übertakten und sagen wir mal mit 50kS/s samplen und dann für jede 
einzelne der 8 Frequenzen einzeln knallhart per nearest neighbor auf 
jeweils 4f resamplen und jeweils nach 4 Samples für die jeweilige 
Frequenz die obige Rechnung anwenden dann haben wir nach ein paar 
Millisekunden für alle 8 Frequenzen jeweils I und Q und können deren 
Amplitude ausrechnen (oder das Quadrat der Amplitude wenn wir keine 
Wurzel ziehen wollen).

Das müsste der ATmega noch mitmachen sag ich mal aus dem Bauch raus, bei 
50kS/s hätten wir noch 320 Takte pro Sample, man muss die Rechnung ja 
auch nicht im IRQ machen sondern kann das auch für die Abarbeitung in 
der main einreihen weil ja oft mehr als einer (und alle Schaltjahre auch 
mal alle 8) gleichzeitig auf einen einzigen Samplezeitpunkt fallen 
könnten.

Wir bekommen durch das krude krumme Dezimieren zwar einen immensen 
Jitter auf die einzelnen Sampleraten aber wir können die Tiefpässe für 
die ganzen I und Q Werte ja so lang machen bis das nicht mehr stört.

Und wenn noch Luft ist und der ADC das mitmacht kann man evtl auch noch 
höher gehen mit der Samplerate, je höher desto weniger Jitter.

: Bearbeitet durch User
von Dergute W. (derguteweka)


Lesenswert?

Moin,


> Mir scheint die Aufgabe sportlich interessant.
Frisch auf - ans Werk ;-)

> Als möglicher Ansatz sehe ich entweder
>
> signal ==> mischer ==> LP ==> FFT 8 Werte
Ich fuercht' mal, durchs Runtermischen gewinnt man nicht viel, die 
Filter werden dann nur "langsamer" aber insgesamt ist glaub' ich die 
Bandbreite doch nicht so schmal, dass runtermischen mehr spart als es 
kostet.

> oder 8 einzelne Filter.
Da bin ich mir ziemlich sicher, dass das mit einem 8fach Goertzel gut 
machbar ist. Wenn man's nicht gerade in Java oder Basic programmiert.

Vermutlich wirds gut sein, wenn der 2*cos(bla) Faktor beim Goertzel 
moeglichst klein ist, d.h. - da die Signale im Frequenzband 697-1633Hz 
liegen, waere da die Mitte bei 1165Hz. Davon das 4fache waere dann eine 
"schoene" Samplingfrequenz - also 4.66KHz. Hm - da wird ein analoges 
Antialiasingfilter, das noch 1633Hz durchlaesst, aber ab 2.33kHz 
ordentlich daempft, schon etwas bloed.
Koennte man sich ueberlegen, mit dem AVR dann mit zB. ca. 9.32kHz oder 
ca. 13.98kHz abzutasten und schonmal vor der ganzen Goertzelei 
entsprechend zu dezimieren. Damit muesste mein analoger Tiefpass noch 
1633Hz durchlassen und kurz vor 7Khz dann ordentlich sperren -das sind 
dann gut 2 Oktaven - Naja, koennte grad' so klappen.

Wenn der AVR mit 16MHz laeuft; dann haett' ich also zwischen 2 Samples 
ueber 16e6/14e3=1143 Takte Zeit. Wenn ich fuer mein 3:1 
Dezimationsfilter dann die Haelfte der Zyklen vertroedeln wuerde; haett 
ich also fuer die 8 Goertzels immernoch 1143/2*3, also ueber 1700 Takte 
- also pro Goertzel pro Sample ueber 200 Takte.
Davon wuerd' ich jetzt 190 Takte hernehmen, um die Multiplikation und 2 
Additionen und das Sampleschieben zu machen; die anderen 10 Takte spar' 
ich mir, um dann jeweils nach vielleicht 64 Goertzeln mir die 
Momentanleistung im entsprechenden Kanal zu berechnen - das sind dann ja 
nochmal 4 Multiplikationen und 2 Additionen.
Dann bin ich auch schon fast durch - muss halt die 8 Werte fuer die 
Leistung im entsprechenden Frequenzband noch auswerten -ob da jetzt was 
gehupt hat oder nicht...

Also ich sag': Das geht.

Gruss
WK

von J. S. (engineer) Benutzerseite


Lesenswert?

Ich hätte spontan auch gesagt, das es geht, zumal ich DSP-mässig auch 
schon Ähnliches hingebaut habe. Aber, in der Praxis sind weitere Punkte 
zu beachten:

1) Das Signal ist meistens real ziemlich verdreckt, wenn es gesampelt 
wurde und das kummuliert mit den einkalkulierten Fehlern einer 
vereinfachten Prozessierung. Am Ende hat man Fehlerkennung ohne Ende.

2) Prozessoren haben meist noch andere Dinge zu tun und es ist selten 
so, dass man einen spendiert, für nur eine solche Aufgabe. Das wäre 
ineffektiv. Daher muss man genau rechnen, was der wirklich erübrigen 
kann. Solche Sachen sind gfs in einem PLD besser aufgehoben.

von Daniel T. (Gast)


Lesenswert?

Ohne Assembler braucht man etwa doppelt soviel CPU-Leistung (12MHz). Der 
unten stehende Code ist ein von mir verworfener Testcode, da ich die 
Tastencodes letztendlich digital (DTMF-Datentyp beim SIP) auslesen 
konnte. Der Code ist also weder mathematisch noch programmtechnisch 
sauber bzw. fehlerfrei. Ich habe mal beispielhaft Testdaten per 
'cos(2*...' erzeugt und das Ergebnis hier angehängt. Die eigentlichen 
Tasten müssten natürlich noch aus Amp[] dekodiert werden (den Code dazu 
konnte ich aber nicht mehr finden).

Der Code funktionierte zwar 1a auch mit realen Telefonatmitschnitten, 
aber der Spezialbaustein MT8870 ist perfekt und kostet keinen Euro.
1
#include <avr/io.h>
2
#include <math.h>
3
4
int32_t MulAndDiv65536(int32_t v32, uint16_t v16)
5
{
6
  uint32_t t0 = ((((uint32_t)v32&0xffff)*v16)+0x8000)>>16;
7
  int32_t t1 = (v32>>16)*v16;
8
  return t1+t0;
9
}
10
11
int16_t GoertzelFilter(int16_t* DataArr, int16_t DataCnt, uint16_t Coeff)
12
{
13
  int32_t tmp;
14
  int32_t v1 = 0;
15
  int32_t v2 = 0;
16
  for(uint8_t i=0; i<DataCnt; i++)
17
  {
18
    tmp = MulAndDiv65536(v1<<1, Coeff) - v2 + DataArr[i];
19
    v2 = v1;
20
    v1 = tmp;
21
  }
22
  v1 >>= 9; // Überlauf verhindern für -511<=DataArr[i]<=+511)
23
  v2 >>= 9; // Überlauf verhindern für -511<=DataArr[i]<=+511)
24
  tmp = MulAndDiv65536(v1<<1, Coeff);
25
  tmp = tmp*v2;
26
  tmp = v1*v1+v2*v2-tmp;
27
  return tmp;
28
}
29
30
int main()
31
{ 
32
  // 
33
  // Koeffizienten für DTMF-Frequenzen bei 8000Hz Sample-Frequenz
34
  //
35
  // - Berechnet aus:
36
  //   Coeff[iCoeff] = cos(2*pi*F(iCoeff)/fSample)*65536
37
  //
38
  const uint16_t CoeffArr[] =
39
  {
40
    55959, //  697 Hz (= cos(2*pi*697/8000)*65536)
41
    53912, //  770 Hz ...
42
    51402, //  852 Hz
43
    48437, //  941 Hz
44
    38145, // 1209 Hz
45
    32649, // 1336 Hz
46
    26169, // 1477 Hz
47
    18629  // 1633 Hz
48
  };
49
  const int CoeffCnt = sizeof(CoeffArr)/sizeof(*CoeffArr);
50
  
51
  for(int f=650; f<1700; f+=10)
52
  {
53
    const uint8_t Cnt = 160; // 20ms lange Blöcke
54
    const short fSample = 8000;
55
    int16_t q[Cnt];
56
    for(int i=0; i<Cnt; i++)
57
    {
58
      int16_t Sample = (int16_t)(cos(2*4*atan(1.0)*f*i/fSample)*511); // +-511
59
      q[i] = Sample;
60
    }
61
    int Amp[CoeffCnt];
62
    printf("%5i Hz ", f);
63
    for(int iCoeff=0; iCoeff<CoeffCnt; iCoeff++)
64
    {
65
      Amp[iCoeff] = GoertzelFilter(q, Cnt, CoeffArr[iCoeff]);
66
      printf("%5i ", Amp[iCoeff]);
67
    }
68
    printf("\n");
69
  }
70
  return 0;
71
}

Ausgabe:

     650 Hz    25   108     1     7     3     3     1     1
     660 Hz   607    48     8    22     1     4     1     1
     670 Hz  2241     0    49    22     7     4     0     1
     680 Hz  4429    64    66    16    12     3     0     1
     690 Hz  6041   208    34     2     9     0     1     0
     700 Hz  6300   320     1    13     3     3     4     1
     710 Hz  5057   169    13    32     1     4     1     1
     720 Hz  2955     0    82    33     7     4     0     1
     730 Hz  1051   361   130    24    12     3     1     1
     740 Hz   164  1566    61     2     9     0     1     0
     750 Hz    22  3672     4    14     3     3     4     1
     760 Hz   241  5545    42    44     1     4     3     1
     770 Hz   281  6328   206    69     7     4     0     1
     780 Hz   151  5476   328    39    19     3     1     1
     790 Hz    29  3743   231     2     9     0     1     0
     800 Hz     8  1542     9    30     3     3     4     1
     810 Hz    61   341   217    74     1     4     3     1
     820 Hz    92     1  1324   106     9     4     0     1
     830 Hz    52   144  3325    64    19     3     1     1
     840 Hz    10   289  5301     2    16     0     1     0
     850 Hz     4   216  6420    55     3     3     4     1
     860 Hz    33    65  5949   201     1     4     3     1
     870 Hz    48     0  4020   298    13     7     0     1
     880 Hz    28    49  1920   213    27     3     1     1
     890 Hz     5   117   487     6    16     0     1     0
     900 Hz     1    76     9   259     7     7     4     1
     910 Hz    22    24   121  1419     1     9     3     4
     920 Hz    31     0   276  3421    12     7     0     1
     930 Hz    13    25   208  5497    22     3     1     1
     940 Hz     4    62    91  6438    25     0     1     0
     950 Hz     1    40     4  5665     7     7     4     3
     960 Hz    14    12    36  3919     1     9     3     4
     970 Hz    20     0    84  1836    12     7     1     3
     980 Hz    11     9    85   394    40     3     1     1
     990 Hz     1    34    43     3    36     0     1     0
    1000 Hz     1    28     1   134     7     7     9     3
    1010 Hz     9    10    23   289     1    16     3     4
    1020 Hz    17     0    45   235    20    13     1     3
    1030 Hz     4     9    36    61    54     7     1     1
    1040 Hz     1    24    15     1    57     1     4     0
    1050 Hz     0    15     0    36    19    12     9     3
    1060 Hz     9     4    15   100     1    25     7     4
    1070 Hz    10     0    25    88    42    19     1     3
    1080 Hz     4     4    21    28   116     7     1     1
    1090 Hz     1    15    14     0   111     1     4     0
    1100 Hz     0    13     0    16    40    19     9     3
    1110 Hz     9     3     8    57     1    31     7     4
    1120 Hz     9     0    22    43    91    19     1     3
    1130 Hz     3     4    10    15   264     7     1     1
    1140 Hz     0    15     8     1   307     1     4     0
    1150 Hz     0     6     0    11   134    28    16     3
    1160 Hz     4     3     8    31     3    57    12     9
    1170 Hz     9     0    13    21   457    48     1     3
    1180 Hz     3     4     9     6  1884    13     1     1
    1190 Hz     1     8     4     1  3860     3     9     0
    1200 Hz     0     6     0     9  5755    52    22     6
    1210 Hz     4     2     4    21  6372   103    17     9
    1220 Hz     4     0    11    21  5325    91     4     3
    1230 Hz     2     4     7     2  3323    21     1     1
    1240 Hz     1     8     4     1  1413     7     9     1
    1250 Hz     0     5     0     9   289   117    32     6
    1260 Hz     4     2     4    13     4   268    26     7
    1270 Hz     4     0     5    14   168   273     4     7
    1280 Hz     2     1     3     4   269    81     1     4
    1290 Hz     1     8     1     1   211    37    16     1
    1300 Hz     0     5     0     4    52   703    44    10
    1310 Hz     4     2     4    13     1  2383    46    13
    1320 Hz     8     0     5     7    46  4519     9    10
    1330 Hz     2     1     3     1    86  6169     4     4
    1340 Hz     1     8     1     1    73  6364    36     1
    1350 Hz     0     5     0     4    19  4869    88    12
    1360 Hz     4     2     4    13     1  2793    89    21
    1370 Hz     4     0     9     7    24  1008    25    10
    1380 Hz     0     1     3     1    41    91     7     4
    1390 Hz     0     8     1     1    43    48   109     1
    1400 Hz     0     2     0     2    12   228   249    24
    1410 Hz     4     0     4     7     0   283   288    34
    1420 Hz     4     0     4     7    10   156    91    16
    1430 Hz     1     1     2     1    22    21    28     4
    1440 Hz     0     4     0     1    25    12   569     4
    1450 Hz     0     2     0     2     7    73  2149    35
    1460 Hz     4     0     4     7     0   112  4288    46
    1470 Hz     4     0     4     7    10    67  5965    34
    1480 Hz     1     1     2     1    19     7  6328     4
    1490 Hz     0     4     0     1    16     7  5195     8
    1500 Hz     0     4     0     2     3    36  3060    61
    1510 Hz     4     0     1     7     0    63  1137    96
    1520 Hz     4     0     4     4     7    31   177    72
    1530 Hz     1     1     2     0    13     3    24     9
    1540 Hz     0     4     1     1     9     7   253    23
    1550 Hz     0     4     0     2     3    25   307   161
    1560 Hz     4     0     1     7     0    37   173   301
    1570 Hz     4     0     4     4     7    21    39   211
    1580 Hz     1     1     2     1     7     3     7    19
    1590 Hz     0     4     1     1     9     3    71   134
    1600 Hz     0     4     0     2     3    16   119  1100
    1610 Hz     4     0     1     7     0    28    65  2937
    1620 Hz     4     0     4     4     3    16    21  5035
    1630 Hz     1     1     0     1     7     1     3  6277
    1640 Hz     0     4     1     1     9     3    42  6132
    1650 Hz     0     4     0     2     3    13    56  4345
    1660 Hz     4     0     1     7     0    19    37  2164
    1670 Hz     4     0     1     4     3     9     7   640
    1680 Hz     1     1     0     1     4     1     1    24
    1690 Hz     0     4     1     1     4     3    30   113

von Marcus (Gast)


Lesenswert?

Hallo Daniel,

vielen Dank für das Codebeispiel. Interessant ist Deine Multiplikation. 
Aus Deinem vorigen Post habe ich entnommen, dass die Multiplikation in 
Assembler geschrieben ist. Macht der GCC die Optimierung automatisch? 
Würde es etwas bringen, "inline" davor zu schreiben?

>Der Code funktionierte zwar 1a auch mit realen Telefonatmitschnitten,
>aber der Spezialbaustein MT8870 ist perfekt und kostet keinen Euro.

Bei mir ist diese Aufgabenstellung reiner Spieltrieb. Ich habe 
eigentlich gar keine richtige Anwendung, experimentiere aber gerne mit 
Signalverarbeitungsproblemen. Von daher ist die Performance für mich 
erst mal zweitrangig.

von Daniel T. (Gast)


Angehängte Dateien:

Lesenswert?

Die Multiplikation in meinem Post ist nicht in Assembler sondern in C 
geschrieben. Deswegen sind auch 12MHz nötig. Der Compiler fügt diese 
zwar automatisch inline ein, es bringt aber nicht sehr viel. Erst mit 
der (hoffentlich) äquivalenten Assembler-Multiplikation aus dem Anhang 
werden es 6MHz.

von Marcus (Gast)


Lesenswert?

Hallo Daniel,

danke für den Code. Mir war gar nicht bewusst, dass man für die 32Bit 
Multiplikation so viele Befehle braucht ( 41, wenn ich mich nicht 
verzählt habe ).

Irgendwann habe ich mal einen Arduuino DUE ( ARM Cortex M3, 84Mhz ) 
gegen einen AVR 16Mhz getestet. Ich hätte da erwartet, dass die 
Geschwindigkeit mindestens um den Faktor 10 höher ist. Aber im Schnitt 
lag es eher bei Faktor 4..5. Bei der Signalverarbeitung könnte der ARM 
hier dank der längeren Wortbreite aber vielleicht doch eine deutlich 
höhere Geschwindigkeit erreichen.

Vor längerer Zeit habe ich auch mal AVR-Assembler in C eingebunden. Die 
Schwierigkeit dort war, herauszufinden, welche Register von C reserviert 
werden und welche man auf vorher auf den Stack retten muss.
Es gibt auch eine Möglichkeit, den Assembler-Code direkt ins C-File 
aufzunehmen, so dass man kein extra *.s File braucht.

von Harald W. (wilhelms)


Lesenswert?

Marcus schrieb:

> Deshalb versuche ich das jetzt mal zu präzisieren: Es soll ein DTMF
> Dekoder im Atmega implementiert werden, also die
> Signalverarbeitungsalgorithmen in Software. Das Anschließen eines
> externen Hardware DTMF Dekoders war nicht die Frage.

Aha, also eine Schulaufgabe, die Du nicht selber lösen willst,
sondern von anderen gelöst bekommen möchtest?

von Sascha (Gast)


Lesenswert?

Es muss wohl sehr einfach gehen einen DTMF Signal auszuwerten.
Sonst wär das in den 70er Jahren nicht gegangen.
Ich habe da schon ein paar abhandlungen gelesen, die aus der 
Telekommunikation kamen.
Ich habe auch schon görtzel umgesetzt, ist aber nicht immer die optimale 
Lösung. Man braucht dahinter noch eine Kreuzkorrelation. Auch FFT ist ja 
letztendlich auch nichts anderes.
Der Trick mit dem Interreferenz-Muster muss doch sehr gut gehen. Das 
wurde anscheinend in den meisten Chips angewandt.
An diesem Thema bin ich auch noch interessiert eine einfache Lösung zu 
finden.

Gruß Sascha

von Schreiber (Gast)


Lesenswert?

Sascha schrieb:
> Es muss wohl sehr einfach gehen einen DTMF Signal auszuwerten.
> Sonst wär das in den 70er Jahren nicht gegangen.

Das ist auch einfach, sofern man es analog macht. Für "faule" 
Zeitgenossen gab (und gibt) es spezielle Decoder-ICs, damit man kein 
Transistorgrab bauen muss.

Hier ist die Zielsetzung allerdings das ganze auf einem lahmen µC per 
Software zu erledigen.

von Marcus (Gast)


Lesenswert?

Autor: Sascha (Gast)
>Ich habe auch schon görtzel umgesetzt, ist aber nicht immer die optimale
>Lösung. Man braucht dahinter noch eine Kreuzkorrelation.

Wieso Kreuzkorrelation? Der Code von Daniel oben benutzt den Görzel 
Algorithmus. Das sogar mit nur einer Multiplikation pro Filter und 
Sample bis auf den letzten Sample mit der Betragsbildung.
Das Ganze ist hier graphisch gezeichnet ( Figure 3 ):
https://www.dsprelated.com/showarticle/495.php

von Dieter F. (Gast)


Lesenswert?

Marcus schrieb:
> Das Ganze ist hier graphisch gezeichnet ( Figure 3 ):

Gibt es hier jemanden der google nicht kennt? Warum legst Du nicht mal 
vor? hier sind viele gespannt auf Deine Lösung :-)

von Dergute W. (derguteweka)


Lesenswert?

Moin,

Harald W. schrieb:
> Aha, also eine Schulaufgabe, die Du nicht selber lösen willst,
> sondern von anderen gelöst bekommen möchtest?

Also wenns so waere, wuerd's mich doch interessieren, welcher 
Ausbilder/Uebungsleiter/Prof/Baumschulleerer sich das antut, dann die 
Loesungen zu bewerten ;-)

Ansonsten wuerd' ich in Anbetracht der umfangreichen 32x32bit 
Multiplikation stark dafuer plaedieren, in Assembler jeweils nur genau 
die Genauigkeit herzunehmen, die man tatsaechlich braucht. also z.b. nur 
eine 24x16bit Multiplikation oder sowas in der Art.
Muss man halt vorher mal sowas in einer Hochsprache mit floatingpoint 
aufm PC programmieren, dann sieht man schon, welche Wertebereiche 
tatsaechlich noetig werden.

Bei der engl. Wikipedia gibts unter Goertzel_Algorithm die Abteilung 
"Power-spectrum terms" mit abschreibfertigem Pseudocode fuer genau das, 
was hier eigentlich interessiert.

Gruss
WK

von Marcus (Gast)


Lesenswert?

>Ansonsten wuerd' ich in Anbetracht der umfangreichen 32x32bit
>Multiplikation stark dafuer plaedieren, in Assembler jeweils nur genau
>die Genauigkeit herzunehmen, die man tatsaechlich braucht.

Das hat Daniel in seiner Assemblerroutine gemacht, deshalb gewinnt er ja 
so einen großen Geschwindigkeitsvorteil:
Beitrag "Re: DTMF decoder"

Eine Idee wäre, ob der C-Compiler die Optimierung nicht auch schaffen 
könnte, wenn man ihm die richtige Hilfestellung gibt. Man könnte die 
Multiplikation eventuell in 16x16 Multiplikationen und Summen zerlegen 
und die 32=16x16 Multiplikation damit realisieren.

von Marcus (Gast)


Lesenswert?

Die Multiplikation aus Daniels C-Code
1
int32_t MulAndDiv65536(int32_t v32, uint16_t v16)
2
{
3
  uint32_t t0 = ((((uint32_t)v32&0xffff)*v16)+0x8000)>>16;
4
  int32_t t1 = (v32>>16)*v16;
5
  return t1+t0;
6
}

wird mit dem GCC ( -Os ) wird zu
1
{
2
0000024B  PUSH R4    Push register on stack 
3
0000024C  PUSH R5    Push register on stack 
4
0000024D  PUSH R6    Push register on stack 
5
0000024E  PUSH R7    Push register on stack 
6
0000024F  PUSH R8    Push register on stack 
7
00000250  PUSH R9    Push register on stack 
8
00000251  PUSH R10    Push register on stack 
9
00000252  PUSH R11    Push register on stack 
10
00000253  PUSH R12    Push register on stack 
11
00000254  PUSH R13    Push register on stack 
12
00000255  PUSH R14    Push register on stack 
13
00000256  PUSH R15    Push register on stack 
14
00000257  MOVW R4,R22    Copy register pair 
15
00000258  MOVW R6,R24    Copy register pair 
16
00000259  MOVW R8,R20    Copy register pair 
17
  uint32_t t0 = ((((uint32_t)v32&0xffff)*v16)+0x8000)>>16;
18
0000025A  MOVW R18,R22    Copy register pair 
19
0000025B  MOVW R20,R24    Copy register pair 
20
0000025C  CLR R20    Clear Register 
21
0000025D  CLR R21    Clear Register 
22
0000025E  MOV R10,R1    Copy register 
23
0000025F  MOV R11,R1    Copy register 
24
00000260  MOVW R24,R10    Copy register pair 
25
00000261  MOVW R22,R8    Copy register pair 
26
00000262  CALL 0x00000701    Call subroutine 
27
00000264  MOVW R12,R22    Copy register pair 
28
00000265  MOVW R14,R24    Copy register pair 
29
00000266  LDI R18,0x80    Load immediate 
30
00000267  ADD R13,R18    Add without carry 
31
00000268  ADC R14,R1    Add with carry 
32
00000269  ADC R15,R1    Add with carry 
33
0000026A  MOVW R12,R14    Copy register pair 
34
0000026B  CLR R14    Clear Register 
35
0000026C  CLR R15    Clear Register 
36
  int32_t t1 = (v32>>16)*v16;
37
0000026D  MOVW R18,R6    Copy register pair 
38
0000026E  CLR R21    Clear Register 
39
0000026F  SBRC R19,7    Skip if bit in register cleared 
40
00000270  COM R21    One's complement 
41
00000271  MOV R20,R21    Copy register 
42
00000272  MOVW R24,R10    Copy register pair 
43
00000273  MOVW R22,R8    Copy register pair 
44
00000274  CALL 0x00000701    Call subroutine 
45
  return t1+t0;
46
00000276  ADD R22,R12    Add without carry 
47
00000277  ADC R23,R13    Add with carry 
48
00000278  ADC R24,R14    Add with carry 
49
00000279  ADC R25,R15    Add with carry 
50
}
51
0000027A  POP R15    Pop register from stack 
52
0000027B  POP R14    Pop register from stack 
53
0000027C  POP R13    Pop register from stack 
54
0000027D  POP R12    Pop register from stack 
55
0000027E  POP R11    Pop register from stack 
56
0000027F  POP R10    Pop register from stack 
57
00000280  POP R9    Pop register from stack 
58
00000281  POP R8    Pop register from stack 
59
00000282  POP R7    Pop register from stack 
60
00000283  POP R6    Pop register from stack 
61
00000284  POP R5    Pop register from stack 
62
00000285  POP R4    Pop register from stack 
63
00000286  RET     Subroutine return

von Dergute W. (derguteweka)


Lesenswert?

Moin,

Die Frage ist erstmal: Welche Genauigkeit brauchts denn ueberhaupt? Was 
ist denn das Teilziel:
Gucken obs hupt. Oder nicht. Also Informationsgehalt 1bit - Die gesuchte 
Frequenz ist eben mit ausreichender Amplitude da oder nicht.

Das heisst doch: Bei der Berechnung der Leistung, wo's 3 
Multiplikationen braucht, interessiert mich am Schluss nur eine Info, 
die in 1bit passt. Da geh' ich doch mal davon aus, dass selbst wenn die 
einzelnen Produkte recht gross werden - also z.b. 32bit - ich lange 
nicht alle 32bit beruecksichtigen muss. Sondern mich von einer eventuell 
anstehenden 32x32bit Multiplikation eh' nur die hoechstwertigsten paar 
Bit interessieren, weil ich nur gucken will, obs hupt oder nicht. Also 
reichen mir doch da sicherlich jeweils 8x8 bit Multiplikationen.
Genauso bei den einzelnen Schritten vor der einmaligen 
Leistungsberechnung. Das wird wahrscheinlich drauf rauslaufen, dass man 
vielleicht 64x oder 128x vor sich hin goertzelt und danach die 
Leistungsberechnung vornimmt.
Also hab' ich 64 oder 128 Samples vorliegen, beim AVR bestenfalls mit 
10bit Aufloesung. Da kann ich mir gut vorstellen, dass da auch 8bit 
Aufloesung reichen. Mehr gibt ein Telefon eh' nicht her. Also wird's 
interessant, welchen Wertebereich die einzelnen s, sprev, und sprev2 so 
durchlaufen. Wahrscheinlich nicht die vollen 32bit, wahrscheinlich 
nichtmal die vollen 24bit - mit Glueck vielleicht nur 16bit? Muss man 
halt mal gucken. Und dann entsprechend die Laengen der "variablen" und 
der Berechnungen waehlen.
Dabei fuercht' ich, wird Zeugs rauskommen, was dem C-Compiler nicht mehr 
so leicht beizubringen ist - zumindest nicht mehr so, dass es sinnvoll 
ist in C zu programmieren...
Das sind halt diese Bereiche, wo man sagen muss: Da kann man mit 
handgedengeltem Assembler noch ordentlich was rausholen - es ist aber 
nicht mehr wirklich wirtschaftlich, sondern nur noch mit "Spass an der 
Freud'" zu rechtfertigen.

Gruss
WK

von Bernd K. (prof7bit)


Lesenswert?

Dergute W. schrieb:
> es ist aber
> nicht mehr wirklich wirtschaftlich

Es sei denn auf der Platine (und in der Marge) ist kein Platz um für 
jede einzelne Teilaufgabe einen separaten Chip zu spendieren wenn diese 
Aufgaben auch alle zusammen genauso gut (ausreichend gut) von einem 
einzigen kleinen µC erledigt werden könnten.

Und wenn man dafür in großen Mengen und in schneller Folge 16x16 Bit 
multiplizieren müsste wählt man halt aus der riesigen Zahl verfügbarer 
Controller einen aus der sowas aus dem Handgelenk macht und trotzdem 
nicht teurer ist als ein ATmega.

Unwirtschaftlich wird es nur wenn man auf Teufel komm raus einen ATMega 
dort einbauen will. Und noch unwirtschaftlicher wird es wenn der 
schweineteure ATmega dann 98% Däumchen dreht weil man dem altehrwürdigen 
Chip keine schweren Aufgaben mehr zumuten will und daher noch 
tonnenweise zusätzliches Zeug auf die Platine pflastern muss.

: Bearbeitet durch User
von Daniel T. (Gast)


Lesenswert?

Ursprünglich ging es doch um die Frage wie sportlich es sein könnte, 
einen DTMF-Decoder auf einen ATMega zu kodieren. Die Antwort ist ja 
beantwortet. Mit Goertzel gehts, wenn  man statt float integer 
verwendet. Und selbst mit einer (256 Punkt) FFT gehts 
(Beitrag "Schnelle FFT in Assembler"), wenn der ATMega genügend 
RAM Speicher hat. Wenn es aber um die Frage geht, wieviel CPU man 
mindestens braucht, dann hätte ich noch eine schmutzige Lösung 
anzubieten:

Man könnte die Fourier-Koeffizienten auch native (ohne Goertzel oder 
FFT) berechnen, wenn das Ergebnis auch 'etwas fehlerhafter' sein dürfte. 
Wenn ein paar Oberwellen zulässig sind, könnte man nämlich statt einer 
Summe aus Sinusprodukten eine Summe aus Rechteckprodukten bilden. Die 
gesamte Berechnung bestände dann nur noch aus zwei Summen ohne 
Multiplikation.

Im Ergebnis ergibt sich ziemlich das gleiche Spektrum wie ich es bereits 
in der Goerzel-Variante (siehe Post vom 13.12.2016 23:00) hatte. Der 
Unterschied ist jedoch, dass der Filter auch beim Dreifachen, 
Fünffachen, usw. der Grundfrequenz anspricht. Beispielsweise erhält man 
bei 2090Hz ein Ansprechen des 697 HZ Filters:

1
     650 Hz    45   149    50     7    65     7    22    59
2
     660 Hz   692    29    22    35    15     0     8     3
3
     670 Hz  1705    29    22    35     1     0     8     3
4
     680 Hz  4658    29   114     7     8     0    43     3
5
     690 Hz  6616   297    22    59     8     3     1     0
6
     700 Hz  8581   304     8     7    15     0    15     3
7
     710 Hz  5639   149     8    31    65     3    29    28
8
     720 Hz  3294     8   128    14    15     7     8     3
9
     730 Hz  1722   240   149     3    29     3    65     0
10
     740 Hz   228  1942    93    35    22   182     1    45
11
     750 Hz    45  3819    29    14    15     0     8     3
12
     760 Hz   284  5633    93    35     1     0    65     3
13
     770 Hz   312 10696   261    70     1     0    15     3
14
     780 Hz   203  5802   402    87     8     3    43    14
15
     790 Hz     0  3911   261     3     1     3     1    14
16
     800 Hz     3  2329    22    14     8    91     1     3
17
     810 Hz     3   747   149   140     1    14     1     3
18
...
19
    2030 Hz     3    22   240    14    93     7     1    17
20
    2040 Hz     3    86    93     0    22     0     1     3
21
    2050 Hz    17    15   107     7     1     7    43    87
22
    2060 Hz   158    22    65     0    43    63     1    17
23
    2070 Hz   597    22     8    17    15     3    43     7
24
    2080 Hz   597     8    15     3     8     3    15    28
25
    2090 Hz  1019    65     8     3     8     3    29     7
26
    2100 Hz   594     1     8     0     1    56    22    31
27
    2110 Hz   457    22     8     3    72    17     8    14
28
    2120 Hz    87     1     1     0    22     7    29   945
29
    2130 Hz    35     8    15     3   114     3     8   351
30
    2140 Hz     3     1    29     0    72     0     1     3


Ich habe diesen Filter anhand von einigen Stunden Musik als Testdaten 
untersucht. Überraschenderweise erhielt ich nicht mehr fehlerhafte 
DTMF-Werte als mit dem Goerzelfilter. Wenn man zusätzlich noch die 
Datentypen ausreizt, dann erhält man eine sehr schnelle Berechnung. Es 
reicht ein Controller ohne Hardware-Multiplikation. Der Code unten 
benötigt nur noch einen ATTiny mit etwa 1.5 MHz!

1
#include <avr/io.h>
2
#include <avr/pgmspace.h>
3
4
#define nBuff   (uint16_t)160 // 160 Samples pro Block -> 20ms
5
#define fSample (long)8000    // 8KHz
6
7
//##################################################### DTMF_CalcAmp
8
void DTMF_CalcAmp(int16_t* Arr, uint16_t* ResAmp)
9
{
10
  short Sum = 0;
11
  for(uint8_t i=0; i<nBuff; i++)
12
  {
13
    Sum += Arr[i];
14
    Arr[i] = Sum;
15
  }
16
  static const uint16_t StepArr[8] PROGMEM =
17
  {
18
    fSample*256/2/ 697, // für 697 Hz
19
    fSample*256/2/ 770, // ...
20
    fSample*256/2/ 852,
21
    fSample*256/2/ 941,
22
    fSample*256/2/1209,
23
    fSample*256/2/1336,
24
    fSample*256/2/1477,
25
    fSample*256/2/1633
26
  };
27
  const uint8_t StepCnt = sizeof(StepArr)/sizeof(*StepArr);
28
  for(uint8_t iCoeff=0; iCoeff<StepCnt; iCoeff++)
29
  {
30
    short Step = pgm_read_word(&StepArr[iCoeff]);
31
    short s = 0;
32
    short c = 0;
33
    {
34
      // "Sin-Summe der positiven Halbwellen"
35
      for(uint16_t p=0; p<nBuff*0x100; p+=Step)
36
      {
37
        s -= Arr[p>>8];
38
        p += Step;
39
        if(p>=nBuff*0x100) p=nBuff*0x100-1;
40
        s += Arr[p>>8];
41
      }
42
      s = Sum-s-s; // -> Sin-Summe beider Halbwellen
43
    }
44
    {
45
      // "Cos-Summe der positiven Halbwellen"
46
      for(uint16_t p=Step/2; p<nBuff*0x100; p+=Step)
47
      {
48
        c -= Arr[p>>8];
49
        p += Step;
50
        if(p>=nBuff*0x100) p=nBuff*0x100-1;
51
        c += Arr[p>>8];
52
      }
53
      c = Sum-c-c; // -> Cos-Summe beider Halbwellen
54
    }
55
    ResAmp[iCoeff] = (uint16_t)(((long)s*(long)s+(long)c*(long)c)>>15);
56
  }
57
}
58
59
//######################################################### main
60
int main(void)
61
{
62
  // 8KHz-Sample pro Sekunde mit 8 Bit Datengröße (Voip-Standard)
63
  for(int f=650; f<1700; f+=10)
64
  {
65
    int16_t Arr[nBuff];
66
    // Testdaten (8Bit/Sample und 8KHz) ablegen
67
    for(int i=0; i<nBuff; i++)
68
    {
69
      // Arr[i] = (int8_t)(cos(2*4*atan(1.0)*f*i/fSample)*120); // Sinus mit -128 bis +127 Amplitude
70
      Arr[i] = (int8_t)((((((long)2*  f*i)/fSample)&1)*2-1)*120); // Rechteck mit -128 bis +127 Amplitude
71
    }
72
    uint16_t Amp[8];
73
    DTMF_CalcAmp(Arr, Amp);
74
    printf("%8i Hz ", f);
75
    for(int iCoeff=0; iCoeff<8; iCoeff++)
76
    {
77
      printf("%5i ", Amp[iCoeff]);
78
    }
79
    printf("\n");
80
  }
81
  return 0;
82
}

von Daniel T. (Gast)


Lesenswert?

Korrektur:

Das Spektrum stimmt nicht. Ich hatte die falsche Zeile in main() 
einkommentiert und die Testdaten waren damit Rechteckdaten. Das Ergebnis 
sieht mit den Sinusdaten schöner aus:
1
     650 Hz    19    71     1     6     1     0    13     6
2
     660 Hz   449    44     3    12     1     0     1     6
3
     670 Hz  1532     0    23    13     7     1     4     1
4
     680 Hz  3039    42    33    10     9     0     7     2
5
     690 Hz  4214   125    19     0     2     0    16     2
6
     700 Hz  4445   175     3     8     6     0     7     0
7
     710 Hz  3660   110    10    18     6     0     1     0
8
     720 Hz  2167     0    65    20     0     1     3     0
9
     730 Hz   775   214    92    14     2     0     1     1
10
     740 Hz   105  1052    44     0     1     0    11     0
11
     750 Hz     9  2443     6    11     2     0    10     0
12
     760 Hz   134  3852    25    30     4     0     6     0
13
     770 Hz   230  4475   123    33     0     1    11     2
14
     780 Hz   162  4091   214    22     0     0     4     4
15
     790 Hz    33  2769   141     0     0     0     0     0
16
     800 Hz     3  1235    11    20     0     0     1     6
17
     810 Hz    48   270   118    58     0     1     0     9
18
...
19
    2030 Hz    17    30    79     0     3     1     6     8
20
    2040 Hz     2    13   103     0     3     1     9    10
21
    2050 Hz    27     8    57     0     6     3     4    14
22
    2060 Hz   115     1    18     0     0     5     0     8
23
    2070 Hz   218     1    14     1     3     6     0    12
24
    2080 Hz   384     6     2     0     2     1     1     8
25
    2090 Hz   504     5     3     0     1     1     8    14
26
    2100 Hz   451     6     3     0     1     3     5    27
27
    2110 Hz   324     3     1     0     0     5     0    10
28
    2120 Hz   175     0     7     1     6     5     0     0
29
    2130 Hz    39     2     3     0     7     1     0     0
30
    2140 Hz     0     0     3     0     9     1     9     1

von Dergute W. (derguteweka)


Angehängte Dateien:

Lesenswert?

Moin,

Hier mal ein Vergleich der Filterfrequenzgaenge.
blau: Goertzel mit 128 Berechnungen fuer 697Hz/8kHz Sample
rot : Ein FIR Filter mit 128 taps, die entweder +1 oder -1 sind, so das 
eben 697Hz als Bandpass angenaehrt wird.

Gruss
WK

von Frank E. (Firma: Q3) (qualidat)


Lesenswert?


von Marcus (Gast)


Lesenswert?

>https://forum.arduino.cc/index.php?topic=121540.0

An den Arduino hatte ich auch schon gedacht, damit würde die Software 
eine weite Verbreitung finden.

Allerdings nutzt die vorne im ZIP-File gepostete Version schamlos die 
einfache Float-Multiplikation und Addition. Die kann in Punkto 
Geschwindigkeit bei weitem nicht mit Daniels Version mithalten.

>Man könnte die Fourier-Koeffizienten auch native (ohne Goertzel oder
>FFT) berechnen, wenn das Ergebnis auch 'etwas fehlerhafter' sein dürfte.
>Wenn ein paar Oberwellen zulässig sind, könnte man nämlich statt einer
>Summe aus Sinusprodukten eine Summe aus Rechteckprodukten bilden. Die
>gesamte Berechnung bestände dann nur noch aus zwei Summen ohne
>Multiplikation.

Mit einem Rechteckfilter hatte ich auch schon mal vor einer Weile als 
Bandpass-Ersatz experimentiert.
So was ähnliches wird seit langem beim Ringmodulator gemacht:
https://de.wikipedia.org/wiki/Ringmodulator

Meine Ergebnisse damals hatten mich nicht so recht überzeugt, deshalb 
habe ich das dann nicht weiter verfolgt.

Deine Ergebnisse sehen besser aus ;-)

von Marcus (Gast)


Lesenswert?

>Hier mal ein Vergleich der Filterfrequenzgaenge.
>blau: Goertzel mit 128 Berechnungen fuer 697Hz/8kHz Sample
>rot : Ein FIR Filter mit 128 taps, die entweder +1 oder -1 sind, so das
>eben 697Hz als Bandpass angenaehrt wird.

Der Peak ist ganz gut zu erkennen. Man müsste sich vielleicht einen Test 
überlegen, mit dem man die Praxistauglichkeit überprüfen kann.

von Daniel T. (Gast)


Lesenswert?

Marcus schrieb:
>>Hier mal ein Vergleich der Filterfrequenzgaenge.
>>blau: Goertzel mit 128 Berechnungen fuer 697Hz/8kHz Sample
>>rot : Ein FIR Filter mit 128 taps, die entweder +1 oder -1 sind, so das
>>eben 697Hz als Bandpass angenaehrt wird.
>
> Der Peak ist ganz gut zu erkennen. Man müsste sich vielleicht einen Test
> überlegen, mit dem man die Praxistauglichkeit überprüfen kann.

Man könnte einen Online-Radio-Stream auf verschiedene Filter anwenden 
und die Fehlerquoten für irrtümlich erkannte DTMF-Code vergleichen. 
Würde mich auch interessieren. Teste das doch mal.

von Marcus (Gast)


Lesenswert?

>Teste das doch mal.

Mal schauen ... vielleicht stelle ich hier mal ein Test-Wav ein und 
mache es mit Octave.

Als Erklärung für das gute Funktionieren Deines Rechteck-Filters hätte 
ich folgendes anzubieten:

Das Spektrum eines Rechtecks verhält sich 1, 1/3, 1/5 usw.
https://de.wikipedia.org/wiki/Rechteckschwingung

Bei einer Filterauslegung für 700Hz würde die erste Oberwelle bei 2100 
Hz liegen. Eine Frequenz bei 2100Hz müsste dann vermutlich 3 mal so 
stark sein um den gleichen Filteroutput zu erzeugen wie die eigentlich 
gesuchte Frequenz. Ich vermute, dass in Sprache und Musik eher die 
tieferen Frequenzen vermehrt über den relativ langen 
Integrationszeitraum auftreten. Deshalb hat der Rechteckfilter trotzt 
seiner Ungenauigkeit eine relativ gute Erkennungsrate.

Ich habe mich früher immer gewundert, warum die DTMF Töne so schräg 
unharmonisch klingen und gedacht, die hätten sich auch schönere Töne 
aussuchen können.

Der Grund wird aber in der Wikipedia erklärt:

"MFV ist ein In-Band-Signalisierungsverfahren, das heißt, die Signale 
befinden sich innerhalb des normalen Sprachfrequenzbandes und können vom 
Telefonierenden mitgehört werden. Daher könnten natürliche Geräusche 
(zum Beispiel Musik) von der Vermittlungsstelle ebenfalls als Signal 
aufgefasst werden. Die Frequenzen von MFV-Signalen wurden daher so 
gewählt, dass sie Dissonanzen erzeugen, die mit sehr geringer 
Wahrscheinlichkeit in der Umgebung eines Telefons auftreten."

von Marcus (Gast)


Lesenswert?

@Daniel
Kleiner Nachtrag:
Ich nehme mal die Zwei Maxima des ersten Filters aus deinen Testdaten:


     700 Hz  4445   175     3     8     6     0     7     0


    2090 Hz   504     5     3     0     1     1     8    14

Das ist ~ Faktor 9. Ich habe Faktor 3 vorher gesagt. Das dürfte daran 
liegen dass der Output in Deiner Berechnung quadratisch ist und die 
Wurzel nicht gezogen wird ( Was ja für die Signalerkennung nicht 
relevant wäre ).

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.