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.
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
>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 ...
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.
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
Vor langer Zeit mit einer simplen Picaxe realisiert. http://www.zierath-software.de/picaxe/beispiele/dtmf.html
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.
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.
>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.
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
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?
Könntest Du Deine Multiplikation hier posten? Das wäre nicht schlecht und ich könnte es mal ausprobieren.
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
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 :-)
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.
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.
>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
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.
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
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
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.
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
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.
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.
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.
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?
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
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.
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
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 :-)
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
>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.
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 |
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
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
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 | }
|
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 |
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
>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 ;-)
>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.
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.
>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."
@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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.