Hallo zusammen, ich überlege mir gerade eine Übertragungsart für serielle Daten über eine Audioleitung. Momentaner Stand ist, dass ich die logischen Pegel einer einfachen 1200 Baud UART mittels FSK moduliere und entsprechend beim Empfänger wieder demodulieren möchte. Jetzt das Problem: Wie erkenne ich beim Empfänger, dass ein Startbit vorliegt? Die Detektion der beiden Spektralkomponenten geschieht über 2 Goertzel-Filter. Allerdings ist mir nicht klar, über wieviele Samples N ich die Filter laufen lassen soll, um nichts zu "verpassen" und dennoch die Synchronisation bzgl. nachfolgender Bits zu gewährleisten? Meine bisherige Idee wäre, N zunächst möglichst klein zu wählen und sobald das Filter eine Frequenz (=Startbit) erkennt, N auf die Anzahl der Samples pro Symbol bei gegebener Abtastrate zu setzen. Wäre das ein praktikabler Weg? Vielleicht noch wichtig zu wissen: Die UART wird nicht auf einem µC implementiert, sondern in einer PC-Software. Beste Grüße
hier Beitrag "Digitale FSK Demodulation mit Goertzel Algorithmus" wird ein anderer, aber aus meiner Sicht interessanter Ansatz verfolgt: IQ-Demodulator, Drehung der Phase (welche sich ganz ohne trigonometrie bestimmen lässt) ist bereits dein Nutzsignal
Danke für den Tipp. Leider sind bei mir alle Frequenzen fest vorgeben: Baudrate: 1225 Logisch 0: 4900 Hz Logisch 1: 7350 Hz Abtastrate: 44100, 48000 oder 96000 Hz, je nach Umgebung. Damit fällt - zumindest nach meinem Verständnis - ein I&Q-Verfahren raus. Ich lasse mich da aber sehr gerne eines Besseren belehren!
ich denke das sollte trotzdem gehen... Mittenfrequenz: (4900+7350)/2 = 6125 Hz 4-fach abtasten: 24500Hz andersrum: 48000 Hz, jedes zweite Sample verwenden: 24000 Hz, dividiert durch 4 = 6000 Hz, nicht weit daneben. Damit liefe halt die Phase in eine Richtung schneller als in die andere...
Blöderweise habe ich nicht die Wahl zwischen 44.1, 48 und 96 KHz, das kann sich von System zu System ändern. Ich habe trotzdem mal deine Beispielrechnung simuliert mit MATLAB (Code aus deinem vorherigen Link):
1 | baud = 1225; |
2 | fs = 44100; |
3 | |
4 | % Signal für Simulation generieren |
5 | l = fs/baud; |
6 | w = 2*pi/(fs/(4900)); |
7 | lo = sign(sin(linspace(0,w*l-1,l))); |
8 | w = 2*pi/(fs/(7350)); |
9 | hi = sign(sin(linspace(0,w*l-1,l))); |
10 | |
11 | signal = [lo, hi, lo, hi, hi, hi, lo]; |
12 | |
13 | faktor1 = 4; |
14 | inphase = signal(1:faktor1:length(signal)); |
15 | quadratur = signal((1:faktor1:length(signal))+1); |
16 | |
17 | % Samplingrate dezimieren |
18 | faktor2 = 2; |
19 | inphase_r = inphase(1:faktor2:length(inphase)); |
20 | quadratur_r = quadratur(1:faktor2:length(inphase)); |
21 | |
22 | % Phasenverlauf berechnen |
23 | angles = unwrap(angle(inphase_r + 1i*quadratur_r)); |
24 | plot(angles, '-o'); |
Das Ergebnis (siehe Plot) ist zumindest für 44.1 KHz so nicht zu gebrauchen, da werde ich wohl doch bei meinen Goertzeln bleiben. Hättest du denn eventuell eine Idee, wie ich ein Startbit anständig mit Goertzel-Filtern detektieren könnte?
ich kenn mich leider mit matlab genau gar nicht aus, aber könnte dein Fehler hier liegen: im Original wird jedes 4. Sample für I verwendet (4*n) und jedes (4*n+1)te für Q. Du solltest aber doppelt so schnell abtasten, also 8*n bzw. 8*n+2 (note the "+2") Ansonsten lass ich mal den Signalverarbeitern hier den Vortritt :-)
Michael Reinelt schrieb: > Du solltest aber doppelt so schnell abtasten Das tue ich bereits, indem ich nicht deine rechnerischen 24.5 KHz als Samplingfrequenz nehme sondern eben 44.1 KHz. Dennoch vielen Dank für deine Gedanken!
Trakuna schrieb: > Michael Reinelt schrieb: >> Du solltest aber doppelt so schnell abtasten > > Das tue ich bereits, indem ich nicht deine rechnerischen 24.5 KHz als > Samplingfrequenz nehme sondern eben 44.1 KHz. Ja! Aber wenn du doppelt so schnell abtastest, musts du auch die Auswertung von 4*n bzw 4*n+1 verdoppeln auf 8*n bzw 8*n+2
Hmm, einleuchtend! :-D Dennoch sind die Ergebnisse unbrauchbar, die Abweichung von der idealen Abtastrate ist zu groß, die Fehler sind leider nicht ignorierbar.
Wenn du schon mit FSK arbeiten willst, dann solltest du dir merken, daß dein Dekodieralgorithmus lediglich das ursprüngliche Sendesignal wiederherstellen kann, also hi oder lo -->Modulator-->Transmission-->Demodulator--> hi oder lo. Mehr nicht, auch keine Startbiterkennung. Was dann ein anschließender Protokoll-Detektor draus macht, kommt dahinter und ist wirklich ein anderes Thema als deine FSK-Modulation. W.S.
W.S. schrieb: > Was dann ein anschließender > Protokoll-Detektor draus macht, kommt dahinter und ist wirklich ein > anderes Thema als deine FSK-Modulation. Dem stimme ich zu. Nach der FSK-Demodulation kommen die Nullen und Einsen raus und die musst du dekodieren! Für die Startbit-Detektion siehe Beitrag "Woran erkennt ein UART eigentlich das Startbit?"
W.S. schrieb: > Was dann ein anschließender > Protokoll-Detektor draus macht, kommt dahinter und ist wirklich ein > anderes Thema als deine FSK-Modulation. Gut, das sehe ich natürlich ein. Dann stufe ich meine Frage mal ein klein wenig zurück: Welche Fenstergröße macht Sinn für eine Demodulation? Ich fange mit meiner Frequenzerkennung ja leider nicht passgenau zu Signalbeginn an.
Ich hab mich jetzt nochmal etwas mit dem IQ-Demodulator gespielt. Da ich Mathematica weder habe noch bedienen kann, hab ich eine kleine Simulation in Perl programmiert. Wenn ich da keinen groben Schnitzer eingebaut habe, spricht das Ergebnis für sich: das funktioniert nicht nur gut, sondern saugut! Blau ist dein Nutzsignal, abgetastet mit 48kHz. Wechselt zwischen 4900Hz und 7350Hz mit einer Rate von 1225 Hz. X-Achse ist skaliert auf die Baudrate. Rot ist der erkannte Phasor. Verschoben primär deshalb, weil die Erkennung nur alle 8 samples läuft.
:
Bearbeitet durch User
Das Ergebnis spricht für sich! Würdest du evtl. den Perl-Code teilen?
Ist aber ein superquickhack :-) Insbesondere die Richtungserkennung hat noch Optimierungspotential
1 | #!/usr/bin/perl
|
2 | |
3 | use strict; |
4 | use warnings; |
5 | |
6 | use constant PI => 4 * atan2(1, 1); |
7 | |
8 | my $baud = 1225; |
9 | my $f0 = 4900; |
10 | my $f1 = 7350; |
11 | |
12 | my $sample = 48000; |
13 | |
14 | sub quadrant ($$) { |
15 | my ($i, $q) = @_; |
16 | return 1 if ($i >= 0 && $q >= 0); |
17 | return 2 if ($i <= 0 && $q >= 0); |
18 | return 3 if ($i <= 0 && $q <= 0); |
19 | return 4; |
20 | }
|
21 | |
22 | |
23 | my ($I_old, $I_new) = (0, 0); |
24 | my ($Q_old, $Q_new) = (0, 0); |
25 | |
26 | my $dir = 0; |
27 | |
28 | for (my $t = 0, my $i = 0; $t < 0.01; $t += 1.0/$sample, $i++ ) { |
29 | |
30 | my $a0 = sin (2*PI*$t*$f0); |
31 | my $a1 = sin (2*PI*$t*$f1); |
32 | |
33 | my $x = $t * $baud; |
34 | my $a; |
35 | if (int($x) % 2 == 0) { |
36 | $a = $a0; |
37 | } else { |
38 | $a = $a1; |
39 | }
|
40 | |
41 | if ($i % 8 == 0) { |
42 | $I_old = $I_new; |
43 | $I_new = $a; |
44 | } elsif ($i % 8 == 2) { |
45 | $Q_old = $Q_new; |
46 | $Q_new = $a; |
47 | |
48 | my $qu1 = quadrant ($I_old, $Q_old); |
49 | my $qu2 = quadrant ($I_new, $Q_new); |
50 | |
51 | if ($qu1 == $qu2) { |
52 | if ($qu1 == 1) { |
53 | if ($I_new > $I_old) { |
54 | $dir = 1; |
55 | } elsif ($I_new < $I_old) { |
56 | $dir = -1; |
57 | } else { |
58 | $dir = 0; |
59 | }
|
60 | } elsif ($qu1 == 2) { |
61 | if ($I_new > $I_old) { |
62 | $dir = 1; |
63 | } elsif ($I_new < $I_old) { |
64 | $dir = -1; |
65 | } else { |
66 | $dir = 0; |
67 | }
|
68 | } elsif ($qu1 == 3) { |
69 | if ($I_new > $I_old) { |
70 | $dir = -1; |
71 | } elsif ($I_new < $I_old) { |
72 | $dir = 1; |
73 | } else { |
74 | $dir = 0; |
75 | }
|
76 | } elsif ($qu1 == 4) { |
77 | if ($I_new > $I_old) { |
78 | $dir = -1; |
79 | } elsif ($I_new < $I_old) { |
80 | $dir = 1; |
81 | } else { |
82 | $dir = 0; |
83 | }
|
84 | } else { |
85 | $dir = 0; |
86 | }
|
87 | } elsif ($qu2-$qu1 == 1 || $qu2-$qu1 == -3) { |
88 | $dir = -1; # CCW |
89 | } elsif ($qu2-$qu1 == -1 || $qu2-$qu1 == 3) { |
90 | $dir = 1; # CW |
91 | } else { |
92 | # Sprung über zwei Quadranten => Richtung unbestimmt
|
93 | $dir = 0; |
94 | }
|
95 | }
|
96 | printf ("%d %.6f %.6f %.6f %d\n", $i, $t, $x, $a, $dir); |
97 | |
98 | }
|
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.