Übertragen Sie Daten durch Ton zwischen 2 Computern (sehr nahe Entfernung)


12

Ich schreibe ein Beispiel für die Übertragung von Daten zwischen zwei Computern. Einige Anforderungen:

  • Die Entfernung ist sehr gering, dh die beiden Computer liegen im Grunde genommen nebeneinander

  • Sehr wenig Lärm (Ich glaube nicht, dass mein Lehrer einen Rocksong als Geräuschquelle einschalten würde)

  • Fehler ist akzeptabel: Wenn ich beispielsweise "Funkkommunikation" sende, ist dies auch in Ordnung, wenn der andere Computer "RadiQ-Kommunikation" empfängt.

  • Wenn möglich: Kein Header, Flag, Prüfsumme, ..., da ich nur ein sehr einfaches Beispiel möchte, das die Grundlagen der Übertragung von Daten durch Ton demonstriert. Kein Grund zur Fantasie.

Ich habe versucht, Audio Frequency Shift Keying wie folgt zu verwenden:

Lab 5 APRS (Automatic Package Reporting System)

und habe ein paar Ergebnisse: Meine Github Seite

aber es ist nicht genug. Ich weiß nicht, wie man Taktwiederherstellung, Synchronisation usw. durchführt (die Verbindung hat einen Phasenregelkreis als Zeitwiederherstellungsmechanismus, aber es hat anscheinend nicht gereicht).

Ich denke, ich sollte einen einfacheren Ansatz finden. Fand einen Link hier:

Daten zu Audio und zurück. Modulation / Demodulation mit Quellcode

Das OP hat die in der Antwort vorgeschlagene Methode jedoch nicht implementiert, sodass ich befürchte, dass sie sehr komplex sein könnte. Außerdem verstehe ich die in der Antwort vorgeschlagene Decodierungsmethode nicht klar:

Der Decoder ist etwas komplizierter, aber hier ein Überblick:

Optional kann das abgetastete Signal mit einem Bandpassfilter um 11 kHz gefiltert werden. Dies verbessert die Leistung in einer lauten Umgebung. FIR-Filter sind recht einfach und es gibt einige Online-Design-Applets, die den Filter für Sie generieren.

Schwelle das Signal ein. Jeder Wert über 1/2 Maximalamplitude ist 1, jeder Wert unter 0. Dies setzt voraus, dass Sie das gesamte Signal abgetastet haben. Wenn dies in Echtzeit geschieht, wählen Sie entweder einen festen Schwellenwert oder führen eine Art automatische Verstärkungsregelung durch, bei der Sie den maximalen Signalpegel über einen längeren Zeitraum verfolgen.

Nach Punkt- oder Strichanfang scannen. Sie möchten wahrscheinlich mindestens eine bestimmte Anzahl von Einsen in Ihrer Punktperiode sehen, um die Abtastwerte als Punkt zu betrachten. Scannen Sie dann weiter, um festzustellen, ob dies ein Strich ist. Erwarten Sie kein perfektes Signal - Sie werden einige Nullen in der Mitte Ihrer Einsen und einige Einsen in der Mitte Ihrer Nullen sehen. Wenn es wenig Rauschen gibt, sollte es ziemlich einfach sein, die "Ein" -Perioden von den "Aus" -Perioden zu unterscheiden.

Kehren Sie dann den obigen Vorgang um. Wenn Sie einen Strich sehen, drücken Sie ein 1-Bit in Ihren Puffer, wenn ein Punkt eine Null drückt.

Ich verstehe nicht, wie viele Einsen es sind, bevor ich es als Punkt klassifiziere. Es gibt also viele Dinge, die ich momentan nicht verstehe. Bitte schlagen Sie mir eine einfache Methode zur Übertragung von Daten durch Ton vor, damit ich den Vorgang nachvollziehen kann. Vielen Dank :)

AKTUALISIEREN:

Ich habe Matlab-Code erstellt, der (etwas) funktionsfähig zu sein scheint. Ich moduliere das Signal zuerst mit Amplitude-Shift-Keying (Abtastfrequenz 48000 Hz, F_on = 5000 Hz, Bitrate = 10 Bits / s) und füge es dann mit einem Header und einer Endsequenz hinzu (moduliere sie natürlich auch). Der Header und die Endsequenz wurden ad-hoc ausgewählt (ja, es war ein Hack):

header = [0 0 1 0 1 1 1 1   1 0 0 0 0 0 0 1   1 0 0 0 0 0 0 1   1 0 1 1 0 1 0 1];  
end_seq = [1 1 1 1 1 0 1 0 1  0 1 0 1 0 1 0 1   0 1 0 1 0 1 0 1     0 1 0 1 0 1 0 1    0 1 0 1 0 1 0 1   0 1 0 1 0 1 0 1  1 0 0 1 0 0 0 1];

Dann übertrage ich sie per Ton und nehme sie mit meinem Smartphone auf. Anschließend sende ich das aufgezeichnete Audio an meinen Computer zurück und verwende einen anderen Code, um das Audio zu lesen. Dann korreliere ich das empfangene Signal (noch nicht demoduliert) mit dem modulierten Header und der Endsequenz, um den Anfang und das Ende herauszufinden. Danach nehme ich nur noch das relevante Signal (vom Anfang bis zum Ende, wie im Korrelationsteil zu finden). Dann demoduliere ich und taste ab, um die digitalen Daten zu finden. Hier sind 3 Audiodateien:

  • "DigitalCommunication_ask": Link hier sendet es den Text "Digital communication". Relativ geräuschlos, obwohl Sie am Anfang und am Ende Hintergrundgeräusche hören können. Das Ergebnis zeigte jedoch nur "Digital Commincatio"

  • "HelloWorld_ask": Link hier sendet es den Text "Hello world". Rauschfrei wie "DigitalCommunication_ask". Das Ergebnis für dieses war jedoch korrekt

  • "HelloWorld_noise_ask": Link hier sendet es den Text "Hello world". Es gibt jedoch ein Geräusch, das ich gemacht habe (ich sagte nur ein paar zufällige Sachen "A, B, C, D, E, ...." während der Übertragung). Dieser ist leider gescheitert

Hier ist der Code für den Absender (sender.m):

 clear
fs = 48000;
F_on = 5000;
bit_rate = 10;

% header = [0 0 1 0 1 1 1 1  1 1 1 1 1 1 1 1   1 1 1 1 1 1 1 1   1 1 1 1 1 1 1 1   1 1 1 1 1 1 1 1     1 1 1 1 1 1 1 1      1 1 1 1 1 1 1 1    1 1 1 1 1 1 1 1     1 1 1 1 1 1 1 1    1 1 1 1 1 1 1 1  1 1 1 1 1 1 1 1 ];
% header = [0 0 1 0 1 1 1 1  1 0 0 0 0 0 0 1   1 0 0 0 0 0 1   1 0 0 0 0 0 0 1   1 0 0 0 0 0 0 1     1 0 0 0 0 0 0 1      1 0 0 0 0 0 0 1    1 0 0 0 0 0 0 1  1 0 0 0 0 0 0 1    1 0 0 0 0 0 0 1  1 1 1 1 1 1 1 1 ];
header = [0 0 1 0 1 1 1 1   1 0 0 0 0 0 0 1   1 0 0 0 0 0 0 1   1 0 1 1 0 1 0 1];  

% end_seq = [1 0 0 1 0 1 0 0  1 0 1 1 0 0 0 1  0 0 0 0 1 0 0 1  1 0 0 0 1 0 0 1];
% end_seq = [1 0 0 1 0 1 0 0  1 0 1 1 0 0 0 1  0 0 0 0 1 0 0 1  1 0 0 0 1 0 0 1   0 1 0 0 1  1 0 0   1 1 0 1 1 0 0 1  ];
% end_seq = [0 0 0 1 0 0 0 1  0 0 0 0 0 0 0 0    0 0 0 0 0 0 0 0   1 1 0 0 1 1 0 0];
end_seq = [1 1 1 1 1 0 1 0 1  0 1 0 1 0 1 0 1   0 1 0 1 0 1 0 1     0 1 0 1 0 1 0 1    0 1 0 1 0 1 0 1   0 1 0 1 0 1 0 1  1 0 0 1 0 0 0 1];


num_of_samples_per_bit = round(fs / bit_rate);
modulated_header = ask_modulate(header, fs, F_on, bit_rate);
modulated_end_seq = ask_modulate(end_seq, fs, F_on, bit_rate);
% input_str = 'Ah';
input_str = 'Hello world';
ascii_list = double(input_str); % https://www.mathworks.com/matlabcentral/answers/298215-how-to-get-ascii-value-of-characters-stored-in-an-array
bit_stream = [];
for i = 1:numel(ascii_list)
    bit = de2bi(ascii_list(i), 8, 'left-msb');
    bit_stream = [bit_stream bit];
end
bit_stream = [header bit_stream  end_seq];
num_of_bits = numel(bit_stream);
bandlimited_and_modulated_signal = ask_modulate(bit_stream, fs, F_on, bit_rate);
sound(bandlimited_and_modulated_signal, fs);

Für den Empfänger (receiver.m):

clear
fs = 48000;
F_on = 5000;
bit_rate = 10;

% header = [0 0 1 0 1 1 1 1  1 1 1 1 1 1 1 1   1 1 1 1 1 1 1 1   1 1 1 1 1 1 1 1   1 1 1 1 1 1 1 1     1 1 1 1 1 1 1 1      1 1 1 1 1 1 1 1    1 1 1 1 1 1 1 1     1 1 1 1 1 1 1 1    1 1 1 1 1 1 1 1  1 1 1 1 1 1 1 1 ];
% header = [0 0 1 0 1 1 1 1  1 0 0 0 0 0 0 1   1 0 0 0 0 0 1   1 0 0 0 0 0 0 1   1 0 0 0 0 0 0 1     1 0 0 0 0 0 0 1      1 0 0 0 0 0 0 1    1 0 0 0 0 0 0 1  1 0 0 0 0 0 0 1    1 0 0 0 0 0 0 1  1 1 1 1 1 1 1 1 ];
header = [0 0 1 0 1 1 1 1   1 0 0 0 0 0 0 1   1 0 0 0 0 0 0 1   1 0 1 1 0 1 0 1];  

% end_seq = [1 0 0 1 0 1 0 0  1 0 1 1 0 0 0 1  0 0 0 0 1 0 0 1  1 0 0 0 1 0 0 1];
% end_seq = [1 0 0 1 0 1 0 0  1 0 1 1 0 0 0 1  0 0 0 0 1 0 0 1  1 0 0 0 1 0 0 1   0 1 0 0 1  1 0 0   1 1 0 1 1 0 0 1  ];
% end_seq = [0 0 0 1 0 0 0 1  0 0 0 0 0 0 0 0    0 0 0 0 0 0 0 0   1 1 0 0 1 1 0 0];
end_seq = [1 1 1 1 1 0 1 0 1  0 1 0 1 0 1 0 1   0 1 0 1 0 1 0 1     0 1 0 1 0 1 0 1    0 1 0 1 0 1 0 1   0 1 0 1 0 1 0 1  1 0 0 1 0 0 0 1];


modulated_header = ask_modulate(header, fs, F_on, bit_rate);
modulated_end_seq = ask_modulate(end_seq, fs, F_on, bit_rate);

% recObj = audiorecorder(fs,8,1);
% time_to_record = 10; % In seconds
% recordblocking(recObj, time_to_record);
% received_signal = getaudiodata(recObj);

% [received_signal, fs] = audioread('SounddataTruong_Ask.m4a');
% [received_signal, fs] = audioread('HelloWorld_noise_ask.m4a');
% [received_signal, fs] = audioread('HelloWorld_ask.m4a');
[received_signal, fs] = audioread('DigitalCommunication_ask.m4a');
ereceived_signal = received_signal(:)';
num_of_samples_per_bit = round(fs / bit_rate);

modulated_header = ask_modulate(header, fs, F_on, bit_rate);
modulated_end_seq = ask_modulate(end_seq, fs, F_on, bit_rate);

y= xcorr(modulated_header, received_signal); % do cross correlation
[m,ind]=max(y); % location of largest correlation
headstart=length(received_signal)-ind+1;

z = xcorr(modulated_end_seq, received_signal);
[m,ind]=max(z); % location of largest correlation
end_index=length(received_signal)-ind+1; 

relevant_signal = received_signal(headstart + num_of_samples_per_bit * numel(header) : end_index - 1);
% relevant_signal = received_signal(headstart + num_of_samples_per_bit * numel(header): end);
demodulated_signal = ask_demodulate(relevant_signal, fs, F_on, bit_rate);
sampled_points_in_demodulated_signal = demodulated_signal(round(num_of_samples_per_bit / 2) :  num_of_samples_per_bit :end);
digital_output = (sampled_points_in_demodulated_signal > (max(sampled_points_in_demodulated_signal(:)) / 2));
% digital_output = (sampled_points_in_demodulated_signal > 0.05);

% Convert to characters 
total_num_of_bits = numel(digital_output);
total_num_of_characters = total_num_of_bits / 8;
first_idx = 0;
last_idx = 0;
output_str = '';
for i = 1:total_num_of_characters
    first_idx = last_idx + 1;
    last_idx = first_idx + 7;
    binary_repr = digital_output(first_idx:last_idx); 
    ascii_value = bi2de(binary_repr(:)', 'left-msb');  
    character = char(ascii_value);
    output_str = [output_str character];    
end
output_str

ASK Modulationscode (ask_modulate):

function [bandlimited_and_modulated_signal] = ask_modulate(bit_stream, fs, F_on, bit_rate)
% Amplitude shift keying: Modulation
% Dang Manh Truong (dangmanhtruong@gmail.com)
num_of_bits = numel(bit_stream);
num_of_samples_per_bit = round(fs / bit_rate);
alpha = 0;
d_alpha = 2 * pi * F_on / fs;
A = 3;
analog_signal = [];
for i = 1 : num_of_bits
    bit = bit_stream(i);
    switch bit
        case 1
            for j = 1 : num_of_samples_per_bit
                analog_signal = [analog_signal A * cos(alpha)];
                alpha = alpha + d_alpha;

            end
        case 0
            for j = 1 : num_of_samples_per_bit
                analog_signal = [analog_signal 0];
                alpha = alpha + d_alpha;                
            end
    end    
end
filter_order = 15;
LP_filter = fir1(filter_order, (2*6000)/fs, 'low');
bandlimited_analog_signal = conv(analog_signal, LP_filter,'same');
% plot(abs(fft(bandlimited_analog_signal)))
% plot(bandlimited_analog_signal)
bandlimited_and_modulated_signal = bandlimited_analog_signal;

end

ASK-Demodulation (ask_demodulate.m) (Grundsätzlich ist es nur die Hüllkurvenerkennung, für die ich die Hilbert-Transformation verwendet habe)

function [demodulated_signal] = ask_demodulate(received_signal, fs, F_on, bit_rate)
% Amplitude shift keying: Demodulation
% Dang Manh Truong (dangmanhtruong@gmail.com)

demodulated_signal = abs(hilbert(received_signal));

end

Bitte sagen Sie mir, warum es nicht funktioniert? Vielen Dank


In der Theorie (in einer lärmfreien Umgebung) wäre dies trivial zu implementieren, in der Praxis ist dies jedoch viel schwieriger. Dies hängt jedoch von der Art der Informationen ab, die Sie senden möchten. Es wäre äußerst schwierig, Text zuverlässig zu übertragen, da selbst kleinste Geräusche den Text unkenntlich machen würden.
dsp_user

@dsp_user Ich versuche, Text zu senden. Ich kann mit einigem Fehler leben (wie "Audio" -> "Apdio") :) Auch ich verstehe das nicht wirklich, für Amplitude Shift Keying zum Beispiel, wenn Sie 1 haben, dann senden Sie eine Sinuswelle, 0 dann nichts als wie kennst du die ersten 0? Ich meine in einer rauschfreien Umgebung, aber vor der ersten 1 würde es eine Menge von 0 geben, oder? Woher weißt du es dann?
Dang Manh Truong

Ich schlage vor, Sie schauen sich ein altmodisches 14.4-Modem für Ideen an.

@ StanleyPawlukiewicz Ich habe einige Fortschritte gemacht. Bitte überprüfen Sie das Update. Vielen Dank.
Dang Manh Truong

Es gibt viel zu kommentieren. Vielleicht möchten Sie sich die Barker-Sequenzen für Ihre Präambel ansehen, da Sie Präambeln verwenden

Antworten:


8

Wie Sie erkannt haben, ist der schwierige Teil der digitalen Kommunikation die Träger-, Symbol- und Rahmensynchronisation sowie die Kanalschätzung / -entzerrung.

Die schlechte Nachricht ist, dass Sie diese Probleme nicht umgehen können. Die gute Nachricht ist, dass die Implementierung nicht allzu schwierig ist, solange Sie sich auf Schmalband-BPSK beschränken. Ich weiß, weil ich das selbst getan habe, und meine (Studenten-) Studenten auch (siehe http://ieeexplore.ieee.org/document/5739249/ )

Ein einfacher Vorschlag, um das Problem der Trägersynchronisation zu umgehen, ist die Verwendung von AM DSB-LC zur Aufwärtskonvertierung Ihres Basisbandsignals. Dann können Sie einen Hüllkurvendetektor ohne Träger- und Phasensynchronisation verwenden. Dies kostet Sie Energieeffizienz, hat aber in Ihrem Fall keine Priorität.

Ein weiterer einfacher Vorschlag ist die "Stapelverarbeitung" anstelle der "Echtzeitverarbeitung". Das heißt, Sie speichern das gesamte empfangene Signal und verarbeiten es anschließend. Dies ist viel einfacher zu implementieren als Streaming oder Echtzeitverarbeitung.

Mein größerer Vorschlag ist, dieses Buch zu lesen: Johnson, Sethares und Klein, "Software receiver design", Cambridge. Es erklärt in sehr klaren Worten jedes einzelne Stück des Empfängers und enthält viele Beispiele für Matlab-Code. Es gibt ein ähnliches Buch von Steven Tretter über die Implementierung eines Kommunikationssystems auf einem DSP (ich kann mich momentan nicht an den genauen Titel erinnern).

Viel Glück; und stellen Sie bitte neue, spezifischere Fragen, wenn Sie sie haben.


Ich habe deine Zeitung gelesen. Mach weiter so! Eine Frage: In der Arbeit sprachen Sie über verschiedene Methoden, mit denen die Schüler die Kanalantwort ermitteln (unter Verwendung von Impulsen, Sinuswellen usw.). Muss ich auch die Kanalantwort finden? :)
Dang Manh Truong

1
Vielen Dank für Ihre freundlichen Worte :) Das Problem ist, dass Sie sicherstellen möchten, dass Sie über ein Frequenzband senden, in dem die Kanalantwort flach ist. Andernfalls benötigen Sie einen Equalizer im Receiver. Wenn Sie die Kanalantwort nicht abschätzen möchten, können Sie eine sehr niedrige Datenrate (z. B. 100 b / s) auf einer Frequenz verwenden, mit der alle Audiogeräte zufrieden sein sollten (z. B. 5000 Hz).
MBaz

1
@DangManhTruong Eine weitere Sache: Stellen Sie sicher, dass Sie bandbreitenbegrenzte Impulse verwenden, wie z. B. den Quadratwurzel-Raised-Cosine, und keine Rechteckimpulse, die eine große Bandbreite haben und höchstwahrscheinlich verzerrt werden.
MBaz

Ich habe das von Ihnen vorgeschlagene Design des Software-Empfängers gelesen (eigentlich habe ich das meiste durchgesehen und mich auf Kapitel 8 konzentriert: Bits zu Symbolen zu Signalen). Ich habe also ein paar Fragen. Sie haben etwas über Impulse gesagt, aber im Buchbeispiel wurde ein Hamming-Fenster als Impuls verwendet. Ist es in Ordnung, wenn ich das tue? Und ist meines Wissens nach richtig: Zuerst modulieren Sie das Signal mit etwa ASK, dann verwenden Sie die Impulsformung. Dann korrelieren Sie am Empfänger zuerst mit dem Impulssignal, um das modulierte Signal zu empfangen. Dann demodulieren Sie. Ist es richtig?
Dang Manh Truong

Und wenn ich Daten in Paketform mit einem Header am Anfang und am Ende senden möchte, sagen wir 1 1 1 1 1 1 1 1, dann sollte ich sie mit den Daten versehen, dann modulieren und dann impulsförmig gestalten. Auf dem Empfänger würde ich das empfangene Signal mit der Pulsform korrelieren (Quadratwurzel-Kosinus, ..), dann muss ich das Signal demodulieren, danach korreliere ich mit dem Header. Ist mein Verständnis korrekt?
Dang Manh Truong

4

Am Ende habe ich DTMF (Dual Tone Multi Frequency Signaling) verwendet. Der ursprüngliche DTMF verfügt über 16 Signale, die jeweils eine Kombination von 2 Frequenzen verwenden. Aber hier habe ich nur "1" (697 Hz und 1209 Hz) und "0" (941 Hz und 1336 Hz) verwendet

Ein Überblick über die Funktionsweise des Codes:

  • Der Sender wandelt Text in Binärdaten um und sendet dann DTMF-Signale mit den Werten "0" / "1" (hier beträgt das Timing 0,3 s für die Tondauer und 0,1 s für die Pause zwischen den Tönen). Der Übertragungscode stammt aus: https://sites.google.com/a/nd.edu/adsp-nik-kleber/home/advanced-digital-signal-processing/project-3-touch-tone . Anscheinend verwendete der Autor einen geringfügig stabilen IIR-Filter, um einen digitalen Oszillator zu implementieren.
  • Die Empfängerseite verwendet zuerst zwei lächerlich hochgeordnete und lächerlich enge Bandpassfilter, um die Frequenzkomponenten "0" bzw. "1" zu extrahieren:

    filter_order = 1000;

    one_band = [[((2696)/Fs) ((2698)/Fs)] [((21208)/Fs) ((21210)/Fs)]];
    
    one_dtmf_filter = fir1(filter_order, one_band);
    
    zero_band = [[((2940)/Fs) ((2942)/Fs)] [((21335)/Fs) ((21337)/Fs)]];
    
    zero_dtmf_filter = fir1(filter_order, zero_band);
    

Danach finden wir den Anfang und das Ende jedes "1" - und "0" -Signals. Der Code stammt von https://github.com/codyaray/dtmf-signaling . Grundsätzlich findet es die Ruheperiode, die mindestens 10 ms und jede Tonperiode mehr als 100 ms beträgt):

Bildbeschreibung hier eingeben

(Von oben nach unten: Nullsignal, Signal nach dem Filter für den gleitenden Durchschnitt, Differenz des Signals nach dem Entfernen der unter dem Schwellenwert liegenden Signale, Signal nach dem Schwellenwert)

  • Zuerst wird das Ergebnis des vorherigen Schritts normalisiert und dann durch ein Filter mit gleitendem Durchschnitt (mit einer Filtergröße von 10 ms * Fs) geleitet. Wenn wir das Ergebnis grafisch darstellen, sehen wir, dass die Form der "0" und "1" deutlich zu erkennen ist. Ich denke, es funktioniert in diesem Fall irgendwie als Hüllkurvendetektor.
  • Dann wird das gesamte Signal unterhalb einer bestimmten Schwelle abgeschnitten (ich habe 0,1 gewählt).
  • Schließlich finden Sie alle Intervalle oberhalb des Schwellenwerts, die ein Zeitintervall von mehr als 100 ms aufweisen.

Dann setzen wir die Bits zusammen und wandeln sie wieder in Text um :)

Videodemo: https://www.youtube.com/watch?v=vwQVmNnWa4s , wo ich den Text "Xin chao" zwischen meinem Laptop und dem PC meines Bruders sende :)

P / S: Ursprünglich tat ich dies, weil mein Lehrer für digitale Kommunikation sagte, dass jeder, der dies tat, ein A bekommen würde, ohne die Abschlussprüfung machen zu müssen, aber ich konnte dies erst nach der Prüfung tun. Also hier geht alle meine Bemühungen :(

P / S2: Ich habe ein C + :(


0

Wenn Sie eine Open-Source-Bibliothek mit sehr guter Synchronisation wünschen, empfehle ich https://github.com/jgaeddert/liquid-dsp, die msequences zum Ausrichten verwendet, dann eine Entzerrung vornimmt und die Nutzdaten demoduliert. Ich habe ein Audiomodem gebaut, das oben läuft und recht gut funktioniert. Daher sollten die Methoden von liquid eine Hilfe sein, wenn nichts anderes

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.