Forum: Digitale Signalverarbeitung / DSP / Machine Learning PSK 31 Modlulation im Mikrocontroller


von marc (Gast)


Lesenswert?

Kennt jemand das PSK31 Verfahren zu Datenübertragung über einen 
Analogkanal?

http://de.wikipedia.org/wiki/PSK31

Ich frage mich, ob man dieses Prinzip in einem Atmega8 oder ähnlichem 
implemetieren könnte.
Nach einiger Überlegung bin ich der Meinung, dass es geht, wenn man 
Tricks wie Abtastratenreduktion usw. anwendet.

Mir ist noch unklar, wie die Zeichenkodierung funktioniert.
Irgendwie muss man sich auf die Phase synchronisieren um zu erkennen, ob 
eine 1 oder eine 0 übertragen wird. Daher meine Vermutung: die 
Information kann eigenlich nur im Phasenwechsel kodiert sein.

von Christoph db1uq K. (christoph_kessler)


Lesenswert?

Gibt es schon, ein ATmega als PSK31-Decoder und Encoder mit einem 
inzwischen nicht mehr lieferbarem Display von Pollin:

http://www.aatis.de/content/aatis-bei-der-ham-radio-2008
"...Am gleichen Stand werden Workshops zum Aufbau eines einfachen und 
preisgünstigen PSK31-Controllers angeboten, so dass Sende- und 
Empfangsbetrieb ohne Einsatz eines PCs oder Notebooks durchgeführt 
werden kann. Der Transceiver muss dabei eine Abstimmung von 10Hz 
ermöglichen. Es wird nur eine PC-Tastatur mit deutschem Zeichensatz 
benötigt. Jeweils bis zu zwölf Interessenten können täglich um 9.30 Uhr 
und um 13.30 Uhr unter Anleitung diese Schaltung aufbauen."

von marc (Gast)


Lesenswert?

Klingt interessant. Schade, dass es nicht mehr Informationen gibt: Ist 
ein externer AD-Wandler eingebaut? Ist die Schaltung wirklich 
mimimalistisch, also nur Atmega und Display?
Vor allen Dingen: wie ist die Signalverarbeitung umgesetzt? Ist 
tatsächlich ein I/Q Mischer implementiert?

Noch eine andere Frage: kann man mit einem Weltempfänger auf irgendeinem 
Band solche Signale empfangen?

von Christoph db1uq K. (christoph_kessler)


Angehängte Dateien:

Lesenswert?

So sieht die Schaltung und das Blockdiagramm aus. Es gibt einen Artikel 
dazu im Praxisheft 18.

von Christoph db1uq K. (christoph_kessler)


Angehängte Dateien:

Lesenswert?

Anscheinend kann ich nicht nachträglich eine zweite Datei anhängen, hier 
das Blockdiagramm aus dem Artikel.

von guest (Gast)


Lesenswert?

PSK31 ist im Internet ausführlichst bis ins letzte Detail dokumentiert.
Einfach nach "PSK31" googeln und lesen. :-)

Kostenlose PSK31-Software auf dem PC installieren, SSB-Weltempfänger mit
der Soundkarte verbinden, PSK31-Frequenz einstellen. Fertsch! :-)

von marc (Gast)


Lesenswert?

Hallo Christoph,

vielen Dank für die Unterlagen. Beim Durchsehen des Schalplans meine ich 
Optimierungsmöglichkeiten zu erkennen:

Den R2R DAC könnte man durch eine einfach PWM mit RC-Tiefpass ersetzen. 
Das würde Bauteile spaaren. Ausserdem könnte man den nachfolgenden 
Verstärker weglassen und statt dessen eine AGC im Eingangszweig 
implementieren.

Auf der Softwareseite ist mir noch nicht ganz klar, warum da eine FFT 
implementiert ist. Um die Phase zu bestimmen, ist die nicht notwendig, 
oder?

marc

von Bernd W. (berndwiebus) Benutzerseite


Lesenswert?

Hallo marc.

> Den R2R DAC könnte man durch eine einfach PWM mit RC-Tiefpass ersetzen.
> Das würde Bauteile spaaren.

Vorsicht! PSK31 soll auch schmalbandig sein. Wenn Du irgendwelche 
Artefakte, Nichtlinearitäten oder gar Reste vom Takt auf dem Signal 
hast, funktioniert Deine Übertragung möglicherweise noch, aber Du störst 
andere mit dem breitbandigen Störnebel, und letztlich wird Deine 
Leistungsbilanz auch mies. In Bezug auf Linearität des Audiozuges ist 
PSK31 relativ anspruchsvoll.


Also an dem Punkte GUT FILTERN!


> Auf der Softwareseite ist mir noch nicht ganz klar, warum da eine FFT
> implementiert ist. Um die Phase zu bestimmen, ist die nicht notwendig,
> oder?

Es gibt PSK 31 Phasenumtastung mit 180 Grad, aber eben auch mehrfach mit 
90 Grad.
Ersteres ist langsamer, aber störfester, zweites empfindlicher aber 
schneller, weil du eine höhere Anzahl von Zuständen überträgst bei 
gleichem Takt.
Es gibt auch noch Varianten mit schnellerem oder langsamerem Takt.
Ausserdem willst Du eventuelle Frequenzabweichungen noch ausgleichen 
können.....
FET könnte Dir dafür die Parameter liefern.

Die Problematik solcher Stand allone Lösungen ist meist die 
Abstimmanzeige....oder Du brauchst eine NF-AFC. Die wird aber 
möglicherweise von benachbarten  Stationen (insbesondere wenn sie 
breitbandig sind) schon beinflusst.


Mit freundlichem Gruß: Bernd Wiebus alias dl1eic

http://www.dl0dg.de

Selbsterkenntnis ist der erste Schritt zur Depression.
Jeder echte Wettbewerb ist ruinös. Darum beruht jede funktionierende 
Wirtschaft auf Schiebung.

von marc (Gast)


Lesenswert?

>> Den R2R DAC könnte man durch eine einfach PWM mit RC-Tiefpass ersetzen.
>> Das würde Bauteile spaaren.

>Vorsicht! PSK31 soll auch schmalbandig sein. Wenn Du irgendwelche
>Artefakte, Nichtlinearitäten oder gar Reste vom Takt auf dem Signal

In einem Beispiel für ein PSK31 Signal habe ich eine Signalfrequenz von 
1600Hz gesehen. Wenn man eine PWM Frequenz von 32Khz nimmt und einen 
doppelten RC Tiefpass nachschaltet dürfte der Noise flor deutlich 
kleiner 46dB sein. Ich würde vermuten, dass das sogar eine besseres 
Ergebnis als beim R2R DAC mit seinen toleranzbehafteten Widerständen 
ist.

von Bernd W. (berndwiebus) Benutzerseite


Lesenswert?

Hallo marc.

> In einem Beispiel für ein PSK31 Signal habe ich eine Signalfrequenz von
> 1600Hz gesehen. Wenn man eine PWM Frequenz von 32Khz nimmt und einen
> doppelten RC Tiefpass nachschaltet dürfte der Noise flor deutlich
> kleiner 46dB sein. Ich würde vermuten, dass das sogar eine besseres
> Ergebnis als beim R2R DAC mit seinen toleranzbehafteten Widerständen
> ist.

Das ist Richtig. Du must halt nur darauf achten. PSK31 ist eben nicht in 
dem Sinne "digital", als das Du meinst, Du hättest auf unterster Ebene 
nur mit "High/Low" zu tun.

Mit freundlichem Gruß: Bernd Wiebus alias dl1eic

http://www.dl0dg.de

Selbsterkenntnis ist der erste Schritt zur Depression.
Jeder echte Wettbewerb ist ruinös. Darum beruht jede funktionierende
Wirtschaft auf Schiebung.

von marc (Gast)


Angehängte Dateien:

Lesenswert?

Um die Schwächen und Stärken des Verfahrens besser zu verstehen, möchte 
ich das ganze simulieren.
Für die Simulation benutze ich Octave ( die freie Version von Matlab ).

Ich habe die Modulation des Sendesignals modelliert. Die 
Modulationsfrequenz und Baudrate kann mit den Variblen verändert werden.

Als nächstes ist das Kanalmodell an der Reihe. Dort weiß ich noch nicht, 
wie es realistischerweise aussehen sollte. Ich werde wohl mit einem 
einfachen Rauschoffset beginnen.
1
% modulation frequency [Hz ]
2
fmod=1000;
3
% sample frequency of the system [Hz]
4
fs=20000;
5
% bit rate ( Baud [1/s])
6
baud=31;
7
8
%bits to be transmitted
9
bits=[0 1 0 1];
10
11
bittime=1/baud;
12
sendtime=length(bits)*bittime;
13
14
% samples n
15
n=1:sendtime*fs;
16
17
phases=[];
18
onebitsamples=bittime*fs;
19
20
% phase 180 degree
21
phase180=fs/fmod/2;
22
23
% generate phase vektor
24
for bitcount=1:length(bits)
25
  for kk=1:onebitsamples
26
        phases=[phases bits(bitcount)*phase180];
27
  endfor
28
endfor
29
30
%plot(phases);
31
32
envelope=abs(sin(pi*baud/fs*n));
33
signal=sin(2*pi*fmod/fs*(n+phases));
34
modulatedSignal=envelope.*signal;
35
36
plot(modulatedSignal);
37
grid on

von marc (Gast)


Angehängte Dateien:

Lesenswert?

Hier mein erster Versuch für den Demodulator:

Das Empfangssignal wird mit der Modulationsfrequenz gemischt
1
signalMixed=modulatedSignal.*exp(i*2*pi*fmod/fs*n);
und danach mittels eines einfache RC-Tiefpassmodels gefiltert.
Der einpolige Filter wird deshalb verwedet, weil er sich auf einem 
Atmega8 mit einer Addion und einem Schiebebefehl realisieren lässt und 
damit sehr wenig Rechenzeit verbraucht.
Im Diagramm sieht man den Realteil und den Imaginärteil des 
ungefilterten und gefilterten Signals.
Wie man sieht, findet sich die Modulationsinformation im Imaginärteil 
des Signals wieder ( durch die Berechnung sind die Vektoren 
synchronisiert, das ist in Wirklichkeit nicht gegeben ).
Allerdings sind die Ripple auf den gefilterten Signalen noch ziemlich 
groß, deshalb bin ich mir nicht sicher, ob nicht deutlich bessere Filter 
notwendig sind.
Hat jemand eine Idee für einen recheneffizienten Tiefpass?


Folgende Einstellungen wurden verwendet
1
% modulation frequency [Hz ]
2
fmod=1000;
3
% sample frequency of the system [Hz]
4
fs=20000;
5
% bit rate ( Baud [1/s])
6
baud=250;
7
8
%bits to be transmitted
9
bits=[0 1 1 0 1];


Kode für Mischer und Tiefpassfilter
1
%############# demodulation ###################################
2
3
signalMixed=modulatedSignal.*exp(i*2*pi*fmod/fs*n);
4
5
%corner frequency of lowpass
6
fg=200;
7
%simple RC-lowpass
8
a=2*pi*fg/fs;
9
B=a;
10
A=[1 a-1];
11
% filter signal with IIR-Filter ( RC-low pass modell )
12
signalFiltered=filter(B,A,signalMixed);
13
14
subplot(2,1,1)
15
plot(real(signalMixed));
16
hold on
17
plot(real(signalFiltered),'g');
18
hold on
19
subplot(2,1,2)
20
plot(imag(signalMixed));
21
hold on
22
plot(imag(signalFiltered),'g');
23
hold on
24
grid on

von marc (Gast)


Angehängte Dateien:

Lesenswert?

Um das Signal noch besser zu Filtern, habe ich einen Moving Average 
Filter und den RC-Tiefpass kombiniert. Die Länge des Moving Average 
Filters entspricht genau der halben Modulationsfrequenz, dadurch wird 
das heruntergemischte Modulationssignal ideal unteredrückt, da sich 
genau an der Stelle der Modulationsfrequenz die Nullstelle des Moving 
Average Filters befindet. Das Ergebnis ist super, wie in den Diagrammen 
zu sehen :-)

Zur Rückgewinnung des Signals habe ich einfach die Phase aus dem I und Q 
Anteil berechnet und siehe da: Die Phase zeigt sich als sehr stabil.
1
% phase plotten ( rote Farbe )
2
plot(angle(signalFiltered),'r');

Um zu testen, wie gut das Verfahren funktioniert, habe ich dem 
Nutzsignal ein weises Rauschen mit der selben Amplitude überlagert ( 
2tes Bild ). Die Phase zeigt sich trotz der Störungen weiterhin ziemlich 
stabil.
1
modulatedSignal=modulatedSignal+(rand(1,length(modulatedSignal))-0.5);

Jetzt muss ich überlegen, wie ich aus dem roten Signal die Bits wieder 
zurückgewinnen kann. Wenn man sich das rote Signal ansieht, scheint das 
kein Problem zu sein. Man sieht ja deutlich, wenn die rote Linie ( Phase 
) oben oder unten ist. Aber einen Algorithmus dazu zu entwerfen, der 
dies Unterscheidung trifft, scheint mir nicht so einfach.

von marc (Gast)


Angehängte Dateien:

Lesenswert?

Hier mal ein reales Signal (aus dem Internet ) durch den "octave 
Demodulator" geschickt.

Seltsamerweise liegt die Modulationsfrequenz wohl bei ca.954Hz. 
Zumindest habe ich die Mischfrequenz so gewählt. Allerdings sieht man, 
dass die Frequenz nicht haargenau stimmt, weil im unteren Diagramm die 
Phase ( rot ) langsam nach unten davon läuft. Warum die Funker in diesem 
Fall eine so ungerade Modulationsfrequenz gewählt haben, ist mir ein 
Rätsel.

Für diesen Fall müsste man wohl noch einen "Tracker" einbauen, der das 
langsame Weglaufen der Phase korrigiert.

Auf jeden Fall kann man im roten Phasendiagramm super die BITs erkennen.


Programmkopf zum laden des Signals
1
% psk31 signal von: http://www.pci-card.com/PSK31_BPSK.wav
2
3
[Y,FS,BITS]=wavread("PSK31_BPSK.wav");
4
5
modulatedSignal=Y(2000:6000)';
6
7
% modulation frequency [Hz ]
8
fm=954;
9
% sample frequency of the system [Hz]
10
fs=FS;
11
% bit rate ( Baud [1/s])
12
baud=31;
13
14
bittime=1/baud;
15
onebitsamples=bittime*fs;
16
17
n=1:length(modulatedSignal);

von p_31 (Gast)


Lesenswert?


von p_31 (Gast)


Lesenswert?


von Gerrit B. (gbuhe)


Lesenswert?

Hallo Marc,

die Trägerfrequenz und selbst die Symbolrate des PSK31-Signales wird 
immer "krumm" sein, da die Taktbasis der beteiligten Rechner - ob 
Mikrocontroller oder PC - immer leicht unterschiedlich ist.
Zum Ausgleich ist eine Trägerfrequenz- und Symboltaktrückgewinnung in 
der Signalverarbeitung vorzunehmen. Auf den Folien 106 und 107 folgender 
Präsentation findest Du etwas Information dazu:

http://www.unidsp56.de/data/DigitaleDatenuebertragung071020final.pdf

Im Falle dieser einfachen BPSK und angesichts der gwünschten niedrigen 
Komplexität, kann die Symboltaktrückgwinnung deutlich vereinfacht 
werden, indem die Symbolmitte bei der betragsmäßig größten Amplitude 
angenommen wird (genügend Überabtastung vorrausgesetzt). Selbst bei der 
QPSK erhöht man damit schon die BER (Bit Error Rate), weil die größten 
Amplituden nicht zum Symbolabtastzeitpunkt auftreten, sondern durch das 
"Überschwingen", bedingt durch die Pulsformung zur 
Bandbreitenreduzierung. Bei der BPSK hat sich die einfache Variante aber 
durchaus bewährt.

Die Simulation mit Octave (oder Alternativen) ist absolut der beste Weg, 
so ein PSK31-Modem zu entwickeln. Ich würde als Datensequenz eine PRBS 
(Pseudo Random Bit Sequence) einsetzen, z.B. eine PRBS9 (9 Bit 
Schieberegister). So kannst Du später den empfangenen Bitstrom in ein 
identisches Schieberegister einspeisen und die BER feststellen. Diese 
ist die wichtigste Metrik zur Beurteilung von in die Signalverarbeitung 
eingebrachten Verbesserungen oder Vereinfachungen. So kannst Du dann 
beurteilen, wie viel dB Signalrauschabstand für eine gegebene BER mehr 
nötig sind, wenn z.B. die Frequenzrückgewinnung sehr einfach anstatt 
komplex implementiert wird, usw.

Weiterhin viel Erfolg und viele Grüße!

Gerrit, DL9GFA

von marc (Gast)


Lesenswert?

Hallo Gerrit,

vielen Dank für Deine Antwort und Deine auführlichen Folien ( sieht nach 
viel Arbeit aus). Die Folien finde ich ganz gut weil sie das Thema 
Signalverarbeitung ziemlich umfangreich behandeln.

>Im Falle dieser einfachen BPSK und angesichts der gwünschten niedrigen
>Komplexität, kann die Symboltaktrückgwinnung deutlich vereinfacht
>werden, indem die Symbolmitte bei der betragsmäßig größten Amplitude
>angenommen wird (genügend Überabtastung vorrausgesetzt)

Daran habe ich auch schon gedacht, aber ich bin noch im Zweifel: Ich 
nehme an dass in einem Funkkanal auch ordentlich Amplitudenschwankungen 
vorhanden sein können. Ich bin mir auch nicht ganz sicher, ob bei PSK31 
zwischen 2 gleichen Symbolen die Amplitude auf 0 geregelt wird ( der 
Einfachheit habler habe ich es in der Senderoutine so gemacht ).

Gerade vorher kam mir die Idee, dass ein "matched Filter" vor dem 
Mischer ja ideal sein müsste um Störungen zu unterdrdrüken. Mit meine 
Simulationsroutinen konnte ich ein Rauchen mit 10 facher Stärke auf das 
Nutzsignal legen und die Phase war immer noch einigermaßen gut 
detektierbar. Das Interessante: Bei der Ausgabe des Signals auf die 
Soundkarte ist bei Rauschfaktor 10 das eigentlich Signal schon gar nicht 
mehr hörbar.

Gruß,
marc

von Abdul K. (ehydra) Benutzerseite


Lesenswert?

Das man das PSK-modulierte Signal nicht mehr hören kann, ist normal. 
Kannste bei Phil Karn dich schlau machen.

Du ersparst dir viel Kopfschmerzen, wenn du dein Signal mit einem 
Komparator jeglicher Amplitude befreist und DPSK verwendest.

von marc (Gast)


Lesenswert?

>Kannste bei Phil Karn dich schlau machen.
Meinst Du hier?
http://www.ka9q.net/dsp.html

von Gerrit B. (gbuhe)


Lesenswert?

Hallo Marc,

bei der Symbolsynchronisation anhand der maximalen Amplitude betrachtet 
man vorzugsweise nur ein kleines zeitliches Fenster um den genauen 
Erwartungswert des Symbolabtastzeitpunktes herum. Wenn das 
Amplitudenmaximum systematisch immer etwas später kommt, erhöht man den 
Periodenzähler, der das nächste Abtastfenster vorhersagt. Wenn das 
Maximum früher kommt, erniedrigt man den Zähler. Der Zähler schwankt 
schlußendlich +/-1 um den idealen Abtastwert herum. Das ist der 
sogenanne "early/late"-Ansatz. Er ist auch auf Mikrocontrollern leicht 
implementiert und die Performance ist auch sehr gut. Ggf. hilft eine AGC 
mit langsamer Zeitkonstante (>>Tsymbol=32ms), die Amplitudenwerte in 
einem geeigneten Fenster zu halten.


> Ich bin mir auch nicht ganz sicher, ob bei PSK31
> zwischen 2 gleichen Symbolen die Amplitude auf 0 geregelt wird ( der
> Einfachheit habler habe ich es in der Senderoutine so gemacht ).

Nein, wenn eine '1' gesendet wird, verändert sich die Phase nicht und 
die Amplitude geht nicht in Richtung Null. Eine größere Anzahl von '1' 
in direkter Folge wird durch die Kodierung allerdings vermieden. Viele 
Nullen können ohne weiteres auftreten (z.B. wenn kein Zeichen gesendet 
wird), aber das führt zu lauter 180°-Änderungen, die hervorragend zur 
Synchronisation taugen.


> Gerade vorher kam mir die Idee, dass ein "matched Filter" vor dem
> Mischer ja ideal sein müsste um Störungen zu unterdrdrüken.

Ja, das Matched Filter ist das optimale Filter hinsichtlich 
Signal-Rausch-Abstand.

> Simulationsroutinen konnte ich ein Rauchen mit 10 facher Stärke auf das
> Nutzsignal legen und die Phase war immer noch einigermaßen gut
> detektierbar. Das Interessante: Bei der Ausgabe des Signals auf die
> Soundkarte ist bei Rauschfaktor 10 das eigentlich Signal schon gar nicht
> mehr hörbar.

Immer wenn die Gesamtrauschleistung in der abgehörten Bandbreite höher 
ist als die Nutzsignalleistung des PSK31-Signales, kann man letzteres 
nicht heraushören. Dank des schmalen Bandpaß- bzw. Tiefpaß-Filters 
(Matched Filter), das auf die PSK31-Bandbreite optimiert ist, wird die 
Rauschbandbreite in der Signalverarbeitung deutlich reduziert und das 
SNR des Nutzsignales wächst so weit, daß eine Auswertung möglich wird. 
Bei Bandbreitenverhältnissen von 2.4kHz (SSB-Filter des Empfängers) zu 
60Hz (Auswertebandbreite des PSK31-Signals) hat man z.B. einen Gewinn an 
Rauschunterdrückung von 16dB (10*log10(2400/60)).

Viele Grüße!

Gerrit, DL9GFA

von Gerrit B. (gbuhe)


Lesenswert?

Hallo Marc,

mir ist aufgefallen, daß Du oben mit genau 31 Symbolen pro Sekunde 
rechnest. Die Symbolrate bei PSK31 ist aber 31.25 Symbole pro Sekunde, 
also genau 32ms pro Symbol.
Wenn Du Dich also wunderst, warum Deine Symboltaktrückgewinnung immer 
hinterher rennt, liegt es vielleicht daran ;o).

Gute Nacht!

Gerrit, DL9GFA

von Jan (Gast)


Lesenswert?

Nanu, Thread eingeschlafen?

Gibt es schon Neuigkeiten bzgl. des Demodulators? Bin sehr interessiert.

von DG8NCY (Gast)


Lesenswert?

Hallo? Gehts hier nicht weiter?? Das wäre sehr sehr schade!!!
Leider kommt man ja bei AATIS schlecht an Bausätze ran, das hier hat 
nach einer hoffnungsvollen Alternative ausgesehen...

von p_31 (Gast)


Lesenswert?

NUE-PSK, open source

von marc (Gast)


Lesenswert?

Hier gibt es eine interessante Realisierung des BPSK31 Verfahrens:

http://www.analogzoo.com/2014/12/amplitude-demodulating-bpsk31/

Scheinbar wird bei der 0 auch die Amplitude reduziert:

http://upload.wikimedia.org/wikipedia/commons/7/78/Bpsk31bits.png

von marc (Gast)


Lesenswert?

So wie es aussieht, habe ich die ganze Zeit die Modulation nicht richtig 
verstanden: Die Mitte des Null-Symbols ist genau da, wo die Amplitude 0 
ist. An diesem Punkt macht die Phase dann den Sprung um 180°.

Der Vollständigkeit halber hier noch den Link auf das GitHub-Repo für 
BPSK31.

von Helmut L. (helmi1)


Lesenswert?

Was er da im Analogzoo macht ist aber keine BPSK Dekodierung. Er nutz 
halt die Tatsache aus das die Amplitude abgesenkt wird im Zeitpunkt des 
Umschaltens. Kann man machen. Dabei hat man aber eine hoehere 
Stoerempfindlichkeit zu erwarten. Richtige BPSK dekoder werten die Phase 
des Signal aus und sind deshalb stabiler. Der normale Weg ist aber das 
in Software zu machen. Da reicht ein kleiner ARM Controller fuer aus.

von Gerrit B. (gbuhe)


Lesenswert?

Hallo Marc,

nein, die minimale Amplitude hat das Signal genau zwischen den 
Symbolen und ausschließlich(!) wenn eine 0 gesendet wurde.
Du mußt Dir das Augendiagramm mit der Phase auf der Ordinate 
("Y-Achse") ansehen (B_P_SK!). Im optimalen Abtastzeitpunkt liegt bei 
gutem SNR auch die maximale Amplitude vor, egal ob es einen 
Phasenwechsel gab oder nicht. Wenn eine 1 gesendet wurde, bleibt die 
Amplitude aber unverändert hoch und verrät nicht den optimalen 
Abtastzeitpunkt.

Natürlich kann man den Effekt ausnutzen, wie im Beispiel, und nur anhand 
des AM-Anteils das Signal demodulieren, aber dafür wird ein deutlich 
höheres SNR benötigt, als es bei der herkömmlichen Phasendemodulation 
nötig ist. Für eine möglichst stabile Verbindung bei geringer Feldstärke 
ist das Verfahren nicht geeignet.

Viele Grüße!

Gerrit, DL9GFA

von marc (Gast)


Lesenswert?

Hallo Gerit,

lustig, dass Du auch nach 4 Jahren des Thread-Stillstands gleich 
antwortest ;-)
Mir ist das Thema gerade wieder ins Auge gesprungen, weil es in Hackaday 
war.

>nein, die minimale Amplitude hat das Signal genau zwischen den
>Symbolen und ausschließlich(!) wenn eine 0 gesendet wurde.

Das Wikipedia-Bild zeigt es anders:

http://upload.wikimedia.org/wikipedia/commons/7/78/Bpsk31bits.png

Vielleicht ist es ja falsch.

>Du mußt Dir das Augendiagramm mit der Phase auf der Ordinate
>("Y-Achse") ansehen (B_P_SK!).

Hast Du gerade einen Link?

von marc (Gast)


Lesenswert?

>Der Vollständigkeit halber hier noch den Link auf das GitHub-Repo für
>BPSK31.

Link vergessen:
https://github.com/zenmetsu/radioModem

von marc (Gast)


Angehängte Dateien:

Lesenswert?

>nein, die minimale Amplitude hat das Signal genau zwischen den
>Symbolen und ausschließlich(!) wenn eine 0 gesendet wurde.

Zur Sicherheit habe ich mal den ersten Teil des Audiosignals aus der 
Wikipedia mit Audacity visuallisiert.
( http://en.wikipedia.org/wiki/File:PSK31_sample.ogg )

Zuer Synchromisation beginnt das Signal wohl mit lauter Nullen ( 
Phasenwechsel ). Danach kommen vereinzelt die Einzen. Bei den Einsen 
bricht das Signal auch leicht ein, was nach der schematischen Wikipedia 
Zeichung nicht sein müsste.

von Gerrit B. (gbuhe)


Lesenswert?

Hallo Marc,

wenn Du nach 'Augendiagramm BPSK' suchst, findest Du etliche Bilder. 
Leider steht immer Amplitude und nicht Phase auf der Ordinate, obwohl es 
sich um die Phase handelt. Leider ist damit die Amplitudeninformation 
nicht dargestellt. Besser läßt sich so ein digital moduliertes Signal im 
Zeigerdiagramm ansehen und diskutieren, da hier Phase und Amplitude 
gleichzeitig gezeigt werden. Man könnte als zweites Diagramm auch die 
Amplituden abschnittsweise (Symboldauer) übereinander legen und damit 
deren zeitlichen Verlauf parallel zur Phase verdeutlichen.

Warum gibt es eigentlich einen Amplitudenanteil, wenn die Information 
doch in der Phase steckt? Nun, man kann die Amplitude auch konstant 
halten, aber dann ist der "Weg zwischen den Symbolen im 
Konstellationsdiagramm" bei der BPSK um den Faktor pi/2 länger. Da die 
Geschwindikeit der Phasenänderung die Bandbreite beeinflußt, würde diese 
bei gleicher Symbolrate höher werden, oder aber die Symbolrate wäre für 
die gleiche Bandbreite zu reduzieren. Um beides zu vermeiden, wird der 
direkte, also kürzeste Weg durch den Ursprung des 
Konstellationsdiagrammes gewählt, was den Amplitudenanteil einbringt, 
mit der Amplitude Null direkt zwischen den Phasenwechseln.

Etwas Überblick über diese Themen findest Du in einem alten Vortrag von 
mir an dieser Stelle (ab Folie 70):

http://unidsp56.de/data/DigitaleDatenuebertragung071020final.pdf

Viele Grüße!

Gerrit, DL9GFA

: Bearbeitet durch User
von marc (Gast)


Lesenswert?

Vielen Dank für die Antwort, deine Folien sind sehr ausführlich und ganz 
informativ.

Von Michael Keller gibt es ein Signalflussbild zu einem PSK31 Empfänger:
http://dl6iak.etonlein.de/pics/pskstructure.gif
Vielleicht werde ich versuchen, die Auswertung so ähnlich in Octave zu 
machen.

Gestern habe ich endeckt, dass ich mit meinem Weltempfänger Radio 
"Sangean ATS909" tatsächlich PSK31 empfangen kann. Ich habe die 
Empfangsfrequenz auf 14.070 MHz ( USB ) eingestellt  und das Radio via 
Soundkarte an den PC angeschlossen. Dann habe ich "fldigi" in der 
"virtualbox" auf meinem Linux System installiert. ( 
http://www.w1hkj.com/Fldigi.html )

Jetzt am Neujahrstag kann ich tatsächlich einige PSK32 Konversationen 
mitlesen. Zugegebnermaßen verstehe ich nicht alle Kürzel der 
Amateurfunker aber macht nichts, ich finde es interessant, dass ich die 
Signale aus so großer Entfernung trotz meiner schlechten Antenne und des 
großen "Noise-Floors" empfangen kann. Hier ein Beispiel:
1
          How copy? QÖtog, DL3DJ de 9A7JDF pse kn 
2
   9A7JDF de DL3DJ
3
   Many thank
4
 sWSr aid enfon
5
my QcP wKO ee-ooee e GW5PH GW5PH pse kn 
6
 .
7
This is the first time we've worked
8
fb signal 599 599  
9
Name EDMOND 
10
QTH Longueville JN04CL Atlantic Coast
11
QSL by Eqsl,  (preffered) (AG) NO Bureau 
12
? 
13
TU IU4AVQ de F1DFF pse
14
-KN-
15
r
16
FYm    h 2893. cable digicat power 40 watios
17
  Antenna  : Hy-Gann 
18
 spletewlno ee V inverter 10/80
19
  Operator : 66 years, licenced 1983
20
 My QSL is OK via only bureau, or direct, information, www.qrz.com
21
 how copy? Michael BTU M6EFO M6EFO de E

von Bernd K. (prof7bit)


Lesenswert?

marc schrieb:
>>nein, die minimale Amplitude hat das Signal genau zwischen den
>>Symbolen und ausschließlich(!) wenn eine 0 gesendet wurde.
>
> Zur Sicherheit habe ich mal den ersten Teil des Audiosignals aus der
> Wikipedia mit Audacity visuallisiert.
> ( http://en.wikipedia.org/wiki/File:PSK31_sample.ogg )

Diese Ogg-Datei hat ziemlich verschmierte Phasenlagen so wie mir das 
nach ein paar ersten Versuchen erscheint (dieser Thread hier hat mich 
angesteckt, jetzt will ichs auch wissen), besser wäre es vielleicht 
erstmal ein wirklich sauberes Signal zu verwenden, ich weiß nicht ob das 
was der extrem komprimierende Vorbis-codec da veranstaltet hat 
realistisch ist um einen gestörten Übertragungsweg zu simulieren.

von Bernd K. (prof7bit)


Lesenswert?

marc schrieb:
> Von Michael Keller gibt es ein Signalflussbild zu einem PSK31 Empfänger:
> http://dl6iak.etonlein.de/pics/pskstructure.gif
> Vielleicht werde ich versuchen, die Auswertung so ähnlich in Octave zu
> machen.

Vielleicht wäre es einfacher auf die Trägerrückgewinnung komplett zu 
verzichten (spart nen Arkustangens auf schwachbrüstigen 
Microcontrollern) und stattdessen einfach das um eine Symbollänge 
verzögerte Empfangssignal selbst als Referenz zu nehmen, die Modulation 
ist ja Differential-PSK, also ginge das, das wäre dann in etwa so wie 
hier auf Seite 4: http://det.bi.ehu.es/~jtpjatae/pdf/p31g3plx.pdf

von marc (Gast)


Angehängte Dateien:

Lesenswert?

>Diese Ogg-Datei hat ziemlich verschmierte Phasenlagen so wie mir das
>nach ein paar ersten Versuchen erscheint (dieser Thread hier hat mich
>angesteckt, jetzt will ichs auch wissen), besser wäre es vielleicht
>erstmal ein wirklich sauberes Signal zu verwenden,

Hallo Bernd,
es freut mich, dass Du Dich auch dafür begeistern kannst. Ich habe eben 
mal eine Wav-Datei mit dem Programm "fldigi" erstellt. Gesendet wird 
immer

test test test ....

von Bernd K. (prof7bit)


Angehängte Dateien:

Lesenswert?

Ich hab mal folgendes gemacht, ziemlich hemdsärmelig aber zumindest 
tut es das was ich davon erwarte:


Ausgegangen wird davon daß ein Audiosignal von exakt 1kHz vorliegt, es 
muss also schon geeignet genau dorthin heruntergemischt sein durch 
entsprechend feinfühligen Abgleich des Transceivers plusminus ein paar 
wenige Hertz.

Ich habe einen Timer laufen mit 4kHz, der stößt den ADC an, ich sample 
also mit exakt der 4-fachen Frequenz. Im ADC-Interrupt dann wird die 
folgende Funktion aufgerufen, 4000 mal in der Sekunde:
1
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc) {
2
    int32_t value = HAL_ADC_GetValue(hadc);
3
    int32_t old = buffer[buffer_ptr];
4
    buffer[buffer_ptr] = value;
5
    if (++buffer_ptr == BUF_SIZE) {
6
        buffer_ptr = 0;
7
    }
8
9
    if (phase == 0) {
10
        I -= old;
11
        I += value;
12
    } else if (phase == 1) {
13
        Q -= old;
14
        Q += value;
15
    } else if (phase == 2) {
16
        I += old;
17
        I -= value;
18
    } else {
19
        Q += old;
20
        Q -= value;
21
        have_sample = true;
22
    }
23
    phase = (phase + 1) & 3;
24
25
}

buffer kann genau 4*32 Samples aufnehmen, ich summiere also immer über 
die letzten 32 Perioden jeweils I und Q, das hat schon eine ziemliche 
Filterwirkung und es sind dennoch keine Multiplikationen notwendig. Ich 
habe da also einen Direktmischer gebaut, wenn die Frequenz exakt 1/4 der 
Abtastrate wäre blieben I und Q konstant, wenn sie leicht daneben liegt 
dann dreht sich der Vektor (I,Q) langsam. Wenn die Phase um 180° springt 
dann springt dieser Vektor ebenfalls um 180°.

in der main habe ich nun folgendes:
1
int main(void) {
2
    init_board();
3
4
    for (uint16_t i=0; i<BUF_SIZE; i++) {
5
        buffer[i] = 0;
6
    }
7
8
    while (1) {
9
        if (have_sample) {
10
            have_sample = false;
11
12
            int32_t previous_I = delay_I[delay_ptr];
13
            int32_t previous_Q = delay_Q[delay_ptr];
14
            delay_I[delay_ptr] = I;
15
            delay_Q[delay_ptr] = Q;
16
            delay_ptr = (delay_ptr + 1) & 31;
17
18
            // scalar product with delayed sample
19
            int32_t prod = I * previous_I + Q * previous_Q;
20
21
            uart_send_16(prod >> 16);
22
        }
23
    }
24
}

delay_I und delay_Q sind beide genau 32 Elemente lang und verzögern 
somit genau 32ms. Ich berechne das Skalarprodukt aus (I,Q) mit dem von 
vor 32ms und das Ergebnis ist negativ wenn die Phase sich geändert hat 
oder positiv wenn die Phase gleich geblieben ist. Dass sich der vektor 
(I,Q) langsam dreht weil die Frequenz weggedriftet ist hat keinen 
Einfluss darauf dass man dennoch einen deutlichen Phasensprung erkennen 
kann.

Zu Debuggingzwecken sende ich dann das Produkt via UART an den PC und 
plotte es, siehe Bild.

Der analoge Aufbau sieht so aus daß ich eine wav Datei am PC abspiele 
über die angeschlossenen Brüllwürfel als Schall ausgebe, dann mit einem 
kleinen Electretmikrofon wieder aufnehme, zwei npn-Transistoren in 
Emitterschaltung zum Verstärken und dann direkt in den ADC-Eingang eines 
am USB-Port angeschlossenen stm32nucleo-boards. Mein Mikrofonverstärker 
ist nicht gerade optimal und er fängt einigen Schmutz aus dem 
Schaltnetzteil auf, das hab ich in 5 Minuten schnell zusammengestöpselt 
auf dem Steckbrett.

Anbei die wav Datei (im Internet gefunden) und ein Screenshot vom Plot 
der Ausgabe von uart_send_16(prod >> 16);

von Bernd K. (prof7bit)


Angehängte Dateien:

Lesenswert?

So. Mal eben schnell zusammengehackt das timing für das Samplen der 
bits. Wenn ich davon ausgehe dass mein Takt keine Abweichungen von 
mehreren Prozent hat dann hab ich mit einem Zähler der bei 32 überläuft 
schon den richtigen takt, ich muss nur die Phase einrasten lassen auf 
den negativen Peaks.

Die blauen spikes sind der Zeitpunkt wo time==symbol_sample_time, man 
sieht schön wie symbol_sample_time zu Beginn langsam verschoben wird bis 
die Phase eingerastet ist.
1
int main(void) {
2
    init_board();
3
4
    for (uint16_t i=0; i<BUF_SIZE; i++) {
5
        buffer[i] = 0;
6
    }
7
8
    //uint32_t period_0 = TIM2->ARR;
9
10
    int32_t neg_peak_value;
11
    uint8_t neg_peak_time;
12
    uint8_t symbol_sample_time = 16;
13
    uint8_t time = 0;
14
15
    int16_t x = 0;
16
17
    while (1) {
18
        if (have_sample) {
19
            have_sample = false;
20
21
            int32_t previous_I = delay_I[delay_ptr];
22
            int32_t previous_Q = delay_Q[delay_ptr];
23
            delay_I[delay_ptr] = I;
24
            delay_Q[delay_ptr] = Q;
25
            delay_ptr = (delay_ptr + 1) & 31;
26
27
            // scalar product with delayed sample
28
            int32_t prod = I * previous_I + Q * previous_Q;
29
            
30
            if (time == symbol_sample_time) {
31
                x = 10000;
32
            } else {
33
                x = 0;
34
            }
35
36
            uart_send_16(prod >> 10);
37
            uart_send_16(x);
38
            
39
            // find the exact time of the negative peak
40
            if (prod < 0 && prod < neg_peak_value) {
41
                neg_peak_value = prod;
42
                neg_peak_time = time;
43
            }
44
            
45
            // the symbol sampling clock is accurate (because we
46
            // have a crystal oscillator) but we must correct its 
47
            // phase so that it coincides with the negative peaks.
48
            // We do this adjustment 16 ms after each negative peak.
49
            if ((time - neg_peak_time == 16) || (time + 32 - neg_peak_time == 16)) {
50
                int8_t diff = neg_peak_time - symbol_sample_time;
51
                if ((diff > 0 && diff <= 16) || (diff <= -16)) {
52
                    symbol_sample_time = (symbol_sample_time + 1) & 31;
53
                }
54
                if ((diff < 0 && diff > -16) || (diff > 16)) {
55
                    symbol_sample_time = (symbol_sample_time - 1) & 31;
56
                }
57
                neg_peak_value = 0;
58
                neg_peak_time = 255; //
59
            }
60
61
            time = (time + 1) & 31;
62
        }
63
    }
64
}

von marc (Gast)


Angehängte Dateien:

Lesenswert?

Du warst etwas schneller.
( Aber ich musste zwischendurch das Abendessen kochen ;-) )

Ich habe Dein Wav-File genommen und mit Octave verarbeitet.
Die Phase wird mit der "angle" Funktion getracked. Sie wird mit einem 
Schrittregler auf pi/2 geregelt.

Die Filter hatte ich auch schon als Moving-Average ausgeführt. 
Ursprünglich habe ich die Filterlänge genau auf die Symbollänge 
eingestellt. Das war aber falsch. Die halbe Symbollänge scheint mir das 
Optimum für die Filter zu sein.

1
[Y,FS,BITS]=wavread("bpsk31.wav");
2
psk31_signal=Y(1:20000)';
3
4
% modulation frequency [Hz ]
5
%fcarrier=954;
6
fcarrier=1000;
7
% sample frequency of the system [Hz]
8
fs=FS;
9
% bit rate ( Baud [1/s])
10
baud=31.25;
11
12
bittime=1/baud;
13
symbol_length=bittime*fs;
14
15
%***************************************************
16
% demodulator and phase controller
17
%***************************************************
18
filter_length=round(symbol_length/2);
19
20
% moving averiger filter coeeficients
21
Bma=ones(1,filter_length)/filter_length;
22
23
filtermemory=zeros(1,filter_length-1); 
24
25
fcorrection=0;
26
27
controlFactor=0.0004;
28
29
for n=1:length(psk31_signal),
30
  fcarrier_corrected=fcarrier+fcorrection;
31
32
  signalMixed(n)=psk31_signal(n)*exp(i*2*pi*fcarrier_corrected/fs*n);
33
34
  [signalFiltered(n) filtermemory]=filter(Bma,1,signalMixed(n),filtermemory);
35
  
36
  alpha=angle(signalFiltered(n));
37
  if(alpha>0)  
38
    x=alpha-pi/2;
39
    fcorrection=fcorrection-sign(x)*controlFactor;    
40
  else
41
    x=alpha+pi/2;
42
    fcorrection=fcorrection-sign(x)*controlFactor;
43
  end
44
  fcorr(n)=fcorrection;
45
end
46
47
Bdelay=zeros(1,filter_length);
48
Bdelay(round(filter_length/2))=1;
49
psk31_signal_shifted_and_scaled=filter(Bdelay,1,psk31_signal)/max(psk31_signal);
50
51
plot(psk31_signal_shifted_and_scaled);
52
hold on
53
plot(angle(signalFiltered),'r','LineWidth',2);
54
plot(fcorr,'y','LineWidth',2);
55
56
% plot phase sollwert helper lines
57
plot(ones(1,length(psk31_signal))*pi/2);
58
plot(ones(1,length(psk31_signal))*-pi/2);
59
60
title('blue: psk31 signal    red: detected phase    yellow: carrier frequency correction');

von Bernd K. (prof7bit)


Angehängte Dateien:

Lesenswert?

anbei noch ein bild mit den gesampleten bits

von marc (Gast)


Lesenswert?

>anbei noch ein bild mit den gesampleten bits

Sieht gut aus :-)

Hier gibt es die Code-Tabelle in C, falls Du den Decoder bist zum 
Textempfang weiterprogrammieren willst und keine Lust hast, die Code 
selber einzutippen:

https://github.com/zenmetsu/radioModem/blob/master/psk31.cpp

Ich schätze, dass die Rechenleistung eines Atmega8 für den Dekoder 
ausreichen würde ....

Hast Du einen Weltempfänger, mit dem Du das ganze real ausprobieren 
willst?
Man braucht einen, bei dem man das "obere Seitenband" selektieren kann.

> Der analoge Aufbau sieht so aus daß ich eine wav Datei am PC abspiele
> über die angeschlossenen Brüllwürfel als Schall ausgebe, dann mit einem
> kleinen Electretmikrofon wieder aufnehme, zwei npn-Transistoren in
> Emitterschaltung zum Verstärken und dann direkt in den ADC-Eingang eines
> am USB-Port angeschlossenen stm32nucleo-boards.

Ich hatte versucht, eine mit ""fldigi" erstellte Datei auf dem Tablet 
abzuspielen und mit dem PC zu empfangen, aber es kam fast nur Müll an. 
Die Sendefrequenz lag bei 2.5kHz und war vielleicht zu hoch.

von Marek N. (Gast)


Lesenswert?

Hi,

als idealer Empfänger würde sich doch der Web-SDR eignen, oder?
http://websdr.ewi.utwente.nl:8901/

Beste Grüße, Marek

von Bernd K. (prof7bit)


Lesenswert?

marc schrieb:
> Ich schätze, dass die Rechenleistung eines Atmega8 für den Dekoder
> ausreichen würde ....

Das müsste gehen, das ist auch meine Absicht. Der einzige Grund warum 
ich das  momentan auf dem stm32 laufen habe ist der daß ich den (als 
totaler ARM-Neuling und ehemals eigentlich eher bei AVR zuhause) gerade 
endlich soweit hatte dass ich Timer und ADC benutzen konnte und somit 
quasi schon genau das dafür benötigte Grundgerüst stehen hatte.

Mir schwebt da aber was für nen kleinen AVR vor, womöglich sogar ein 
ATTiny, das werd ich demnächst mal versuchsweise aufbauen. Das ist auch 
der Grund warum ich versucht habe möglichst ohne komplizierte 
Rechenoperationen auszukommen, so wie es jetzt ist hab ich nur noch zwei 
Integer-Multiplikationen pro Millisekunde, und die bring ich bestimmt 
auch noch von 32bit auf 16bit runter.

Gestern hatte ich mal versuchsweise eine tanlock-Loop so ähnlich wie bei 
Dir implementiert um meine Abtastrate auf die Trägerfreguenz 
einzurasten, das hat auch gar nicht mal so übel funktioniert aber als 
ich die Skizze mit der simplifizierten inkohärenten Demodulation gesehen 
habe hab ichs wieder rausgeworfen und muss jetzt nicht mehr über 
Winkelfunktionen auf schwachbrüstigen Mikrocontrollern nachgrübeln ;-)

von Bernd W. (berndwiebus) Benutzerseite


Lesenswert?

Hallo Marek.

Marek N. schrieb:

> als idealer Empfänger würde sich doch der Web-SDR eignen, oder?
> http://websdr.ewi.utwente.nl:8901/

Das geht in der Tat. Weil sich meine Audiokarte streubte, intern etwas, 
was am Ausgang auftaucht im Eingang zu benutzen, habe ich eine 
Sprechkarnitur ausgegraben und das Mikrofon so an den Kopfhörer gebogen, 
dass ich das was ich über den Web-SDR im Kopfhörer höre, über das 
Mikrophon für fldigi zurückspeise. ;O)

Das geht natürlich nur bei Duplex fähigen Audiokarten.

Mit freundlichem Gruß: Bernd Wiebus alias dl1eic
http://www.dl0dg.de

von marc (Gast)


Lesenswert?

>Mir schwebt da aber was für nen kleinen AVR vor, womöglich sogar ein
>ATTiny, das werd ich demnächst mal versuchsweise aufbauen. Das ist auch
>der Grund warum ich versucht habe möglichst ohne komplizierte
>Rechenoperationen auszukommen, so wie es jetzt ist hab ich nur noch zwei
>Integer-Multiplikationen pro Millisekunde, und die bring ich bestimmt
>auch noch von 32bit auf 16bit runter.

Mit einem Attiny könnte es auch gehen, aber der hat ja keinen 
HW-Multiplizierer, was wieder ordentlich Rechenzeit kostet.
Meiner Meinung nach ist es gut, nicht zu sehr zu sparen, damit man nicht 
zuviel Rauschen ins System induziert. Eine hohe Dynamik durch große 
Wortbreiten ist da sicherlich nützlich. Ebenfalls sollte es helfen, den 
ADC mit der vollen Auflösung zu betreiben. Bei den AVRs also mit 10 Bit.

Wenn ich mir die echten Signale aus dem Weltempfänger anschaue, ist es 
schon erstaunlich, aus wie wenig Signal "fldigi" noch etwas herausholen 
kann. Aber wer weis, vielleicht lässt sich auch die Empfangsleistung von 
"fldigi" noch verbessern.

von marc (Gast)


Angehängte Dateien:

Lesenswert?

Vielleicht reicht es für die Phasenregelung aus, einfach den Q-Part auf 
0 zu regeln.

von marc (Gast)


Angehängte Dateien:

Lesenswert?

Nachdem ich ein wenig mit der Carrier-Frequenz herum gespielt habe, 
scheint es doch so zu sein, dass der Regler zum schwingen neigt.
Deshalb habe ich statt der Frequenz einen Phasenregler gebaut. Der ist 
ziemlich stabil und die Phase steht nach kurzer Zeit wie eine "Eins".
Das setzt allerdings einen ziemlich guten Übereinstimmung des 
Sendercarriers mit der Empfangsmodulationsfrequenz voraus.
1
[Y,FS,BITS]=wavread("bpsk31.wav");
2
psk31_signal=Y(1:20000)';
3
4
% modulation frequency [Hz ]
5
6
fcarrier=1000;
7
% introduce some carrier mismatch for robustness test
8
carrier_error_percent=0;
9
fcarrier=fcarrier*(1+carrier_error_percent/100);
10
11
% sample frequency of the system [Hz]
12
fs=FS;
13
% bit rate ( Baud [1/s])
14
baud=31.25;
15
16
bittime=1/baud;
17
symbol_length=bittime*fs;
18
19
%***************************************************
20
% demodulator and phase controller
21
%***************************************************
22
filter_length=round(symbol_length/2);
23
24
% moving averiger filter coeeficients
25
Bma=ones(1,filter_length)/filter_length;
26
27
filtermemory=zeros(1,filter_length-1); 
28
29
phase_correction=0;
30
31
controlFactor=0.0004;
32
33
for n=1:length(psk31_signal),
34
35
  signalMixed(n)=psk31_signal(n)*exp(i*2*pi*fcarrier/fs*n)*exp(i*phase_correction);
36
37
  % moving average filter
38
  [signalFiltered(n) filtermemory]=filter(Bma,1,signalMixed(n),filtermemory);
39
  
40
  alpha=angle(signalFiltered(n));
41
42
  if(alpha>0)  
43
    x=alpha-pi/2;
44
    phase_correction=phase_correction-sign(x)*controlFactor;    
45
  else
46
    x=alpha+pi/2;
47
    phase_correction=phase_correction-sign(x)*controlFactor;
48
  end
49
50
  % fcorr just to visuallize the phase adatpion
51
  fcorr(n)=phase_correction;
52
end
53
54
Bdelay=zeros(1,filter_length);
55
Bdelay(round(filter_length/2))=1;
56
psk31_signal_shifted_and_scaled=filter(Bdelay,1,psk31_signal)/max(psk31_signal);
57
58
hold off
59
plot(psk31_signal_shifted_and_scaled);
60
hold on
61
plot(angle(signalFiltered),'r','LineWidth',2);
62
plot(fcorr,'y','LineWidth',2);
63
64
% plot phase sollwert helper lines
65
plot(ones(1,length(psk31_signal))*pi/2);
66
plot(ones(1,length(psk31_signal))*-pi/2);
67
68
title('blue: psk31 signal    red: detected phase    yellow: phase correction');

von Gerrit B. (gbuhe)


Lesenswert?

Hallo Marc und Bernd,

ich bin sehr begeistert von Euern Aktivitäten.

Eine bewährte Vorgehensweise ist tatsächlich die numerische Simulation 
auf dem PC (Matlab/Scilab/Octave), um komfortabel an alle Signale im 
Zeit- und Frequenzbereich heran zukommen und die Gesamtaufgabe richtig 
zu verstehen/durchdringen. Hier sollte zu Beginn ruhig noch alles mit 
der hohen numerischen Auflösung und z.B. den "eingebauten" 
trigonometrischen Funktionen berechnet werden.
Die Bewertung der entwickleten Signalverarbeitung kann dann anhand von 
Bitfehlerraten (BER) über Signal-zu-Rausch-Verhältnissen (SNR) erfolgen. 
Ziel ist es natürlich, so nah wie möglich an die theoretische BER-Kurve 
zu kommen, die man aber nie ganz erreichen kann (z.B. wird man keine 
unendlich langen RRC-Filter einsetzen).
Wenn das Ergebnis gut ist, können nun die einzelnen Funktionsblöcke 
durch implementierungfreundlichere Algorithmen ersetzt werden. Nun kann 
man anhand der BER-Kurven die Implementierungsverluste abschätzen die in 
dB SNR angegeben werden. Benötigt man z.B. 3dB mehr SNR für eine 
gegebene BER (BER-Kurve 3dB verschoben), dann sind diese 3dB genau der 
Implementierungsverlust. Auf diese Weise können die verschiedenen 
Vereinfachungen genau bewertet werden. Es gibt dabei oft Überraschungen, 
wenn z.B. ein viel einfacherer Algorithmus eine bessere Performance 
offenbart als manch ein komplizierter.
Im vorletzten Schritt kann man sogar die Quantisierung der Abtastwerte 
in allen Funktionsblöcken nachstellen und damit auf eine Bit-genaue 
Implementierung zur Mikrocontroller/DSP-Lösung kommen.
Der letzte Schritt ist natürlich die Implementierung auf der 
Ziel-Hardware. Da man das Verhalten der Algorithmen nun schon sehr gut 
kennt, fallen einem Abweichungen beim Debuggen sehr schnell auf und 
diese sind dann genauso schnell behoben. Sind Veränderungen in der 
Implementierung nötig, sollten sie zuerst auch in die Simulation 
aufgenommen werden, um die Auswirkungen (Verluste) beurteilen zu können.
Es ist ebenfalls möglich und gute Praxis, Abtastwerte aus der 
Implementierung in die Simulation zu übertragen und genauso Daten aus 
der Simulation in die Hardware für die Verifikation verschiedener 
Abschnitte oder der ganzen Verarbeitungskette zu laden (via 
Debug-Puffer).

Soviel zur "best practise" zum Thema. Vielleicht findet Ihr die eine 
oder andere Anregung darin. Viele Wege führen nach Rom! ;o)

Weiterhin viel Erfolg!

Gerrit, DL9GFA

von marc (Gast)


Angehängte Dateien:

Lesenswert?

>Eine bewährte Vorgehensweise ist tatsächlich die numerische Simulation
>auf dem PC (Matlab/Scilab/Octave), um komfortabel an alle Signale im
>Zeit- und Frequenzbereich heran zukommen und die Gesamtaufgabe richtig
>zu verstehen/durchdringen. Hier sollte zu Beginn ruhig noch alles mit
>der hohen numerischen Auflösung und z.B. den "eingebauten"
>trigonometrischen Funktionen berechnet werden.

Das sehe ich ganz genau so und mache es auch schon länger. Da jetzt 
gerade Jahreswechsel ist habe ich etwas Zeit und es macht Spaß, sich mal 
mit praktischer Signalverarbeitung zu befassen. Ausserdem kann ich ja 
auch noch was lernen.

Ich finde es beeindruckend, das Bernd so minimalistisch gute Ergebnisse 
erzielen kann. Bin mal gespannt, wie weit er kommt.
Ich weis noch nicht wie viel Zeit ich für dieses Projekt habe, da es 
aber schon 5 Jahre her ist ( wie man aus dem Start-Posting sieht) kann 
ich ja zur Not auch in 5 Jahren damit weitermachen. Dann sind die AVRs 
wahrscheinlich ganz obsolet und die Rechenpower der ARMs ermöglicht 100 
Kanäle gleicheitig.

Hier ein Rauschmodell. Ich hoffe, ich habe die Signalamplitude aus der 
SNR richtig berechnet. Die Phasenerkennung scheint auch bei -15dB noch 
gut zu funktionieren, das Singal kann man akustisch im Rauschen nicht 
mehr hören.
1
% indroduce Noise for robustness test
2
SNR=-15 % DB
3
4
signalPower=sum(psk31_signal_raw.*psk31_signal_raw)/length(psk31_signal_raw);
5
noiseAmplitude=sqrt(signalPower)/power(10,SNR/20)
6
noise=(rand(1,length(psk31_signal_raw))*2-1)*noiseAmplitude;
7
8
psk31_signal=psk31_signal_raw+noise;

von marc (Gast)


Angehängte Dateien:

Lesenswert?

Hier das gefilterte Signal hinter dem Moving-Average-Filter.
Wie man sieht, wird der Realteil bei korrekter Phase zu Null. Damit 
sollte es ausreichen, den Realteil zur Regelung zu verwernden.

von marc (Gast)


Angehängte Dateien:

Lesenswert?

Es scheint tatsächlich zu funktionieren. Man braucht keine 
zeitaufwendige Winkelberechnung. Die getrennte Betrachtung der I- und Q- 
Anteile reicht aus. Damit entallen auch die Multiplikationen zur 
Betragsbildung von Bernd.

Die rote Kurve im Bild zeigt den Realteil des gefilterten Signals.
1
....
2
3
phase_correction=0;
4
5
controlFactor=0.0004;
6
7
for n=1:length(psk31_signal),
8
9
  signalMixed(n)=psk31_signal(n)*exp(i*2*pi*fcarrier/fs*n)*exp(i*phase_correction);
10
11
  % moving average filter
12
  [signalFiltered(n) filtermemory]=filter(Bma,1,signalMixed(n),filtermemory);
13
  
14
  qpart=real(signalFiltered(n));
15
  ipart=imag(signalFiltered(n));
16
17
  if qpart>0,
18
    phase_correction=phase_correction+sign(ipart)*controlFactor;
19
  else
20
    phase_correction=phase_correction-sign(ipart)*controlFactor;
21
  end
22
23
  % fcorr just to visuallize the phase adatpion
24
  fcorr(n)=phase_correction;
25
end
26
27
...

von Bernd K. (prof7bit)


Lesenswert?

marc schrieb:
> Es scheint tatsächlich zu funktionieren. Man braucht keine
> zeitaufwendige Winkelberechnung. Die getrennte Betrachtung der I- und Q-
> Anteile reicht aus. Damit entallen auch die Multiplikationen zur
> Betragsbildung von Bernd.

Aber wie verhält es sich dann wenn die Amplitude schwankt? Ich habe 
versuchsweise mal eine PLL mit
1
           int32_t phase_error = Q * (I > 0 ? 1 : -1);

implementiert und dann mit P-Filter (als auch testweise mal mit 
PI-Filter) zur Nachregelung der Mischfrequenz implementiert, es geht im 
Prinzip ganz gut, jedoch hängt dann die Stabilität ganz erheblich von 
der Amplitude des Signals ab: ist sie zu niedrig fängt er die Frequenz 
nicht vernünftig, ist sie zu hoch gibt es heftige Regelschwingungen. 
Also komm ich um mindestens eine Multiplikation zwecks Pegelregelung 
doch nicht herum.

sodann hab ich es zum direkten Vergleich noch mal mit
1
            int16_t a = atan2(Q, I) * 180 / PI;
2
            int16_t phase_error = a;
3
            if (phase_error > 90) {
4
                phase_error -= 180;
5
            }
6
            if (phase_error < -90) {
7
                phase_error += 180;
8
            }
Und das war außerordentlich stabil! Auch der Fangbereich war viel weiter 
und es war wirklich sehr gutmütig zu dimensionieren und weitaus 
stabiler. Jedoch bringt mich das wieder zurück zum Problem der 
Arkustangens-Berechnung.

Leider hat sich gezeigt daß ich mit meiner gestrigen Implementierung 
ohne PLL nicht mehr als etwa +-3Hz abweichen darf, bei +-7Hz hat das 
verzögerte Signal das ich als Referenz verwende bereits eine Drehung von 
90° und bei +-15Hz bereits 180°. Das bedeutet ich kann das Web-SDR nicht 
gut als Empfänger verwenden, dort kann ich nur in 30Hz-Schritten 
abstimmen :-(

Ich werde jetzt aber erstmal noch den letzten Schritt gehen und 
ausgehend von meinem Stand von gestern Abend mal die Decodierung der 
Daten implementieren, so daß es überhaupt mal ein paar Lebenszeichen von 
sich gibt.

@Gerrit: Es leuchtet mir ein daß eine systematische Vorgehensweise wie 
Du sie empfiehlst wahrscheinlich der bessere Weg ist, jedoch muss ich 
mir da zunächst noch etwas mehr Theorie und Praxis im Umgang mit 
Werkzeugen wie Octave zulegen und auch in die Mathematik der 
Signalverarbeitung tiefer einsteigen. Vielleicht nehm ich das zum Anlass 
mal bei Gelegenheit das was ich hier so pi-mal-Daumen implementiert habe 
in Octave nachzustellen um tiefere Erkenntnisse über das Verhalten und 
die Eigenschaften meines "Quick & Dirty"-Demodulators zu gewinnen ;-)

: Bearbeitet durch User
von marc (Gast)


Angehängte Dateien:

Lesenswert?

>Aber wie verhält es sich dann wenn die Amplitude schwankt? Ich habe
>versuchsweise mal eine PLL mit

Getestet habe ich es nur mit -15dB SNR. Die Rausamplitude ist damit 
knapp 6 Mal stärker als die Signalamplidude und man kann das Signal 
nicht mehr erkennen.
Ich könnte mir vorstellen, dass ein Amplitudenschwankung gar nicht so 
viel ausmacht, weil ich ja nur auf großer/kleiner Null regle:
1
  qpart=real(signalFiltered(n));
2
  ipart=imag(signalFiltered(n));
3
4
  if qpart>0,
5
    phase_correction=phase_correction+sign(ipart)*controlFactor;
6
  else
7
    phase_correction=phase_correction-sign(ipart)*controlFactor;
8
  end

von marc (Gast)


Angehängte Dateien:

Lesenswert?

Nochmal ...
Hier das Richtige.
( Falls ein Moderator mitliest: bitte den letzen Post löschen ).

von Matthias (Gast)


Lesenswert?

@marc:
I ist normalerweise doch der Realteil!

psk31 basiert auf BPSK. Das macht dann auch Sinn, dass es geht, weil bei 
180º ist eh nur der Realteil wichtig. Also dein 'q'.

Eventuell kann Gerrit was sagen dazu, weil ich bin da auch nicht so fit.

von marc (Gast)


Lesenswert?

>I ist normalerweise doch der Realteil!

Tja, ich befürchte Du hast Recht. Ich habe mir immer I wie "imaginär" 
gemerkt.

Aber:

 I für In-phase component und Q für Quadrature Component
