Forum: Digitale Signalverarbeitung / DSP / Machine Learning Erkennung des Startbits bei UART mit FSK


von Trakuna (Gast)


Lesenswert?

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

von Michael R. (Firma: Brainit GmbH) (fisa)


Lesenswert?

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

von Trakuna (Gast)


Lesenswert?

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!

von Michael R. (Firma: Brainit GmbH) (fisa)


Lesenswert?

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...

von Trakuna (Gast)


Angehängte Dateien:

Lesenswert?

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?

von Michael R. (Firma: Brainit GmbH) (fisa)


Lesenswert?

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 :-)

von Trakuna (Gast)


Lesenswert?

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!

von Michael R. (Firma: Brainit GmbH) (fisa)


Lesenswert?

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

von Trakuna (Gast)


Lesenswert?

Hmm, einleuchtend! :-D
Dennoch sind die Ergebnisse unbrauchbar, die Abweichung von der idealen 
Abtastrate ist zu groß, die Fehler sind leider nicht ignorierbar.

von W.S. (Gast)


Lesenswert?

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.

von Michael A. (michiavelli)


Lesenswert?

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?"

von Trakuna (Gast)


Lesenswert?

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.

von Michael R. (Firma: Brainit GmbH) (fisa)


Angehängte Dateien:

Lesenswert?

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
von Trakuna (Gast)


Lesenswert?

Das Ergebnis spricht für sich! Würdest du evtl. den Perl-Code teilen?

von Michael R. (Firma: Brainit GmbH) (fisa)


Lesenswert?

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
Noch kein Account? Hier anmelden.