Piszę przykład przesyłania danych przez dźwięk między 2 komputerami. Niektóre wymagania:
Odległość jest bardzo bliska, tzn. 2 komputery są w zasadzie przylegające do siebie
Bardzo mało hałasu (nie sądzę, żeby mój nauczyciel włączył rockową piosenkę jako źródło hałasu)
Błąd jest dopuszczalny: na przykład, jeśli wyślę „Komunikacja radiowa”, to jeśli drugi komputer odbierze „RadiQ communEcation”, to również jest w porządku.
Jeśli to możliwe: brak nagłówka, flagi, sumy kontrolnej, .... ponieważ chcę tylko bardzo prosty przykład demonstrujący podstawy przesyłania danych przez dźwięk. Nie musisz być fantazyjny.
Próbowałem użyć Audio Shift Keying Shift według tego linku:
Lab 5 APRS (automatyczny system raportowania paczek)
i uzyskałem kilka wyników: Moja strona Github
ale to nie wystarczy. Nie wiem, jak wykonać odzyskiwanie zegara, synchronizację, ... (link ma mechanizm synchronizacji fazy jako mechanizm odzyskiwania czasu, ale najwyraźniej to nie wystarczyło).
Myślę więc, że powinienem znaleźć prostsze podejście. Znaleziono link tutaj:
Dane do audio i wstecz. Modulacja / demodulacja z kodem źródłowym
ale OP nie wdrożył metody sugerowanej w odpowiedzi, więc obawiam się, że może być bardzo złożona. Również nie rozumiem jasno metody dekodowania zaproponowanej w odpowiedzi:
Dekoder jest nieco bardziej skomplikowany, ale oto zarys:
Opcjonalnie filtruj pasmowo-filtrowy próbkowany sygnał około 11 kHz. Poprawi to wydajność w głośnym otoczeniu. Filtry FIR są dość proste i istnieje kilka apletów projektu online, które wygenerują filtr dla Ciebie.
Przekrocz próg sygnału. Każda wartość powyżej 1/2 maksymalnej amplitudy wynosi 1, a każda wartość poniżej wynosi 0. To zakłada, że próbkowałeś cały sygnał. Jeśli odbywa się to w czasie rzeczywistym, albo wybierasz stały próg, albo wykonujesz automatyczną kontrolę wzmocnienia, w której śledzisz maksymalny poziom sygnału przez pewien czas.
Wyszukaj początek kropki lub myślnika. Prawdopodobnie chcesz zobaczyć przynajmniej pewną liczbę jedynek w okresie kropki, aby uznać próbki za kropkę. Następnie kontynuuj skanowanie, aby sprawdzić, czy to kreska. Nie oczekuj idealnego sygnału - zobaczysz kilka zer na środku swoich zer i kilka jedynek na środku swoich zer. Jeśli występuje niewielki hałas, odróżnienie okresów włączenia od okresów wyłączenia powinno być dość łatwe.
Następnie odwróć powyższy proces. Jeśli widzisz myślnik wypchnij 1 bit do bufora, jeśli kropka popchnie zero.
Nie rozumiem, ile cyfr 1 sklasyfikowano jako kropkę ... Więc jest wiele rzeczy, których teraz nie rozumiem. Proszę zasugerować mi prostą metodę przesyłania danych dźwiękiem, aby zrozumieć proces. Dziękuję Ci bardzo :)
AKTUALIZACJA:
Zrobiłem trochę kodu Matlaba, który wydaje się (nieco) działać. Najpierw moduluję sygnał za pomocą kluczowania z przesunięciem amplitudy (częstotliwość próbkowania 48000 Hz, F_on = 5000 Hz, przepływność = 10 bitów / s), a następnie dodaję go z nagłówkiem i sekwencją końcową (oczywiście je również moduluję). Nagłówek i sekwencja końcowa zostały wybrane na zasadzie ad hoc (tak, to był 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];
Następnie przesyłam je dźwiękiem i nagrywam na smartfonie. Następnie wysyłam nagrany dźwięk z powrotem do mojego komputera, użyj innego fragmentu kodu, aby odczytać dźwięk. Następnie koreluję odbierany sygnał (jeszcze nie zdemodulowany) z modulowanym nagłówkiem i sekwencją końcową, aby znaleźć początek i koniec. Następnie biorę tylko odpowiedni sygnał (od początku do końca, jak w części dotyczącej korelacji). Następnie demoduluję i próbkuję, aby znaleźć dane cyfrowe. Oto 3 pliki audio:
„DigitalCommunication_ask”: Link tutaj przesyła tekst „Komunikacja cyfrowa”. Stosunkowo bezszumowy, chociaż na początku i na końcu słychać szum tła. Jednak wynik pokazał tylko „Digital Commincatio”
„HelloWorld_ask”: Link tutaj wysyła tekst „Hello world”. Bez hałasu jak „DigitalCommunication_ask”. Jednak wynik tego był poprawny
„HelloWorld_noise_ask”: Link tutaj wysyła tekst „Hello world”. Jest jednak trochę hałasu, który wydałem (właśnie powiedziałem kilka przypadkowych rzeczy „A, B, C, D, E,…” podczas transmisji). Niestety ten zawiódł
Oto kod nadawcy (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);
W przypadku odbiornika (odbiornik.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
ZAPYTAJ kod modulacji (ask_modulate):
function [bandlimited_and_modulated_signal] = ask_modulate(bit_stream, fs, F_on, bit_rate)
% Amplitude shift keying: Modulation
% Dang Manh Truong ([email protected])
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) (Zasadniczo jest to po prostu wykrywanie obwiedni, dla którego użyłem transformacji Hilberta)
function [demodulated_signal] = ask_demodulate(received_signal, fs, F_on, bit_rate)
% Amplitude shift keying: Demodulation
% Dang Manh Truong ([email protected])
demodulated_signal = abs(hilbert(received_signal));
end
Powiedz mi, dlaczego to nie działa? Dziękuję Ci bardzo
źródło
Odpowiedzi:
Jak zauważyłeś, trudną częścią komunikacji cyfrowej jest synchronizacja nośnej, symbolu i ramki oraz szacowanie / wyrównanie kanału.
Zła wiadomość jest taka, że nie można obejść tych problemów. Dobra wiadomość jest taka, że ich wdrożenie nie jest takie trudne, o ile ograniczysz się do wąskopasmowego BPSK. Wiem, ponieważ sam to zrobiłem, podobnie jak moi (studenci) studenci (patrz http://ieeexplore.ieee.org/document/5739249/ )
Jedną z prostych propozycji obejścia problemu synchronizacji nośnej jest użycie AM DSB-LC do konwersji sygnału w paśmie podstawowym. Następnie możesz użyć detektora obwiedni bez synchronizacji fazy i nośnej. Będzie to kosztować wydajność energetyczną, ale w twoim przypadku nie jest to priorytetem.
Inną prostą sugestią jest „przetwarzanie wsadowe” zamiast „przetwarzanie w czasie rzeczywistym”; oznacza to, że zapisz cały odebrany sygnał, a następnie przetworz go. Jest to o wiele łatwiejsze do wdrożenia niż przetwarzanie strumieniowe lub przetwarzanie w czasie rzeczywistym.
Bardziej merytoryczną propozycją jest przeczytanie tej książki: Johnson, Sethares i Klein, „Software Receiver Design”, Cambridge. Wyjaśnia bardzo jasno każdy element odbiornika i zawiera wiele przykładowych kodów Matlab. Istnieje podobna książka Stevena Trettera o wdrażaniu systemu komunikacji na DSP (nie pamiętam teraz dokładnego tytułu).
Powodzenia; i proszę zadawać nowe, bardziej szczegółowe pytania, jeśli je masz.
źródło
W końcu zastosowałem DTMF (sygnalizacja wieloczęstotliwościowa Dual Tone). Oryginalny DTMF ma 16 sygnałów, każdy przy użyciu kombinacji 2 częstotliwości. Ale tutaj użyłem tylko „1” (697 Hz i 1209 Hz) i „0” (941 Hz i 1336 Hz)
Zarys działania kodu:
Strona odbiornika najpierw wykorzystuje 2 absurdalnie wysokie uporządkowane i śmiesznie wąskie filtry pasmowoprzepustowe, aby wyodrębnić odpowiednio składowe częstotliwości „0” i „1”:
filter_order = 1000;
Po wykonaniu tej czynności znajdziemy początek i koniec każdego sygnału „1” i „0”. Kod pochodzi z https://github.com/codyaray/dtmf-signaling . Zasadniczo znajduje okres ciszy wynoszący co najmniej 10 ms i dowolny okres tonu dłuższy niż 100 ms):
(Od góry do dołu: sygnał zerowy, sygnał po ruchomym filtrze średnim, różnica sygnału po usunięciu tych poniżej progu, sygnał po progowaniu)
Następnie montujemy bity i przekształcamy z powrotem w tekst :)
Demo wideo: https://www.youtube.com/watch?v=vwQVmNnWa4s , gdzie wysyłam tekst „Xin chao” między moim laptopem a komputerem mojego brata :)
P / S: Początkowo to zrobiłem, ponieważ mój nauczyciel komunikacji cyfrowej powiedział, że ktokolwiek to zrobi, dostanie A bez konieczności zdawania egzaminu końcowego, ale mogłem to zrobić dopiero po egzaminie. Oto wszystkie moje wysiłki :(
P / S2: Mam C + :(
źródło
Jeśli chcesz mieć bibliotekę open source z bardzo dobrą synchronizacją, polecam https://github.com/jgaeddert/liquid-dsp, który używa sekwencji do wyrównania, a następnie dokonuje korekcji i demoduluje ładunek. Zrobiłem modem audio, który działa na górze i działa całkiem dobrze, więc jeśli nic więcej, metody cieczy powinny być pomocne
źródło