( aus http://de.wikipedia.org/wiki/Quadraturamplitudenmodulation )

Da muss ich wohl alles umbenennen ....

von Bernd K. (prof7bit)


Angehängte Dateien:

Lesenswert?

So, hab dann mal das Decodieren implementiert:
1
#include <stdio.h>
2
#include <stdlib.h>
3
#include <stdbool.h>
4
#include "stm32f4xx_hal.h"
5
#include "stm32f401xe.h"
6
#include <stm32f4xx_hal_rcc.h>
7
#include <itoa.h>
8
#include <board.h>
9
#include <math.h>
10
11
#define PI              3.14159265358979323846
12
13
#define BUF_PERIODS     32
14
#define BUF_SIZE        4 * BUF_PERIODS
15
16
uint16_t PSK_TO_PSK_IDX[128] = {
17
    0b1,
18
    0b11,
19
    0b101,
20
    0b111,
21
    0b1011,
22
    0b1101,
23
    0b1111,
24
    0b10101,
25
    0b10111,
26
    0b11011,
27
    0b11101,
28
    0b11111,
29
    0b101011,
30
    0b101101,
31
    0b101111,
32
    0b110101,
33
    0b110111,
34
    0b111011,
35
    0b111101,
36
    0b111111,
37
    0b1010101,
38
    0b1010111,
39
    0b1011011,
40
    0b1011101,
41
    0b1011111,
42
    0b1101011,
43
    0b1101101,
44
    0b1101111,
45
    0b1110101,
46
    0b1110111,
47
    0b1111011,
48
    0b1111101,
49
    0b1111111,
50
    0b10101011,
51
    0b10101101,
52
    0b10101111,
53
    0b10110101,
54
    0b10110111,
55
    0b10111011,
56
    0b10111101,
57
    0b10111111,
58
    0b11010101,
59
    0b11010111,
60
    0b11011011,
61
    0b11011101,
62
    0b11011111,
63
    0b11101011,
64
    0b11101101,
65
    0b11101111,
66
    0b11110101,
67
    0b11110111,
68
    0b11111011,
69
    0b11111101,
70
    0b11111111,
71
    0b101010101,
72
    0b101010111,
73
    0b101011011,
74
    0b101011101,
75
    0b101011111,
76
    0b101101011,
77
    0b101101101,
78
    0b101101111,
79
    0b101110101,
80
    0b101110111,
81
    0b101111011,
82
    0b101111101,
83
    0b101111111,
84
    0b110101011,
85
    0b110101101,
86
    0b110101111,
87
    0b110110101,
88
    0b110110111,
89
    0b110111011,
90
    0b110111101,
91
    0b110111111,
92
    0b111010101,
93
    0b111010111,
94
    0b111011011,
95
    0b111011101,
96
    0b111011111,
97
    0b111101011,
98
    0b111101101,
99
    0b111101111,
100
    0b111110101,
101
    0b111110111,
102
    0b111111011,
103
    0b111111101,
104
    0b111111111,
105
    0b1010101011,
106
    0b1010101101,
107
    0b1010101111,
108
    0b1010110101,
109
    0b1010110111,
110
    0b1010111011,
111
    0b1010111101,
112
    0b1010111111,
113
    0b1011010101,
114
    0b1011010111,
115
    0b1011011011,
116
    0b1011011101,
117
    0b1011011111,
118
    0b1011101011,
119
    0b1011101101,
120
    0b1011101111,
121
    0b1011110101,
122
    0b1011110111,
123
    0b1011111011,
124
    0b1011111101,
125
    0b1011111111,
126
    0b1101010101,
127
    0b1101010111,
128
    0b1101011011,
129
    0b1101011101,
130
    0b1101011111,
131
    0b1101101011,
132
    0b1101101101,
133
    0b1101101111,
134
    0b1101110101,
135
    0b1101110111,
136
    0b1101111011,
137
    0b1101111101,
138
    0b1101111111,
139
    0b1110101011,
140
    0b1110101101,
141
    0b1110101111,
142
    0b1110110101,
143
    0b1110110111,
144
    0b1110111011
145
};
146
147
uint16_t PSK_IDX_TO_ASCII[128] = {
148
    0x20, // SP
149
    0x65, // 'e'
150
    0x74, // 't'
151
    0x6f, // 'o'
152
    0x61, // 'a'
153
    0x69, // 'i'
154
    0x6e, // 'n'
155
    0x72, // 'r'
156
    0x73, // 's'
157
    0x6c, // 'l'
158
    0x0a, // LF
159
    0x0d, // CR
160
    0x68, // 'h'
161
    0x64, // 'd'
162
    0x63, // 'c'
163
    0x2d, // '-'
164
    0x75, //HD_low_u,
165
    0x6d, //HD_low_m,
166
    0x66, //HD_low_f,
167
    0x70, //HD_low_p,
168
    0x3d, //HD_equals,
169
    0x2e, //HD_period,
170
    0x67, //HD_low_g,
171
    0x79, //HD_low_y,
172
    0x62, //HD_low_b,
173
    0x77, //HD_low_w,
174
    0x54, //HD_cap_T,
175
    0x53, //HD_cap_S,
176
    0x2c, //HD_comma,
177
    0x45, //HD_cap_E,
178
    0x76, //HD_low_v,
179
    0x41, //HD_cap_A,
180
    0x49, //HD_cap_I,
181
    0x4f, //HD_cap_O,
182
    0x43, //HD_cap_C,
183
    0x52, //HD_cap_R,
184
    0x44, //HD_cap_D,
185
    0x30, //HD_zero,
186
    0x4d, //HD_cap_M,
187
    0x31, //HD_one,
188
    0x6b, //HD_low_k,
189
    0x50, //HD_cap_P,
190
    0x4c, //HD_cap_L,
191
    0x46, //HD_cap_F,
192
    0x4e, //HD_cap_N,
193
    0x78, //HD_low_x,
194
    0x42, //HD_cap_B,
195
    0x32, //HD_two,
196
    0x09, // HT Tab
197
    0x3a, //HD_colon,
198
    0x29, //HD_rightparenthesis,
199
    0x28, //HD_leftparenthesis,
200
    0x47, //HD_cap_G,
201
    0x33, //HD_three,
202
    0x48, //HD_cap_H,
203
    0x55, //HD_cap_U,
204
    0x35, //HD_five,
205
    0x57, //HD_cap_W,
206
    0x22, //HD_doublequote,
207
    0x36, //HD_six,
208
    0x5f, //HD_underscore,
209
    0x2a, //HD_multiply,
210
    0x58, //HD_cap_X,
211
    0x34, //HD_four,
212
    0x59, //HD_cap_Y,
213
    0x4b, //HD_cap_K,
214
    0x27, //HD_apostrophe,
215
    0x38, //HD_eight,
216
    0x37, //HD_seven,
217
    0x2f, //HD_divide, ///
218
    0x56, //HD_cap_V,
219
    0x39, //HD_nine,
220
    0x7c, // '|'
221
    0x3b, //HD_semicolon,
222
    0x71, //HD_low_q,
223
    0x7a, //HD_low_z,
224
    0x3e, //HD_greaterthan,
225
    0x24, //HD_dollar,
226
    0x51, //HD_cap_Q,
227
    0x2b, //HD_add,
228
    0x6a, //HD_low_j,
229
    0x3c, //HD_lessthan,
230
    0x5c, // '\'
231
    0x23, //HD_pound,
232
    0x5b, //HD_leftbracket,
233
    0x5d, //HD_rightbracket,
234
    0x4A, //HD_cap_J,
235
    0x21, //HD_exclamation,
236
    0x00, // NUL
237
    0x5A, //HD_cap_Z, 1010101101
238
    0x3f, //HD_question,
239
    0x7d, //HD_rightcurlybracket,
240
    0x7b, //HD_leftcurlybracket,
241
    0x26, //HD_and,
242
    0x40, //HD_at,
243
    0x5e, //HD_power,
244
    0x25, //HD_percent,
245
    0x7e, // '~'
246
    0x01, // SOH
247
    0x0c, // FF
248
    0x60, // '`'
249
    0x04, // EOT
250
    0x02, // STX
251
    0x06, // ACK
252
    0x11, // DC1
253
    0x10, // DLE
254
    0x1e, // RS
255
    0x07, // BEL
256
    0x08, // BS
257
    0x1b, // ESC
258
    0x17, // ETB
259
    0x14, // DC4
260
    0x1c, // FS
261
    0x05, // ENQ
262
    0x15, // NAK
263
    0x16, // SYN
264
    0x0b, // VT
265
    0x0e, // SO
266
    0x03, // ETX
267
    0x18, // CAN
268
    0x19, // EM
269
    0x1f, // US
270
    0x0f, // SI
271
    0x12, // DC2
272
    0x13, // DC3
273
    0x7f, // DEL
274
    0x1a, // SUB
275
    0x1d, // GS
276
};
277
278
int32_t buffer[BUF_SIZE];
279
uint16_t buffer_ptr = 0;
280
int32_t I = 0;
281
int32_t Q = 0;
282
uint8_t phase = 0;
283
284
uint16_t cnt = 100;
285
volatile bool have_sample = false;
286
287
int32_t smooth = 0;
288
289
int32_t delay_I[32];
290
int32_t delay_Q[32];
291
uint8_t delay_ptr = 0;
292
293
void process_word(uint16_t word) {
294
    for (uint8_t i=0; i<128; i++) {
295
        if (word == PSK_TO_PSK_IDX[i]) {
296
            char c = PSK_IDX_TO_ASCII[i];
297
            uart_send_8(c);
298
        }
299
    }
300
}
301
302
void decode_bit(bool bit) {
303
    static bool started = false;
304
    static uint16_t word = 0;
305
    if (bit) {
306
        started = true;
307
        word = (word << 1) | 1;
308
    } else {
309
        if (started) {
310
            word <<= 1;
311
            if ((word & 3) == 0) {
312
                word >>= 2;
313
                process_word(word);
314
                word = 0;
315
                started = false;
316
            }
317
        }
318
    }
319
}
320
321
int main(void) {
322
    init_board();
323
324
    for (uint16_t i=0; i<BUF_SIZE; i++) {
325
        buffer[i] = 0;
326
    }
327
328
    uint32_t period_0 = TIM2->ARR;
329
    int16_t period_tune_p = 0;
330
    int32_t period_tune_i = 0;
331
332
    int32_t neg_peak_value;
333
    uint8_t neg_peak_time;
334
    uint8_t symbol_sample_time = 16;
335
    uint8_t time = 0;
336
337
    int32_t phase_error_slow;
338
    int32_t phase_error_d;
339
340
    int16_t x = 0;
341
    int16_t t = 0;
342
343
    while (1) {
344
        if (have_sample) {
345
            have_sample = false;
346
347
            // PLL
348
            int16_t a = atan2(Q, I) * 180 / PI;
349
            int16_t phase_error = a;
350
            if (phase_error > 90) {
351
                phase_error -= 180;
352
            }
353
            if (phase_error < -90) {
354
                phase_error += 180;
355
            }
356
            phase_error_slow = (phase_error_slow * 15 + phase_error) / 16;
357
            phase_error_d = phase_error - phase_error_slow;
358
359
            period_tune_p = phase_error * 4;
360
361
            TIM2->ARR = period_0 + period_tune_p;
362
363
364
            int32_t previous_I = delay_I[delay_ptr];
365
            int32_t previous_Q = delay_Q[delay_ptr];
366
            delay_I[delay_ptr] = I;
367
            delay_Q[delay_ptr] = Q;
368
            delay_ptr = (delay_ptr + 1) & 31;
369
370
            // scalar product with delayed sample
371
            int32_t prod = I * previous_I + Q * previous_Q;
372
373
            if (time == symbol_sample_time) {
374
                t = -200;
375
                if (prod > 0) {
376
                    x = 100;
377
                    decode_bit(true);
378
                } else {
379
                    x = 0;
380
                    decode_bit(false);
381
                }
382
            } else {
383
                t = -100;
384
            }
385
386
387
            //uart_send_16(prod >> 10);
388
            //uart_send_16(x);
389
            //uart_send_16(t);
390
391
            if (prod < 0 && prod < neg_peak_value) {
392
                neg_peak_value = prod;
393
                neg_peak_time = time;
394
            }
395
396
            // the symbol sampling clock is accurate (because we
397
            // have a crystal oscillator) but we must correct its
398
            // phase so that it coincides with the negative peaks.
399
            // We do this adjustment 16 ms after each negative peak.
400
            if ((time - neg_peak_time == 16) || (time + 32 - neg_peak_time == 16)) {
401
                int8_t diff = neg_peak_time - symbol_sample_time;
402
                if ((diff > 0 && diff <= 16) || (diff <= -16)) {
403
                    symbol_sample_time = (symbol_sample_time + 1) & 31;
404
                }
405
                if ((diff < 0 && diff > -16) || (diff > 16)) {
406
                    symbol_sample_time = (symbol_sample_time - 1) & 31;
407
                }
408
                neg_peak_value = 0;
409
                neg_peak_time = 255; //
410
            }
411
412
            if (I + Q > 3000) {
413
                HAL_GPIO_WritePin(PORT(LED_GREEN), PIN(LED_GREEN), 1);
414
            } else {
415
                HAL_GPIO_WritePin(PORT(LED_GREEN), PIN(LED_GREEN), 0);
416
            }
417
418
            time = (time + 1) & 31;
419
        }
420
    }
421
}
422
423
424
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc) {
425
    int32_t value = HAL_ADC_GetValue(hadc);
426
    int32_t old = buffer[buffer_ptr];
427
    buffer[buffer_ptr] = value;
428
    if (++buffer_ptr == BUF_SIZE) {
429
        buffer_ptr = 0;
430
    }
431
432
    if (phase == 0) {
433
        I -= old;
434
        I += value;
435
    } else if (phase == 1) {
436
        Q -= old;
437
        Q += value;
438
    } else if (phase == 2) {
439
        I += old;
440
        I -= value;
441
    } else {
442
        Q += old;
443
        Q -= value;
444
        have_sample = true;
445
    }
446
    phase = (phase + 1) & 3;
447
448
    if (phase & 1) {
449
        HAL_GPIO_TogglePin(PORT(D12), PIN(D12));
450
    }
451
452
}

von marc (Gast)


Lesenswert?

Hey, das sieht ja sehr gut aus. Woher hast die Empfangsdaten?

Ich habe mal Web-SDR ausprobiert, aber es gibt immer Unterbrechungen und 
bei 14070 MHz gar kein Empfangssignal.

Was mir bei Deinem "Direktmischer" auffällt: bei 4kHz ADC-Frequenz wird 
jeder der beiden IQ-Kanäle nur mit 2kHt abgetastet. Ist das richtig?

von Bernd K. (prof7bit)


Lesenswert?

marc schrieb:
> Hey, das sieht ja sehr gut aus. Woher hast die Empfangsdaten?

Ich hab hab einfach das Mikrofon (+ zweistufiger Verstärker + 
STM32-Evaluation-Board) vor die PC-Lautsprecher gehalten (bis die Frau 
sich über das nervige Gefiepe beschwert hat) während ich im Web-SDR 
versucht habe so abzustimmen dass ich einen der Träger genau auf 1kHz 
bekomme (das ist gar nicht so leicht denn man kann dort nur in 
30Hz-Schritten abstimmen und das ist viel zu grob für meinen engen 
Filter und ich muss die Frequenz auf +-3Hz genau treffen, da muss ich 
mir noch was besseres überlegen)

>
> Ich habe mal Web-SDR ausprobiert, aber es gibt immer Unterbrechungen und
> bei 14070 MHz gar kein Empfangssignal.

Ja, gestern hats den ganzen Abend lang übel gestottert, das hat 
angefangen genau in dem Moment als ich fertig war und es ausprobieren 
wollte, das ist nicht immer so, normalerweise geht das besser.

> Was mir bei Deinem "Direktmischer" auffällt: bei 4kHz ADC-Frequenz wird
> jeder der beiden IQ-Kanäle nur mit 2kHt abgetastet. Ist das richtig?

Ja, das ist der Trick dabei, so muss ich nicht multiplizieren, die 
Koeffizienten sind abwechselnd 1 und -1. Was ich da eigentlich mache ist 
eine DFT über 32 Perioden für nur eine einzige Frequenz mit einem 
gleitenden Rechteckfenster. Oder ein anderer Weg es zu sehen ist ich 
korreliere (falte? mische?) das Signal mit einem Sinus (und einem 
Cosinus) von genau der selben Frequenz und raus kommen zwei Zahlen (die 
konstant wären wenn ich die Frequenz eines unmodulierten Trägers genau 
treffen würde), das Basisbandsignal kommt da direkt raus.

Das wirkt auch wie ein Filter und bei plusminus 15Hz ist die erste 
Nullstelle. Diese Anordnung ist mir eingefallen als mal jemand irgendwo 
im Forum erwähnte er habe in grauer Vorzeit mal ein Modem gebaut bei dem 
er durch geschickt gewählte Abtastfrequenz nur Koeffizienten in der Art 
von -1, 0, 1, 0 in seinen Filtern brauchte und es habe wunderbar 
funktioniert.

Ich weiß nicht ob diese Art von Anordnung (Filter und Mischer in einem) 
einen speziellen Namen hat, es hat zwei um 90° verschobene FIR-Filter 
mit Koeffizienten 1,-1,1,-1,... und es mischt das 1kHz Empfangssignal 
mit 1kHz Sinus und 1kHz Cosinus und heraus kommt direkt das Basisband. 
Es ist also gleichzeitig auch ein Direktmischer.

Mir ist übrigens aufgefallen daß man damit auch Unterabtastung machen 
kann wenn man bestimmte ganzzahlige Verhältnisse von Sample- und 
Abtastfrequenz trifft, zum Beispiel f_signal/f_sample = 3/4 (und noch 
andere, z.B. 5/4), das sind dann Spiegelfrequenzen von f_signal und 
f_abtast/2, mein Demodulator funktioniert also auch wenn ich ihm 3kHz 
oder 5kHz (und noch viele weitere) an den Eingang füttere. Die erste 
liegt bei 3kHz.

Wenn jemand weiß ob diese spezielle Filter-Mischer-Anordnung einen 
speziellen Namen hat, bitte her damit.

: Bearbeitet durch User
von marc (Gast)


Lesenswert?

>Ich hab hab einfach das Mikrofon (+ zweistufiger Verstärker +
>STM32-Evaluation-Board) vor die PC-Lautsprecher gehalten (bis die Frau
>sich über das nervige Gefiepe beschwert hat)

Haha, so ging es mir auch. Ich konnte das Signal leider immer nur kurz 
abspielen, weil es immer Einspruch gab.

>Ja, das ist der Trick dabei, so muss ich nicht multiplizieren, die
>Koeffizienten sind abwechselnd 1 und -1. Was ich da eigentlich mache ist
>eine DFT über 32 Perioden für nur eine einzige Frequenz mit einem
>gleitenden Rechteckfenster.

Ah, das habe ich übersehen: Es ist einfach Sinus und Cosinus an 4 
Punkten abgetastet. Deshalb ergibt sich eine Sinus und Cosinus Frequenz 
von 1kHz bei 4kHz Abtastrate.

>Oder ein anderer Weg es zu sehen ist ich
>korreliere (falte? mische?)

Es ist ein Mischer:
http://de.wikipedia.org/wiki/Mischer_%28Elektronik%29

Das reelle Empfangssingal wird mit der komplexen Frequenz gemischt d.h. 
multipliziert. Dadurch verschiebt sich das gesuchte Signal auf die 
Frequenz 0 und kann mit dem Tiefpass von den störenden Frequenzen 
getrennt werden.

In Matlab/Octave kann man das in einer Zeile schreiben ( das i ist der 
komplexe Wert ):
1
signalMixed(n)=psk31_signal(n)*exp(i*2*pi*fcarrier/fs*n);

Dein Verfahren ist ziemlich effizient, hat aber eine bestimmten 
Nachteil. Besser wäre es, das Signal mit 32 kHz statt mit 4 kHz 
abzutasten, weil sich dann die Störfrequenzen auf ein breiteres Spektrum 
verteilen. Alle Frequenzanteile über 2kHz, die Dein Anti-Aliasing Filter 
nicht unterdrückt, tauchen als Spiegelfrequenzen und Störung auf.

von chris_ (Gast)


Angehängte Dateien:

Lesenswert?

Hier ein Text to Signal Converter für PSK31 Signale in Octave.
Das Ganze ist ein wenig langsam, aber die Signale werden korrekt 
erzeugt.

von marc (Gast)


Angehängte Dateien:

Lesenswert?

Zum Vergleich habe ich eine Signal mit fs=20kHz und fs=4kHz erzeugt, um 
zu sehen, ob bei 4kHz die Störungen mehr zuschlagen.

Von links nach rechts:

fs=20khz ohne Störung, dann SNR=-15db, dann fs=4kHz mit SNR=-15dB

so richtig viel schlechter scheint das 4kHz Signal nicht zu sein. Liegt 
das vielleicht an meiner Methode? Wahrscheinlich müsste ich das Rauschen 
um den Faktor 5 erhöhen, weil es ja erst dann der Faltung des Rauschens 
in den 4kHz Bereich entspricht.

von Bernd K. (prof7bit)


Angehängte Dateien:

Lesenswert?

marc schrieb:
> Es ist ein Mischer:
> http://de.wikipedia.org/wiki/Mischer_%28Elektronik%29
>
> Das reelle Empfangssingal wird mit der komplexen Frequenz gemischt d.h.
> multipliziert. Dadurch verschiebt sich das gesuchte Signal auf die
> Frequenz 0 und kann mit dem Tiefpass von den störenden Frequenzen
> getrennt werden.
>
> In Matlab/Octave kann man das in einer Zeile schreiben ( das i ist der
> komplexe Wert ):
> signalMixed(n)=psk31_signal(n)*exp(i*2*pi*fcarrier/fs*n);

Das was ich da gebaut habe ist aber auch gleichzeitig ein Filter. Es 
werden immer 32 Perioden aufsummiert. Laut Octave müsste der 
Frequenzgang so aussehen wie im ersten Bild.
1
b = repmat([1,0,-1,0],1,32)
2
freqz(b, 1, 8192, 0, 4000)

Und das was ich messe ist in den zwei anderen Bildern (x-Achse bitte 
ignorieren, das ist die Zeit in Millisekunden, ich hab währenddessen am 
Frequenzgenerator langsam manuell von unten nach oben durchgestimmt, die 
Minima und Maxima liegen aber auf den richtigen Frequenzen, das hab ich 
überprüft), einmal linear, einmal logarithmisch in dB, das Ergebnis 
entspricht also meiner Theorie.

Zum Mischer wird es erst dadurch daß ich nur bei jedem vierten Sample 
den Wert nehme.

Und das ist so weil ich durch die Art und Weise wie ich das 
implementiert habe gar nicht anders kann als nur jedes 4. Sample zu 
nehmen: Anstatt das Signal Sample für Sample durch den Filter 
durchzuschieben und jedesmal neu alle 128 Produkte zu berechnen und 
aufzusummieren addiere ich einfach 4 neu "berechnete" dazu und 
subtrahiere die 4 ältesten, ich schieb es also immer gleich in 4-er 
Schritten durch. Und das wiederum geht aber nur weil alle meine 
Filterkoeffizienten sich alle 4 Samples exakt wiederholen.

: Bearbeitet durch User
von chris_ (Gast)


Lesenswert?

>Zum Mischer wird es erst dadurch daß ich nur bei jedem vierten Sample
>den Wert nehme.

Nicht ganz.

Deine Nullen und Einsen sind exact die Abtastwerte eines Sinus und 
Cosinus wie sie für einen IQ-Mischer benötigt werden:
1
octave:1> n=0:3;
2
octave:2> f=1000;
3
octave:3> fs=4000;
4
octave:4> sin(2*pi*f/fs*n)
5
ans =
6
7
   0.00000   1.00000   0.00000  -1.00000
8
9
octave:5> cos(2*pi*f/fs*n)
10
ans =
11
12
   1.0000   0.00000  -1.0000  0.00000

Du betrachtest die Signal über 32 Stützstellen
1
octave:6> n=0:31;
2
octave:7> sin(2*pi*f/fs*n)
3
ans =
4
5
 Columns 1 through 12:
6
7
   0.00000   1.00000   0.00000  -1.00000  -0.00000   1.00000   0.00000  -1.00000  -0.00000   1.00000   0.00000  -1.00000
8
9
 Columns 13 through 24:
10
11
  -0.00000   1.00000   0.00000  -1.00000  -0.00000   1.00000   0.00000  -1.00000  -0.00000   1.00000   0.00000  -1.00000
12
13
 Columns 25 through 32:
14
15
  -0.00000   1.00000  -0.00000  -1.00000  -0.00000   1.00000   0.00000  -1.00000

Da es sich nur um Einsen und Nullen handelt, kann man die Multiplikation 
vereinfachen, weil

y=x*1 genau y=x entspricht.

bzw.

y=x*-1 genau y=-x

Durch die Summation mit dem Moving Average Filter ergibt sich hargenau 
das Ergebnis einer 32 Punkte DFT an der Stelle 1kHz.

von chris_ (Gast)


Lesenswert?

Dein oben dargestellter Frequenzgang des Filters entspricht der 
Fensterfunktion der DFT
http://de.wikipedia.org/wiki/Fensterfunktion#mediaviewer/File:Fenstereigenschaften.svg

und wird schmaler, wenn Du die Filterlänge des MA erhöhst also z.B. 64 
statt 32 Abtastwerte nimmst. Allerdings geht dann der Vorteil der 
wegfallenden Multiplikationen verloren, da dann die Abtastrate erhöht 
werden muss und 8 statt 4 Stützstellen für Sinus und Cosinus benötigt 
werden.

von Bernd K. (prof7bit)


Lesenswert?

chris_, Du hast Recht :-)

Ich hab mich nur etwas undeutlich ausgedrückt. Irgendwo weiter oben hab 
ich ja auch schon angedeutet daß man das was mein Mischer macht 
eigentlich auch genausogut als DFT bezeichnen könnte. Vom Verständnis 
her ist mir schon klar was da passiert, ich kanns mir auch schön 
veranschaulichen.

Die Frage war nur ob dieser Hack (nur Einsen und Nullen, neue addieren 
und alte subtrahieren um letztlich pro Sample nur noch zwei Additionen 
zu haben anstatt n Multiplikationen und n Additionen) oder wenigstens 
ganz generell die Idee eine DFT (oder diesen Spezialfall der DFT) als 
kombinierten Filter und Mischer zu verwenden einen besonderen Namen hat 
nachdem ich googlen kann um zu sehen was andere damit schon schönes 
gebaut haben.

: Bearbeitet durch User
von Abdul K. (ehydra) Benutzerseite


Lesenswert?

hm. Spezieller Name? Ich kenne das nur unter dem Oberbegriff Sampler. 
Wenn man Stützstellen wegläßt, führt das aber zu einem schlechteren S/N. 
Bzw. bei einer Phasennachregelung zu früheren Regelschwingungen und der 
zunehmenden Tendenz, daß die Chose noch früher aussetzt, also die Phase 
verliert... und dann irgendwann irgendwo irgendwie wieder einrastet...


marc schrieb:
>>Ich hab hab einfach das Mikrofon (+ zweistufiger Verstärker +
>>STM32-Evaluation-Board) vor die PC-Lautsprecher gehalten (bis die Frau
>>sich über das nervige Gefiepe beschwert hat)
>
> Haha, so ging es mir auch. Ich konnte das Signal leider immer nur kurz
> abspielen, weil es immer Einspruch gab.
>

Das muß irgendwas mit frau ansich zu tun haben. Ich kann hier auch von 
mehreren solchen Modellen berichten, die eine geradezu abartige 
Abneigung gegen elektronisches Audio haben. Ich dagegen kann mich an 
solchen Dingen und Motorgeräuschen regelrecht berauschen. Gibt doch nix 
schöneres, als blinkende LEDs, bei denen man weiß warum sie gerade 
blinken, oder?!!


Aber mal was anderes:
Ich mache solche Signalberechnungen immer in LTspice. Leider ist es 
grottelahm, wenn man da einige Bits komplett durch einen Demodulator 
durchackern läßt.
Funzt sowas in Octave usw. besser? Es sind ja immer vielleicht 100 Bits, 
die von einem Träger kommen. Das Ganze dann mehrfach leicht frequenz- 
und phasenversetzt, damit man Bitfehlerraten abschätzen kann.
Also wie lange braucht Octave auf welchem Rechner für welche 
Systembeschreibung?

: Bearbeitet durch User
von chris_ (Gast)


Lesenswert?

> Ich kenne das nur unter dem Oberbegriff Sampler.
> Wenn man Stützstellen wegläßt, führt das aber zu einem schlechteren S/N.

Für die Implementierung von Bernd trifft das aber nicht zu. zwar ist 
jede zweiter Sample beim sinus NUll
1
octave:4> sin(2*pi*f/fs*n)
2
ans =
3
4
   0.00000   1.00000   0.00000  -1.00000

Dafür ist der betrag des cosinus an der gleichen Stell Eins, so dass 
keine Information des Eingangssignals verloren geht.
1
octave:5> cos(2*pi*f/fs*n)
2
ans =
3
4
   1.0000   0.00000  -1.0000  0.00000

Es ist kein "trickreiches" Verfahren wie z.B. die DDS, bei der man 
gewisse Verluste an Genauigkeit in Kauf nimmt, um mit geringem 
Rechenaufwand ein Sinus-Signal zu erzeugen.
Das obige Verfahren ist in dem Sinne "trickreich", dass man das 
Verhältnis von Wunschfrequenz zu Abtastfrequenz so wählt, dass die 
Rechnung besonders einfach wird. Verluste an Genauigkeit gibt es 
gegenüber einem anderen Rechenverfahren nicht, es ist mathematisch 
exakt.

von chris_ (Gast)


Lesenswert?

>Ich mache solche Signalberechnungen immer in LTspice. Leider ist es
>grottelahm,
>...
>Also wie lange braucht Octave auf welchem Rechner für welche
>Systembeschreibung?

Das hängt von der Art der Programmierung ab.
Bei Matlab/Octave sind alle Variablen Vektoren bzw. Matrizen.

Man kann einen Sinus z.B. so berechnen lassen:


for n=1:1000000,
  x(n)=sin(2*pi*1/10*n);
end

dann ist die Berechnung des Sinus relativ langsam, da er Index für Index 
berechnet wird und Octave per "Malloc" für X in jedem Schritt neuen 
Speicher allocieren muss.

Folgende Berechnungsart ist viel schneller:

n=1:1000000;
x=sin(2*pi*1/10*n)

da octave jetzt die interne Vektormultiplikation benutzen kann und auch 
die Speichergröße vor der Berechnung klar ist.

Das obige Octave-Script

http://www.mikrocontroller.net/attachment/242758/OctavePSK31Text2WAV.zip

ist relativ langsam und braucht für die Umwandlung des Textes in das 
Signal auf meinem Rechner 5-10 Sekunden. Allerdings ist das Signal auch 
mehrere 100kB groß und ich habe viel mit Indexberechnungen gearbeitet. 
Bezüglich der Rechenzeit ist da noch einiges an Optimierungspotential.

von Bernd K. (prof7bit)


Angehängte Dateien:

Lesenswert?

wird besser (siehe Bild). Ich glaub an der Art und Weise wie der 
Symboltakt synchronisiert wird kann man noch was drehen, so hab ichs 
jetzt und das Ergebnis ist viel besser als beim ersten Mal:
1
            // scalar product with delayed sample
2
            int32_t prod = I * previous_I + Q * previous_Q;
3
4
            if (time == symbol_sample_time) {
5
                if (prod > 0) {
6
                    decode_bit(true);
7
                } else {
8
                    decode_bit(false);
9
                }
10
            }
11
12
13
14
            /*
15
             * Our symbol sampling clock frequency will be accurate enough
16
             * to hit the right symbol sample time 9 consecutive times in a
17
             * row (because we have a crystal oscillator) but we must correct
18
             * its phase occasionally. We make a slight correction on every
19
             * negative peak (negative peak means there was a phase change)
20
             */
21
22
            // record the exact time of the negative peak
23
            if (prod < neg_peak_value) {
24
                neg_peak_value = prod;
25
                neg_peak_time = time;
26
            }
27
28
            // We do this adjustment after the end of a negative peak.
29
            if (prod >= 0 && neg_peak_value < 0) {
30
                int8_t diff = neg_peak_time - symbol_sample_time;
31
                if ((diff > 0 && diff <= 16) || (diff <= -16)) {
32
                    symbol_sample_time = (symbol_sample_time + 1) & 31;
33
                }
34
                if ((diff < 0 && diff > -16) || (diff > 16)) {
35
                    symbol_sample_time = (symbol_sample_time - 1) & 31;
36
                }
37
                neg_peak_value = 0;
38
            }

Die beiden Stationen aus dem Screenshot kamen übrigens beide zwischen S7 
und S9 (schwankend) rein (laut web-SDR-Anzeige). Ich hab das Signal 
immer noch über den Umweg Lautsprecher+Mikrofon laufen.

von Abdul K. (ehydra) Benutzerseite


Lesenswert?

Danke! Da kann ich ja Octave mit deinen Beispielen einfach mal 
ausprobieren. Offensichtlich kann man mit etwas Mathematikverständnis in 
Octave einfach tiefer und weiter Eingriff nehmen in die Art wie die 
Daten verwaltet werden, als in SPICE möglich ist. Speziell LTspice 
fehlen für sowas einfach ein paar wichtige Funktionen: u.a. Zähler, 
echte Digitalfunktionen im Sinne von Einzelbits, Start und Stop -Flags 
für automatische Aufzeichnung usw. Vielleicht lohnt es sich, speziell 
für solche Sachen nicht mehr LTspice zu benutzen und sich dafür in 
Octave einzuarbeiten.

Wäre es möglich vorerst die Diskussion auf die reine PSK-Demodulation zu 
beschränken? Also ohne den Varicode-Symboldekoder! Dann könnte man die 
Erkenntnisse auch im weiteren Sinne jenseits von speziell PSK31 
gebrauchen.

Kannst du mal das Ergebnis von "Das obige Octave-Script..." als 
Wave-Datei posten?
Hat schonmal jemand untersucht, inwieweit MP3, OGG etc. das Signal 
durchlassen?

von Abdul K. (ehydra) Benutzerseite


Lesenswert?

chris_ schrieb:
>> Ich kenne das nur unter dem Oberbegriff Sampler.
>> Wenn man Stützstellen wegläßt, führt das aber zu einem schlechteren S/N.
>
> Für die Implementierung von Bernd trifft das aber nicht zu. zwar ist
> jede zweiter Sample beim sinus NUll
> ...
> Dafür ist der betrag des cosinus an der gleichen Stell Eins, so dass
> keine Information des Eingangssignals verloren geht.
>
> ...
>
> Es ist kein "trickreiches" Verfahren wie z.B. die DDS, bei der man
> gewisse Verluste an Genauigkeit in Kauf nimmt, um mit geringem
> Rechenaufwand ein Sinus-Signal zu erzeugen.
> Das obige Verfahren ist in dem Sinne "trickreich", dass man das
> Verhältnis von Wunschfrequenz zu Abtastfrequenz so wählt, dass die
> Rechnung besonders einfach wird. Verluste an Genauigkeit gibt es
> gegenüber einem anderen Rechenverfahren nicht, es ist mathematisch
> exakt.

Das bezieht sich doch auf die Phasenlage des lokalen Oszillators im 
Empfänger in Bezug auf die Phasenlage des empfangenen Signals. Wenn nun 
der Oszillator genau äh 90° (??) verschoben ist, so sind sin und cos 
jeweils bei 45° und damit numerisch auf 0,7..
Leistungsmäßig auf 0.5 ! Die Detektionswahrscheinlichkeit wäre dann 
genau 50%. sin und cos werden korreliert, damit sinkt der S/N an dieser 
exakten Stelle um 3dB.
Je nach lokaler Phasenlage (z.B. im Präambel-Suchzeitbereich, wo der 
Empfängeroszillator einrasten [könnte]), 'wabert' also das S/N abwärts 
bis 3dB von Optimum 0dB (Wenn man den theoretischen Detektionsverlust 
von DBPSK hier schon abgezogen hat vom Realwert).

Oder denke ich falsch? Ich hoffe ich habe mich halbwegs verständlich 
gemacht.

Man muß bei solchen Betrachtungen auch immer abwägen zwischen möglichst 
nahe am theoretisch möglichen für eine spezielle Modulationstechnik und 
der Frage wie lange der Demodulator zum Einrasten brauch speziell bei 
Burst-Betrieb (also wenn zeitlich schnell aufeinander diverse 
unterschiedliche Sender zu verkraften sind). Auf einem 'Bussystem' wird 
man eher auf eine kurze Synchronisationszeit Wert legen, um Zeitverluste 
mit Datenmüll zu minimieren. Also die Durchlaß-Sättigungsgrenze des 
Mediums möglichst hoch halten.


Um nochmal auf oben zurückzukommen: Wenn man nun mehr Samples berechnet 
pro komplette Bitzeit, dann werden diese genannten 3dB kleiner. Das wäre 
der Fall von Multiplikation mit 0, -1, +1.
Bei Analogmodulation gibt es natürlich keine Schwankungen der 
Empfangsamplitude auf dem Einheitskreis. Der Radius ist dann immer =1. 
Um das anzunähern, brauch man nur einige wenige Bits 
Amplitudenauflösung. Erkauft sich aber im Umkehrschluß eine zunehmende 
Amplitudenstörungsempfindlichkeit, die ein Komparator (der nur -1 und +1 
liefern kann) nicht hat.
In einem kleinen bestimmten Bereich, gibt es sogar einen 
Detektionsgewinn wenn man einen Komparator benutzt und nicht eine 
volllineare Multiplikation hinlegt.

: Bearbeitet durch User
von Bernd (Gast)


Lesenswert?

Abdul K. schrieb:
> verschoben ist, so sind sin und cos
> jeweils bei 45° und damit numerisch auf 0,7..
> Leistungsmäßig auf 0.5 !

No, Leistungsmäßig zusammen immer noch auf 1:
1
>> sin(pi/4)^2 + cos(pi/4)^2
2
ans =  1
3
>> sin(0)^2 + cos(0)^2
4
ans =  1
5
>> sin(42)^2 + cos(42)^2
6
ans =  1

von Abdul K. (ehydra) Benutzerseite


Lesenswert?

Ich weiß nicht so recht, was ich dazu sagen soll! Bei meinen 
Simulationen haben eigentlich alle stark digital arbeitenden 
Demodulatoren Probleme, wenn die Phasenlage nicht passend ist. Also 
brauch man eine Loop, die die Phase 1. erkennt und 2. nachregelt. Und 
das dann bitte ohne Schwingen - was es extrem kompliziert, denn entweder 
hängt es irgendwann leicht daneben oder fängt an sich zum Oszillator zu 
entwickeln...

Und jede Regelung verzögert die Erkennung eines Datenpakets extrem! Was 
die Präambel automatisch verlängert und damit die Sättigungsgrenze des 
Übertragungskanals verschlechtert.
Phasengeregelte Demodulatoren brauchen typisch 30 bis 100 Bits zum 
Einrasten. Demodulatoren, die komplett asynchron demodulieren können, 
schaffen das in der Zeit von 2 Bits.


Bist du denn mit meinen sonstigen Bemerkungen zufrieden und hast nichts 
einzuwenden?

von Bernd (Gast)


Lesenswert?

Abdul K. schrieb:
> Bei meinen
> Simulationen haben eigentlich alle stark digital arbeitenden
> Demodulatoren Probleme, wenn die Phasenlage nicht passend ist.

Passend zu was? Mein Demodulator vergleicht die Phase mit der Phase von 
einer Symbollänge zuvor. Deshalb spielt die absolute Phasenlage 
überhaupt keine Rolle, einzig die Abweichung der Mischerfrequenz vom 
Träger sollte erheblich kleiner als die Symbolrate sein, so dass es sich 
nicht allzuweit weitergedreht hat zwischen 2 Symbolen.


> Bist du denn mit meinen sonstigen Bemerkungen zufrieden und hast nichts
einzuwenden?

Mir ist noch nicht ganz klar wo der eigentliche Kritikpunkt liegen soll, 
mir ist nicht klar warum Du plötzlich weniger Signal und mehr Rauschen 
hast wenn das Signal um 45° phasenverschoben abgetastet wird, eventuell 
liegt das an der Art wie Dein Demodulator arbeitet, wirfst Du Q weg und 
betrachtest nur I? Meine Demodulator berücksichtigt I und Q 
gleichermaßen, der Betrag dieses Vektors ist bei jeder Phasenlage 
gleich.

Simuliert hab ichs noch nicht (zumindest nicht außerhalb meines Kopfes), 
dazu fehlt mir die Kenntnis von Octave, ich habs stattdessen einfach 
kurzerhand implementiert und ausprobiert, aber vielleicht kannst Du es 
ja mal schnell simulieren und mit Deinen anderen Simulationen 
vergleichen.

von Abdul K. (ehydra) Benutzerseite


Lesenswert?

Bernd schrieb:
> Abdul K. schrieb:
>> Bei meinen
>> Simulationen haben eigentlich alle stark digital arbeitenden
>> Demodulatoren Probleme, wenn die Phasenlage nicht passend ist.
>
> Passend zu was?

Passend zum Symboltakt der Bits die reinkommen, logischerweise.


> Mein Demodulator vergleicht die Phase mit der Phase von
> einer Symbollänge zuvor. Deshalb spielt die absolute Phasenlage
> überhaupt keine Rolle, einzig die Abweichung der Mischerfrequenz vom
> Träger sollte erheblich kleiner als die Symbolrate sein, so dass es sich
> nicht allzuweit weitergedreht hat zwischen 2 Symbolen.
>

Jo, daß ist der Ansatz der DIFFERENTIEAL-BPSK.
Aber hast du deinen Demodulator auch mal länger laufen lassen. 
Irgendwann (eigentlich leicht berechenbar wann) ergibt sich keinerlei 
Amplitude mehr hinter diesem, danach gehts dann wieder aufwärts. Eine 
Schwebung eben.

Eine Korrektur ist also unumgänglich, wenn du einen Demodulator benutzt 
der synchron laufen muß. Darin unterscheidet sich BPSK und DBPSK 
überhaupt nicht.


>
>> Bist du denn mit meinen sonstigen Bemerkungen zufrieden und hast nichts
> einzuwenden?
>
> Mir ist noch nicht ganz klar wo der eigentliche Kritikpunkt liegen soll,

Kritik ist das falsche Wort. Sagen wir mal Einwendungen oder Nachfragen. 
Ich habe gar nichts gegen den Thread!


> mir ist nicht klar warum Du plötzlich weniger Signal und mehr Rauschen
> hast wenn das Signal um 45° phasenverschoben abgetastet wird, eventuell
> liegt das an der Art wie Dein Demodulator arbeitet, wirfst Du Q weg und
> betrachtest nur I? Meine Demodulator berücksichtigt I und Q
> gleichermaßen, der Betrag dieses Vektors ist bei jeder Phasenlage
> gleich.
>

Muß ich mir nochmal ansehen, wenn ich durch Octave besser durchsteige. 
Ich bin gerade bedient von Pfadangaben die keine Leerzeichen haben 
dürfen und c:\octave\ vorgegeben. Aber sonst sieht es gut aus.


> Simuliert hab ichs noch nicht (zumindest nicht außerhalb meines Kopfes),
> dazu fehlt mir die Kenntnis von Octave, ich habs stattdessen einfach
> kurzerhand implementiert und ausprobiert, aber vielleicht kannst Du es
> ja mal schnell simulieren und mit Deinen anderen Simulationen
> vergleichen.

Leider ist schnell nichhh. Deswegen will ich ja Octave in meine 
Werkzeugkiste aufnehmen, wenns besser paßt.


Eigentlich versuche ich nur besser zu verstehen, was einen guten 
Demodulator von einem schlechten unterscheidet. Manches bekomme ich 
intellektuell sauber hin, an anderen Stellen scheitere ich kläglich.
z.B. ist diese irre Frequenzempfindlichkeit (also delta Frequenz 
Sender-Empfänger) bei BPSK mir nicht ganz erklärlich. Das behindert 
diese Modulationsart im praktischen Einsatz massiv. Und wie könnte man 
das deutlich erleichtern? Gibt z.B. den Ansatz, die BPSK nach DBPSK eine 
Stufe weiter zu treiben in dem Sinne von DDBPSK. Das verschlechert zwar 
das S/N, aber relaxt auch die Frequenzempfindlichkeit. Gibt da Papers zu 
im Sat-Bereich. Über D^3(BSPK) fand ich noch nichts. Verstehen tue ich 
es auch nicht richtig.
Wenn man es mathematisch nicht nachts im Bett zerlegen kann, muß man 
tagsüber simulieren ;-)

Also vorran!

von Bernd K. (prof7bit)


Lesenswert?

So, ich habs jetzt mal auf dem ATMega328 implementiert. Diese Variante 
benötigt keine einzige(!) Multiplikation, dafür aber satte 400 Byte RAM:

https://gist.github.com/prof7bit/ea9b272c80182eeaccba

von chris_ (Gast)


Lesenswert?

>So, ich habs jetzt mal auf dem ATMega328 implementiert.

Sehr schön. Das ist ja der gleiche Prozessor wie auf einem Arduino Uno.
Falls sich die Interrupts nicht mit der Arduino-Lib beißen würden, 
könnte man es direkt darauf laufen lassen. Dann wäre es für eine große 
Community verfügbar.

von chris_ (Gast)


Lesenswert?

>Abdul K. schrieb:
>> verschoben ist, so sind sin und cos
>> jeweils bei 45° und damit numerisch auf 0,7..
>> Leistungsmäßig auf 0.5 !

Bernd schrieb:
>No, Leistungsmäßig zusammen immer noch auf 1:

>>> sin(pi/4)^2 + cos(pi/4)^2
>ans =  1
>>> sin(0)^2 + cos(0)^2
>ans =  1
>> sin(42)^2 + cos(42)^2
>ans =  1

Hier die Darstellung in Octave.

Wir erzeugen ein komplexes signal:
1
octave> fs=4000;
2
octave> f=1000;
3
octave> n=0:3
4
n =
5
6
   0   1   2   3
7
8
sig =
9
10
 Columns 1 through 3:
11
12
   1.00000 + 0.00000i   0.00000 + 1.00000i  -1.00000 + 0.00000i
13
14
 Column 4:
15
16
  -0.00000 - 1.00000i

Der Betrag des Signals ist an jeder Stelle 1:
1
octave> abs(sig)
2
ans =
3
4
   1   1   1   1

Und das selbe Signal um pi/4 phasenverschoben:
1
octave:20> sig=exp(i*(2*pi*f/fs*n+pi/4))
2
sig =
3
4
 Columns 1 through 3:
5
6
   0.70711 + 0.70711i  -0.70711 + 0.70711i  -0.70711 - 0.70711i
7
8
 Column 4:
9
10
   0.70711 - 0.70711i

Der Betrag des Signals ist wieder an jeder Stelle 1:
1
octave> abs(sig)
2
ans =
3
4
   1   1   1   1

Die Koeffizienten sind jetzt alle 1/wurzel(2). Die Multiplikation kann 
jetzt nicht mehr eingespart werden. Aber das verschobene Signal bringt 
auch keinen Gewinn an Genauigkeit, deshalb ist Bernd's Methode ohne 
Multiplikation auch völliig ausreichend.

Abdul K. schrieb
>Kannst du mal das Ergebnis von "Das obige Octave-Script..." als
>Wave-Datei posten?
Wenn Du Octave installiert hast, kannst Du obiges Script einfach laufen 
lassen. Die letzte Zeile ist für das Abspeichern des WAV-Files, die habe 
ich auskommentiert.

von Bernd K. (prof7bit)


Angehängte Dateien:

Lesenswert?

chris_ schrieb:
> Sehr schön. Das ist ja der gleiche Prozessor wie auf einem Arduino Uno.
> Falls sich die Interrupts nicht mit der Arduino-Lib beißen würden,

Von der Arduino-lib hab ich keine Ahnung, benutze ich auch nicht, 
allerdings läuft das in der Tat momentan auf der Hardware eines 
Arduino-Uno-Klons, siehe Bild :-)

(Ich hab die Schaltung mal von Steckbrett auf Drahtigel umgebaut, das 
war zu wackelig)

von chris_ (Gast)


Lesenswert?

Hallo Bernd,

eine lustige Drahtigelkonstruktion hast Du da. Manchmal löte ich auch 
Drahtigel, aber ich verwende mittlerweile ganz gerne Erdnuss- oder 
Cashewkerndosen von Aldi als Grundlage. Ich drehe die Dosen mit dem 
Deckelboden nach oben und löte dann die Schaltung oben drauf. Meistens 
klebe ich noch mit doppelseitigem Klebeband kleine Kufpferplatinenstücke 
darauf. Das Ganze steht dann sehr stabil auf dem Tisch.

>Von der Arduino-lib hab ich keine Ahnung,

Bei der Arduino Lib sehe ich den Vorteil, dass man den Code einfach in 
die IDE kopieren kann und dann "downloaden". Bei reinem Code muss man 
erst eine Umgebung aufsetzen.

von Floppy (Gast)


Lesenswert?

Bernd K. schrieb:
> chris_ schrieb:
>> Sehr schön. Das ist ja der gleiche Prozessor wie auf einem Arduino Uno.
>> Falls sich die Interrupts nicht mit der Arduino-Lib beißen würden,
>
> Von der Arduino-lib hab ich keine Ahnung, benutze ich auch nicht,
> allerdings läuft das in der Tat momentan auf der Hardware eines
> Arduino-Uno-Klons, siehe Bild :-)
>
> (Ich hab die Schaltung mal von Steckbrett auf Drahtigel umgebaut, das
> war zu wackelig)

Hallo Bernd,

kannst Du mal die Schaltung skizzieren? Habe auch einen Arduino, würde 
aber gerne mal eine eigene Schaltung aufbauen! An welchem Port hast du 
das Signal angeklemmt?

von Abdul K. (ehydra) Benutzerseite


Lesenswert?

chris_ schrieb:
>>Abdul K. schrieb:
>>> verschoben ist, so sind sin und cos
>>> jeweils bei 45° und damit numerisch auf 0,7..
>>> Leistungsmäßig auf 0.5 !
>
> Bernd schrieb:
>>No, Leistungsmäßig zusammen immer noch auf 1:
>
>>>> sin(pi/4)^2 + cos(pi/4)^2
>>ans =  1
>>>> sin(0)^2 + cos(0)^2
>>ans =  1
>>> sin(42)^2 + cos(42)^2
>>ans =  1
>
> Hier die Darstellung in Octave.
>
> Wir erzeugen ein komplexes signal:
>

Danke für deine Ausführung! Lassen wir das erstmal beiseite. Ich kann 
darauf nicht wirklich sinnvoll eingehen.


> Abdul K. schrieb
>>Kannst du mal das Ergebnis von "Das obige Octave-Script..." als
>>Wave-Datei posten?
> Wenn Du Octave installiert hast, kannst Du obiges Script einfach laufen
> lassen. Die letzte Zeile ist für das Abspeichern des WAV-Files, die habe
> ich auskommentiert.

Jo, habs installiert. Die Version der Spanier UPM R8.2 mit GUI.


Wäre es möglich, die Source oder die fertigen wave-Files von dem 
S/N-Versuch oben zu bekommen?
(Beitrag "Re: PSK 31 Modlulation im Mikrocontroller")
Würde gerne mal das wave auf meinen Demodulator in LTspice loslassen.
Vielleicht ist das irgendwo nun schon gepostet, ich finds aber nicht. 
Der Thread ist schon wieder zu lang geworden.

Also so ne Fehlerrate von 2 Bit falsch in 10 Bit insgesamt fände ich 
interessant zu vergleichen. Klar ist das unrealistisch, besser wäre 
sowas wie 1 Fehler in 100 oder gar 1000 Bits, nur sind dann die 
Simulationszeiten zumindest in LTspice sowas von irrsinnig lang, daß es 
keinen Sinn mehr macht. 1000 Bits bedeutet mehrere Stunden und 
vielleicht 3GByte Daten.
Ich weiß, daß diese Angabe quasi rückwärts ist, denn normalerweise 
definiert man das S/N und erhält dann die Bitfehlerrate, und nicht 
umgekehrt.

Müßte man noch ne sinnvolle Bandbreite fürs Breitbandrauschen sich 
ausdenken. 2,5KHz für einen SSB-Empfänger? Also das wären dann geschätzt 
3,5KHz bis 5KHz Rauschbandbreite für ne weiche Filterkurve des 
Empfängers.

von Bernd K. (prof7bit)


Angehängte Dateien:

Lesenswert?

hab mir heute überlegt was wäre wenn ich einen extrem scharfen 
IIR-Bandpass zur Gewinnung des Symboltaktes verwende anstelle einer PLL.
1
int16_t filter_bandpass_32Hz(int16_t val) {
2
    static int32_t back1 = 0;
3
    static int32_t back2 = 0;
4
    int32_t acc = (int32_t)val << 7;
5
    acc += 32080 * back1;
6
    acc -= 16325 * back2;
7
    back2 = back1;
8
    back1 = acc >> 14;
9
10
    return acc >> 16;
11
}

Zwei von denen hab ich mal testweise hintereinandergeschaltet, Ergebnis 
siehe Bild. Allerdings ist das ziemlich knifflig den richtig 
einzustellen, und ich hab wieder einige Multiplikationen drin. Aber das 
Ergebnis scheint mir um einiges besser! Ich kann jetzt so viel Rauschen 
drüber legen daß ich das Signal nur noch mit sehr viel gutem Willen 
raushören kann, jedoch wird es immer noch fehlerfrei dekodiert. Mit der 
vorherigen Version wars deutlich anfälliger.

von Abdul K. (ehydra) Benutzerseite


Angehängte Dateien:

Lesenswert?

Hier mal Bilder von der Phasenabhängigkeit, die ich oben erwähnte.
Oben mit wenig Rauschen im Signal, unten mit viel. In beiden Sims wird 
die Phase innerhalb 360° alle 20° durchgerechnet. Man sieht schön, wie 
bei meinem Demodulator das S/N von der aktuell verwendeten Phasenlage 
abhängt.

von Bernd K. (prof7bit)


Lesenswert?

Abdul K. schrieb:
> In beiden Sims wird
> die Phase innerhalb 360° alle 20° durchgerechnet. Man sieht schön, wie
> bei meinem Demodulator das S/N von der aktuell verwendeten Phasenlage
> abhängt.

Wo sieht man die Phasenlage? Und die Phase von was relativ zu was 
(weiter oben gings Dir zunächst um die Phasenlage des Trägers (beim 
Samplen und im Mischer), später dann meintest Du plötzlich die 
Phasenlage des Symboltaktes, also welche Phasenlage nun)? Was sieht man 
da überhaupt in den Bildern? Es ist zwar alles schön bunt aber was ist 
was? Es ist nicht gerade selbsterklärend.

von Abdul K. (ehydra) Benutzerseite


Angehängte Dateien:

Lesenswert?

Naja, hast recht. 1. ist es zu wenig Auflösung und 2. weiß ich nicht 
mehr genau was ich tat. Ist schon ein paar Monate her, wo ich das 
Diagramm erzeugte.


Also hab ich die letzte Version nochmal komplett durchrechnen lassen und 
angehängt:

Zeile 1 ist das bandpaßgefilterte Eingangssignal noch mit Träger. Die 
Phasensprünge kann man gut sehen.

Zeile 2 ist das Signal nach dem Demodulator. Die verschiedenen Farben 
sind jeweils ein 20° Step der Phasenlage aus den 360°. Die Phase wird 
nicht nachgeregelt!

Zeile 3 ist das per Komparator digitalisierte Signal von Zeile 2. Hier 
kann man schön die Flankenverschiebung sehen. Wenn die Flanke zu weit 
wegwandert, gibts ein Fehlerbit.

Ansich entspricht die Schaltung dem vorherig geposteten Bild. Ist hier 
nur mit wenig Rauschen am Eingang durchgerechnet.

Nein, die Schaltung werde ich nicht veröffentlichen (Ich halte sie für 
neuartig). Ich würde sie nur gerne leistungsmäßig vergleichen mit euren 
Ideen.

: Bearbeitet durch User
von Bernd K. (prof7bit)


Lesenswert?

Abdul K. schrieb:
> Zeile 1 ist das bandpaßgefilterte Eingangssignal noch mit Träger. Die
> Phasensprünge kann man gut sehen.

Warum ist die Amplitude nicht konstant während der Zeit während der 
"1"-Bits gesendet werden? Während einer Folge zusammenhängender 1-Bits 
soll doch weder die Phase wechseln noch die Amplitude, während dieser 
Zeit sollte da ein unmodulierter Träger stehen.

Ein Schwanken zwischen 100% und 140% könnt ich mir noch erklären wenn Du 
(so wie ich in meinem Code [der zweiten Version, nicht der ersten]) die 
Amplitude nicht über sqrt(I² + Q²) ausrechnest sondern nach 
Manhattan-Metrik abs(I)+abs(Q) und sich die Phasenlage derweil aufgrund 
leicht daneben liegender Frequenz langsam weiterdreht, aber was sollen 
die kompletten Einbrüche bei jedem zweiten Mal?

Und dann ist natürlich schwer zu sagen was dann passiert (und warum) 
wenn Du nicht offenlegst wie Du das Signal dann weiter verarbeitest, wie 
Du von Zeile 1 nach Zeile 2 kommst (oder wie Zeile 1 überhaupt zustande 
kommt, denn das sieht nicht wie ein rohes PSK31-Signal aus, das ist 
schon auf irgendeine Weise irgendwie verändert, ich kann mir aber grad 
beim besten Willen nicht vorstellen wie).

: Bearbeitet durch User
von Abdul K. (ehydra) Benutzerseite


Lesenswert?

Ich hab mich einfach mal auf das RDS gestürzt und daher ist es nicht 
einfach nur DBPSK.
Bei RDS wird das Baseband DBPSK-Signal nochmals biphase auf den Träger 
moduliert. Deswegen ist auf der eigentlichen Trägerfrequenz keine Linie.

Vorne weg ist ein analoger Bandpaß halbwegs passender Bandbreite. Daher 
ist die Amplitude niemals konstant.


Die Schaltung macht alles auf einmal:
1. Undersampler
2. phasenunabängiger Korrelator (Der Punkt ist etwas eingeschränkt)
3. Biphase-Demodulation
4. Differentialdemodulation

Alles mit ein paar wenigen Gattern und Flip-Flops. Was noch fehlt ist 
die Bittaktregeneration. Da habe ich noch keine super Idee für. Man 
könnte sich mit einem schnöden Taktteiler behelfen, der einfach an 
Flanken auf den halben Wert gesetzt wird. Dann erreicht man aber nicht 
das allerbeste S/N. Sollte aber ganz gut laufen, wenn das analoge 
Vorfilter leistungsfähig ist.


Naja, wie gesagt ich möchte es nur zu eurem Ansatz leistungsmäßig 
vergleichen. Befürchte nur, daß ich da noch kräftig umbauen muß um 
vergleichen zu können. Und da liegt das eigentliche Problem: Ich 
verstehe die eigene gefundene Schaltungsstruktur nicht komplett! Klar, 
das ist nicht euer Problem und ohne die Schaltung offenzulegen und zu 
erklären, sowieso kein Thema. Aber eure Gedanken helfen mir, Lösungen 
für mich zu finden.


Das Thema Bandpaß würde mich auch davon abgesehen weiter interessieren. 
Es hat mir mal jemand gesagt, ein RRCF könne man nicht als Bandpaß 
realisieren. Also was nimmt man dann? Ein Bessel, aber wie ergeben sich 
die Parameter??

von Bernd K. (prof7bit)


Lesenswert?

Abdul K. schrieb:
> Das Thema Bandpaß würde mich auch davon abgesehen weiter interessieren.
> Es hat mir mal jemand gesagt, ein RRCF könne man nicht als Bandpaß
> realisieren.

da ist bei mir auch kein RRC im Spiel, mein experimenteller Ansatz war 
sehr simpel und pragmatisch (geradezu hemdsärmelig wie ich ja ganz zu 
Beginn meiner Postings warnte). Nachdem bei mir aus dem Demodulator 
etwas rausfällt was wohl am ehesten Deiner Zeile 2 entspricht habe ich 
einfach mittels gängiger Tools (z.B. hier: 
http://www.micromodeler.com/dsp/ ) einen möglichst schmalen IIR Bandpass 
hoher Güte zusammengeklickt der bei einer Samplingrate von 1kHz (das ist 
die Frequenz in der meine while() loop neue Samples entgegennimmt) eine 
Resonanzfrequenz von genau 31.25Hz hat. Also fs/32. Dort hinein habe ich 
das demodulierte Signal (das blaue Signal) geschickt, das enthält 
Anteile des Symboltaktes und heraus aus dem Filter kommt das gelbe 
Signal. Der Filter ist so haarscharf bemessen dass er beinahe (aber 
gerade eben noch nicht) von selbst oszilliert und wenn eine Weile lang 
nur 1-Bits kommen (also keine Anteile des Symboltaktes auf dem blauen 
Signal sind) schwingt er dennoch dutzende von Perioden lang weiter mit 
31.25Hz und exakt der passenden Phasenlage so daß es reicht neun 
einser-Bits (die längst-mögliche einser-Sequenz) zu überbrücken ohne daß 
er aus der Phase läuft. Das gelbe Signal hab ich dann also mal testweise 
als Symboltakt verwendet und es hat wunderbar funktioniert.

Das geht bei mir aber nur deswegen so einfach weil ich quarzstabile 
Samplerate habe und demnach mein digitaler Filter ebenso genau ist, 
deshalb läuft er nicht weg und hat seine Resonanz immer genau bei 1/32 
fs. Ich weiß nicht ob das bei Deiner diskret (und teils analog?) 
aufgebauten Anordnung so einfach einzubauen wäre, bei mir warens halt 
nur mal eben ein dutzend Zeilen Code.

: Bearbeitet durch User
von Abdul K. (ehydra) Benutzerseite


Lesenswert?

Und du hast eine unmodulierte Spektrallinie auf deiner Filtermitte? Eine 
PLL kann ohne Linie nicht rasten, eine Costas-Loop dagegen ja.

Wenn man real BPSK benutzt, hat man immer Nichtlinearitäten in der 
Übertragung, die automatisch zumindest eine schwache Linie erzeugen und 
damit ein Einrasten ermöglichen.
Frag mich nicht, wie schwach die Linie sein darf. Hab ich noch keine 
Idee von.
Ich hab das mal näher untersucht und festgestellt, daß das 
Remodulator-Konzept immer daran scheitert. Keine ausreichende Linie, 
keine Demodulation.

von Bernd K. (prof7bit)


Lesenswert?

Ich glaube da liegt ein Missverständnis vor. Oben erwähnten Filter 
verwende ich für den Symboltakt, für dessen Rekonstruktion nach 
bereits erfolgter Demodulation, nicht für den Träger.

Für den Träger benutze ich lediglich eine zeitverzögerte Version seiner 
selbst als Referenz, dieser Teil läuft vollkommen frei, nicht kohärent, 
da muss gar nichts einrasten. Das ist doch gerade der Trick dabei.

: Bearbeitet durch User
von Abdul K. (ehydra) Benutzerseite


Angehängte Dateien:

Lesenswert?

Ah. Immer dieses Aneinandervorbeireden. Schon erstaunlich wie weit du 
mit a bisserl Software kommst.


Ein direkter Vergleich ist, wie gesagt, meines Erachtens unmöglich. Ich 
habe kein zweistufiges Konzept. Der Träger wird direkt im Demodulator 
mit verwurstet. Das Ganze entstand über Monate aus diversen 
Überlegungen, Patentrecherche, Sims usw. Manches überlegt geändert, und 
abundzu würfele ich auch mal gezielt wenn ich keine bessere Idee habe. 
Wer macht das nicht ;-)
So, nachdem das fast ein Jahr rumlag, weil ich erschöpft war an dieser 
Sache, werde ich das Neuordnen und systematisch weitertesten.


Was die Ähnlichkeiten angeht:
Man kann die Biphasemodulation bei RDS auch als eine Verdopplung der 
Bitrate ansehen, wenn man sich darüber klar ist das die beiden Teilbits 
jeweils miteinander 'korrespondieren' (sage ich mal so).
Dann bleibt aber noch das feste Verhältnis von 24 zwischen 
Trägerfrequenz und Datentakt. Der Faktor ist wohl bei PSK31 ein anderer.

Die Symbol-Synchronisation läuft doch bei PSK31 ähnlich einem UART:
1. UART: Startbit(0)-Datenbits-Stopbit(1)
2. PSK31: Startbit(0)-variable Datenbitlänge (aber nie 
'00'-auftreten)-Stopbit(0)
Ich denke man kann es so sehen, wenn man die Übereinstimmungen betonen 
will.

Also z.B. retriggerbarer Monoflop, der von den Flangen getriggert wird, 
für den Takt.


Wer will kann ja mal versuchen RDS zu demodulieren. Im Thread von 
Bernhard sind dazu mehr Infos.

Hier poste ich noch die wave-Datei, die ich auch in der Sim benutze. Die 
wurde von einem Spezialprogramm für die Synthese von RDS-Datenströmen 
erzeugt und ist für Soundkarten mit 192KHz Samplerate Mono gedacht. Das 
reicht für einen Träger bei 57KHz durchaus aus.
Mehr will ich den Thread auch nicht kapern.

von chris_ (Gast)


Lesenswert?

Floppy schrieb:
>Hallo Bernd,
>kannst Du mal die Schaltung skizzieren? Habe auch einen Arduino, würde
>aber gerne mal eine eigene Schaltung aufbauen!

Das dürfte ein zweistufiger Transistormikrofonverstärker sein:
http://www.elexs.de/ev4.gif

von http://www.elexs.de/kap5_2.htm

>An welchem Port hast du das Signal angeklemmt?

Ich würde sagen, wenn Du das Bild anschaust, siehst Du, dass das Signal 
an Analog 0 angeklemmt ist.

von Bernd K. (prof7bit)


Lesenswert?

chris_ schrieb:
> Das dürfte ein zweistufiger Transistormikrofonverstärker sein:
> http://www.elexs.de/ev4.gif

Genau das ist die Schaltung. Die Widerstände sind etwas anders, ich habe 
zwei unterschiedliche Transistoren die noch übrig waren in der 
Bastelkiste genommen und habe dann die Widerstände solange geändert bis 
ich ziemlich genau 2.5V am Kollektor hatte.

Zusätzlich hab ich noch ein C (paar hundert Picofarad) zwischen 
Kollektor und Basis des ersten Transistors weil er dazu neigte zu 
schwingen und übergebührlich HF aufgeschnappt hat, das war damit gut zu 
unterdrücken.

Vom Kollektor des zweiten gehe ich direkt auf den ADC, denn da habe ich 
ja bereits einen Gleichspannungsanteil von ungefähr 2.5V, das passt 
genau.

Die Schaltung ist eigentlich vollkommen egal, es gäbe zig andere 
Varianten, Hauptsache man bekommt das NF-Signal so verstärkt dass es mit 
einem brauchbaren Pegel (einige Volt Spitze-Spitze und ein DC-Anteil von 
2.5V) am ADC ankommt.

Eine Verbesserung wäre es analoge Tiefpässe mit einzubauen die alles 
oberhalb von 1kHz gut unterdrücken (oder gar Bandpässe die nur 1kHz 
durchlassen).

von DH1AKF W. (wolfgang_kiefer) Benutzerseite


Lesenswert?

Hallo Bernd,

Bernd K. schrieb:
> Eine Verbesserung wäre es analoge Tiefpässe mit einzubauen die alles
> oberhalb von 1kHz gut unterdrücken (oder gar Bandpässe die nur 1kHz
> durchlassen).

... heute habe ich auf einem PSoC5 Dein Programm vom 2.1.2015, 
zusätzlich mit einem  65 Hz breiten 1000 Hz- Filter zum Laufen gebracht. 
Allerdings ohne die AFC. Man kann sehr schön über Twente mitlesen. Es 
fehlt noch eine Möglichkeit, um z.B. über eine FFT das Spektrum 
anzuzeigen und die Frequenz exakt einstellen zu können. Aber das wird 
auch noch.

Nochmals vielen Dank für Deine Beiträge!

Wolfgang

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.