Machen Sie ein (Software-) Modem!

14

Zielsetzung

Entwerfen Sie ein mo dulator / DM odulator Paar genau zu übertragen Daten so schnell wie möglich über simulierte Plain Old Telephone Service (POTS) .

Schritte

  1. Zufälliges generieren (/dev/random oder ähnliche) Daten, deren Übertragung 3-4 Sekunden dauert
  2. Modulieren Sie die Daten mit Ihrem Modulator, um eine Audiodatei zu erstellen
  3. Leiten Sie die Audiodatei durch den POTS-Simulator . Wenn Sie nicht über Python / Scipy verfügen, können Sie eine Datei mit dem Formular hochladen oder eine JSON-API-Anforderung ausführen.
  4. Demodulieren Sie die Audiodatei wieder in Binärdaten
  5. Vergewissern Sie sich, dass Eingabe und Ausgabe gleich sind. * (Maximal 1 von 1000 Bits kann beschädigt werden.)
  6. Score ist die Anzahl der übertragenen Bits geteilt durch die Länge der Audiodatei (Bits / Sekunde)

Regeln

  • Die Eingabedatei muss 3-4 Sekunden lang, 44,1 kHz, mono sein.
  • Starten Sie den Simulator mit einem SNR von 30 dB (Standardeinstellung)
  • Der Demodulator muss die übertragenen Daten mit einer Bitfehlerrate von nicht mehr als 10 -3 (1 pro tausend Bits) rekonstruieren .
  • Es ist keine digitale Komprimierung zulässig (dh das Komprimieren der Daten liegt außerhalb des Bereichs der Herausforderung).
  • Kein Versuch, Daten in Frequenzen über 4 kHz zu verschieben. (Meine Filter sind nicht perfekt, aber mit einer relativ geringen Anzahl von Taps einigermaßen POTS-artig.)
  • Wenn Ihr Modemprotokoll eine kurze Präambel (nicht länger als 1 Sekunde) zum Synchronisieren / Kalibrieren des Empfängers benötigt, wird dies nicht bestraft.
  • Wenn möglich, hosten Sie die Audiodatei an einem zugänglichen Ort, damit wir eine Kakophonie von Signaltönen und Signaltönen hören können.

Beispiel

Hier ist ein Beispielnotizbuch , das die Modulation / Demodulation durch einfaches "On-Off-Keying" demonstriert (inklusive Hörproben!).

Es würde 100 (Bits / Sekunde) erzielen. Beachten Sie, dass es mit einem viel schlechteren 5-dB-SNR sendet.

Nick T
quelle
2
Unterscheidet sich dies von einer normalen "Komprimieren dieser Binärdaten" -Herausforderung? Wenn ja, können Sie klarstellen, wie genau sich dies unterscheidet?
Türklinke
1
Hier modulieren Sie Daten (wandeln sie in etwas Analoges um) und umgekehrt. Man könnte es vielleicht "analoge Komprimierung" nennen
Nick T
Entschuldigung, ich bin mir nicht sicher, wie diese Herausforderung funktioniert. Das Wort "modulieren" erscheint nicht einmal in dem Wikipedia-Artikel, den Sie verlinkt haben. Könnten Sie weitere Hintergrundinformationen hinzufügen oder die Spezifikation präzisieren?
Türknauf
4
wget wikipedia.org/Special:Random | grep title | texttospeech audio.wav speechtotext POTSaudio.wav | wget wikipedia/wiki/$text
TessellatingHeckler
1
Dies ist eine großartige Herausforderung, ich werde versuchen, die Zeit zu finden, um eine Antwort einzureichen!
GoatInTheMachine

Antworten:

7

MATLAB, 1960 bps

Hier ist mein aktualisierter Versuch:

fs = 44100; %44.1kHz audio rate
fc = 2450;  %2.45kHz carrier - nice fraction of fs!
fsym = fc/5; %symbol rate

tmax = 4; %about 4 seconds worth

preamblesyms = 6;

t = 1/fs:1/fs:(tmax+preamblesyms/fsym);

symbols = preamblesyms+fsym*tmax;
symbollength = length(t)/symbols;
bits = symbols*3;
bitstream = [zeros(1,preamblesyms*3),rand(1,bits-preamblesyms*3)>0.5]; %Add a little preamble of 18 bits
data = bin2dec(char(reshape(bitstream,3,symbols)'+'0'))';

greycode = [0 1 3 2 6 7 5 4];

%Encode the symbols using QAM8 - we use effectively grey code so that
%adjacent symbols in the constellation have only one bit difference
%(minimises error rate)
encoded = zeros(2,symbols);
encoded(1,data==1) = 1/sqrt(2);
encoded(1,data==3) = 1;
encoded(1,data==2) = 1/sqrt(2);
encoded(1,data==7) = -1/sqrt(2);
encoded(1,data==5) = -1;
encoded(1,data==4) = -1/sqrt(2);
encoded(2,data==0) = 1;
encoded(2,data==1) = 1/sqrt(2);
encoded(2,data==2) = -1/sqrt(2);
encoded(2,data==6) = -1;
encoded(2,data==7) = -1/sqrt(2);
encoded(2,data==4) = 1/sqrt(2);

%Modulate onto carrier
carrier = [sin(2*pi*fc*t);cos(2*pi*fc*t)];
signal = reshape(repmat(encoded(1,:)',1,symbollength)',1,[]);
signal(2,:) = reshape(repmat(encoded(2,:)',1,symbollength)',1,[]);
modulated = sum(signal.*carrier)';

%Write out an audio file
audiowrite('audio.wav',modulated,fs);

%Wait for the user to run through the POTS simulator
input('');

%Read in the filtered data
filtered=audioread('audio.pots-filtered.wav')';

%Recover the two carrier signals
preamblecos = filtered(symbollength+1:symbollength*2);
preamblesin = filtered(symbollength+1+round(symbollength*3/4):symbollength*2+round(symbollength*3/4));

%Replicated the recovered carriers for all symbols
carrierfiltered = [repmat(preamblesin,1,symbols);repmat(preamblecos,1,symbols)];

%Generate a demodulation filter (pass up to 0.66*fc, stop at 1.33*fc
%(really we just need to kill everything around 2*fc where the alias ends up)
d=fdesign.lowpass('Fp,Fst,Ap,Ast',0.05,0.1,0.5,60);
Hd = design(d,'equiripple');

%Demodulate the incoming stream
demodulated = carrierfiltered .* [filtered;filtered];
demodulated(1,:)=filtfilt(Hd.Numerator,1,demodulated(1,:));
demodulated(2,:)=filtfilt(Hd.Numerator,1,demodulated(2,:));

%Split signal up into bit periods
recovereddemodulated=[];
recovereddemodulated(1,:,:) = reshape(demodulated(1,:),symbollength,symbols);
recovereddemodulated(2,:,:) = reshape(demodulated(2,:),symbollength,symbols);

%Extract the average level for each bit period. Only look at the second
%half to account for slow rise times in the signal due to filtering
recoveredsignal=mean(recovereddemodulated(1,round(symbollength/2):symbollength,:));
recoveredsignal(2,:)=mean(recovereddemodulated(2,round(symbollength/2):symbollength,:));

%Convert the recovered signal into a complex number.
recoveredsignal=recoveredsignal(2,:) + 1j*recoveredsignal(1,:);

%Determine the magnitude and angle of the symbol. The phase is normalised
%to pi/4 as that is the angle between the symbols. Rounding this to the
%nearest integer will tell us which of the 8 phases it is closest to
recoveredphase = round(angle(recoveredsignal)/(pi/4));
recoveredphase = mod(recoveredphase+8,8)+1; %Remap to an index in the grey code vector.

%Determine the symbol in the QAM8 constellation
recoveredencoded=greycode(recoveredphase);
recoveredencoded(1:preamblesyms)=0; %Assume the preamble is correct for comparison

%Turn it back in to a bit stream
bitstreamRecovered = reshape(dec2bin(recoveredencoded)'-'0',1,[]);

%And check if they are all correct...
if(all(bitstream==bitstreamRecovered))
    disp(['Woop, ' num2str(fsym*4) 'bps']);
else
    error('Its corrupt Jim.');
end

Seit meinem ersten Versuch habe ich ein bisschen rumgespielt. Es gibt jetzt eine kleine Präambel am Anfang (18-Bit-Perioden, die aber kürzer sein könnte), die nur eine Kosinuswelle enthält. Ich extrahiere dies und repliziere es, um korrekt phasengesteuerte Sinus- und Cosinus-Träger für die Demodulation zu erstellen. Da es sich um eine sehr kurze Präambel handelt, habe ich sie nicht gemäß Ihren Anweisungen in der Bitrate gezählt.

Auch seit dem ersten Versuch verwende ich jetzt eine QAM8-Konstellation, um 3 Bits pro Symbol anstelle von 2 zu erzielen. Dies verdoppelt effektiv die Übertragungsrate. Mit einem Träger mit ~ 2,4 kHz erreiche ich jetzt 1960 Bit / s.

Ich habe auch die Symbolerkennung verbessert, damit die Mittelwertbildung nicht durch langsame Anstiegszeiten beeinträchtigt wird, die durch die Filterung verursacht werden. Im Grunde wird nur die zweite Hälfte jeder Bitperiode gemittelt, um den Einfluss von Anstiegszeiten zu beseitigen.

Noch lange nicht annähernd die theoretische Kanalbandbreite von 40kbps von der Shannon-Hartley-Theorie (unter der Annahme des 30-dB-SNR)

Nur für diejenigen, die schreckliche Klänge mögen , ist dies der neue Eintrag:


Und falls jemand interessiert ist, ist dies der vorherige Eintrag mit 960 Bit / s

Tom Carpenter
quelle
Die Bewertung ist nur die Übertragungsrate. Halten Sie Ihren Code klar. Ich habe einen Vorschlag hinzugefügt, um Ihre Audiodatei irgendwo zu hosten, wenn es für Funsies einfach ist: D
Nick T
Ich werde das Audio auf meine Site hochladen. Es klingt ziemlich unheimlich!
Tom Carpenter
@ NickT-Audiodatei hochgeladen - siehe den Link am Ende des Beitrags.
Tom Carpenter
Wenn Sie über ein SoundCloud-Konto verfügen, können Sie Ihre Audiodaten hochladen und einen Link posten, der in Ihrem Beitrag wiedergegeben werden kann. ( Beispiel )
Calvins Hobbys
@ NickT danke. Ich habe ein Soundcloud-Konto erstellt und hochgeladen. Ich habe auch eine aktualisierte Version mit doppelter Datenrate gemacht :)
Tom Carpenter