Erkennung des Startbits bei UART mit FSK

Gast #3576352
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
Gast #3576375
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!
(Firma: Brainit GmbH) #3576404
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...
Gast #3576527
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?
Angehängte Dateien:
(Firma: Brainit GmbH) #3576610
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 :-)
Gast #3578900
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.
Gast #3581044
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.
(Firma: Brainit GmbH) #3586172
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.
Angehängte Dateien:
(Firma: Brainit GmbH) #3589078
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
}

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren