2 대의 컴퓨터 사이에서 소리를 통해 데이터를 전송합니다 (매우 가까운 거리)


12

두 대의 컴퓨터 사이에서 사운드를 통해 데이터를 전송하는 예를 쓰고 있습니다. 일부 요구 사항 :

  • 거리는 매우 가깝습니다. 즉, 2 대의 컴퓨터가 기본적으로 서로 인접 해 있습니다.

  • 소음이 거의 없음 (선생님이 록 소스를 소음원으로 사용하지 않을 것 같습니다)

  • 예를 들어 "Radio communication"을 보내면 다른 컴퓨터가 "RadiQ communEcation"을 수신해도 괜찮습니다.

  • 가능한 경우 : 헤더, 플래그, 체크섬 등이 없습니다. 사운드를 통해 데이터를 전송하는 기본 사항을 보여주는 매우 기본적인 예를 원하기 때문입니다. 화려할 필요는 없습니다.

이 링크에 따라 Audio Frequency Shift Keying을 사용해 보았습니다.

랩 5 APRS (자동 패키지보고 시스템)

결과가 나타납니다 : My Github 페이지

그러나 충분하지 않습니다. 나는 시계 복구, 동기화, ...를 수행하는 방법을 모른다.

그래서 나는 더 간단한 접근법을 찾아야한다고 생각합니다. 여기에 링크가 있습니다 :

데이터를 오디오 및 백으로. 소스 코드를 이용한 변조 / 복조

그러나 OP는 답변에서 제안 된 방법을 구현하지 않았으므로 매우 복잡 할 수 있습니다. 또한 대답에서 제안 된 디코딩 방법을 명확하게 이해하지 못합니다.

디코더는 조금 더 복잡하지만 개요는 다음과 같습니다.

선택적으로 11Khz 주변에서 샘플링 된 신호를 대역 통과 필터링합니다. 시끄러운 환경에서 성능이 향상됩니다. FIR 필터는 매우 간단하며 필터를 생성하는 몇 가지 온라인 디자인 애플릿이 있습니다.

신호 임계 값. 1/2 최대 진폭을 초과하는 모든 값은 1이며, 아래 모든 값은 0입니다. 이는 전체 신호를 샘플링 한 것으로 가정합니다. 이것이 실시간 인 경우 고정 임계 값을 선택하거나 일정 시간 동안 최대 신호 레벨을 추적하는 일종의 자동 게인 제어를 수행합니다.

도트 또는 대시의 시작을 스캔하십시오. 샘플을 도트로 간주하기 위해 도트주기에서 적어도 1의 특정 수를보고 싶을 것입니다. 그런 다음 스캔을 계속하여 대시인지 확인하십시오. 완벽한 신호를 기대하지 마십시오. 1의 중간에 몇 개의 0이 있고 0의 중간에 몇 개의 1이 보일 것입니다. 노이즈가 적 으면 "켜기"기간과 "끄기"기간을 구분하는 것이 매우 쉽습니다.

그런 다음 위 과정을 반대로하십시오. 대시가 버퍼에 1 비트를 밀어 넣으면 도트가 0을 밀어 넣으십시오.

나는 그것을 점으로 분류하기 전에 얼마나 많은 1을 이해하지 못합니다 ... 그래서 지금 이해하지 못하는 것이 많이 있습니다. 프로세스를 이해할 수 있도록 사운드를 통해 데이터를 전송하는 간단한 방법을 제안하십시오. 대단히 감사합니다 :)

최신 정보:

(일부) 작동하는 것처럼 보이는 Matlab 코드를 만들었습니다. 먼저 진폭 시프트 키잉 (샘플링 주파수 48000Hz, F_on = 5000Hz, 비트 레이트 = 10 비트 / s)을 사용하여 신호를 변조 한 다음 헤더와 종료 시퀀스를 추가하여 신호를 추가합니다 (물론 변조). 헤더와 종료 시퀀스는 임시로 선택되었습니다 (예 : 핵).

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];

그런 다음 소리로 전송하여 스마트 폰으로 녹음했습니다. 그런 다음 녹음 된 오디오를 컴퓨터로 다시 보내고 다른 코드를 사용하여 오디오를 읽습니다. 그런 다음 수신 된 신호 (아직 복조되지 않은)를 변조 된 헤더 및 종료 시퀀스와 상관시켜 시작과 끝을 찾습니다. 그 후 관련 신호 (상관 부분에서 찾은 것처럼 처음부터 끝까지) 만 가져옵니다. 그런 다음 복조하고 샘플링하여 디지털 데이터를 찾습니다. 다음은 3 개의 오디오 파일입니다.

  • "DigitalCommunication_ask": 여기에 링크 하면 "Digital communication"이라는 텍스트가 전송됩니다. 처음과 끝에서 약간의 배경 소음을들을 수 있지만 비교적 소음이 없습니다. 그러나 결과는 "Digital Commincatio"만 보여주었습니다.

  • "HelloWorld_ask": 여기에 링크 하면 "Hello world"라는 텍스트가 전송됩니다. "DigitalCommunication_ask"와 같은 잡음이 없습니다. 그러나이 결과는 정확했습니다.

  • "HelloWorld_noise_ask": 여기에 링크 하여 "Hello world"텍스트를 보냅니다. 그러나 내가 만든 약간의 소음이 있습니다 (전송 중에 임의의 물건 "A, B, C, D, E, ...."라고 말한 것입니다). 불행히도이 하나는 실패

발신자 코드 (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);

수신자 (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 변조 코드 (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 복조 (ask_demodulate.m) (기본적으로 그것은 힐버트 변환을 사용한 봉투 감지입니다)

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

왜 작동하지 않습니까? 대단히 감사합니다


이론적으로 (소음이없는 환경에서) 구현하기는 쉽지 않지만 실제로는 훨씬 어렵습니다. 여전히 보내려는 정보 유형에 따라 다릅니다. 가장 작은 노이즈로도 텍스트를 인식 할 수 없기 때문에 텍스트를 안정적으로 전송하기가 매우 어려울 수 있습니다.
dsp_user

@ dsp_user 텍스트를 보내려고합니다. 나는 약간의 오류 ( "Audio"-> "Apdio"와 같은)로 살 수 있습니다. 처음 0을 아십니까? 나는 소음이없는 환경을 의미하지만 처음 1 이전에는 많은 0이있을 것입니까? 그럼 어떻게 알아?
Dang Manh Truong

구식 14.4 모뎀과 같은 아이디어를 찾는 것이 좋습니다.

@StanleyPawlukiewicz 몇 가지 진전이있었습니다. 업데이트를 확인하십시오. 대단히 감사합니다.
Dang Manh Truong

의견이 많습니다. 당신은 당신이 프리앰블 사용하고있는 점을 감안하여 프리앰블에 대한 바커 시퀀스를보고 할 수 있습니다

답변:


8

아시다시피, 디지털 통신을 수행하는 데있어 어려운 부분은 캐리어, 심볼 및 프레임 동기화 및 채널 추정 / 등화입니다.

나쁜 소식은 이러한 문제를 해결할 수 없다는 것입니다. 좋은 소식은 자신을 협 대역 BPSK로 제한하는 한 이러한 구현이 그렇게 어렵지는 않다는 것입니다. 본인은 본인이이 일을했기 때문에 저 (학부생) 학생들도 있습니다 ( http://ieeexplore.ieee.org/document/5739249/ 참조 ).

반송파 동기화 문제를 해결하기위한 간단한 제안 중 하나는 AM DSB-LC를 사용하여 기저 대역 신호를 상향 변환하는 것입니다. 그런 다음 반송파 및 위상 동기화없이 엔벨로프 감지기를 사용할 수 있습니다. 이렇게하면 전력 효율성이 떨어지지 만 우선 순위는 아닙니다.

또 다른 간단한 제안은 "실시간 처리"대신 "일괄 처리"를 수행하는 것입니다. 즉, 수신 된 전체 신호를 저장하고 나중에 처리하십시오. 이는 스트림 또는 실시간 처리보다 구현하기가 훨씬 쉽습니다.

보다 실질적인 제안은이 책을 읽는 것입니다 : Johnson, Sethares 및 Klein, "소프트웨어 수신기 설계", Cambridge. 수신기의 모든 부분을 매우 명확하게 설명하고 Matlab 코드의 예가 많이 있습니다. DSP에서 통신 시스템을 구현하는 것에 관한 Steven Tretter의 비슷한 책이 있습니다 (현재 정확한 제목을 기억할 수는 없습니다).

행운을 빕니다; 질문이 있으시면 새롭고 더 구체적인 질문을하십시오.


나는 당신의 논문을 읽었습니다. 좋은 일을 계속하십시오! 한 가지 질문 :이 논문에서는 학생들이 채널 응답을 찾기 위해 사용하는 몇 가지 방법 (임펄스, 사인파 사용)에 대해 이야기했습니다. 채널 응답도 찾아야합니까? :)
Dang Manh Truong

1
친절한 말에 감사드립니다 :) 문제는 채널 응답이 평평한 주파수 대역을 통해 전송해야한다는 것입니다. 그렇지 않으면 수신기에 이퀄라이저가 필요합니다. 채널 응답을 추정하지 않으려면 모든 오디오 장비가 편한 주파수 (예 : 5000Hz)에서 매우 낮은 데이터 속도 (예 : 100b / s)를 사용하면됩니다.
MBaz December

1
@DangManhTruong 한 가지 더 : 대역폭이 크며 왜곡이 발생할 가능성이 큰 제곱 펄스가 아닌 제곱근 올림 코사인과 같은 대역폭 제한 펄스를 사용해야합니다.
MBaz

나는 당신이 제안한대로 소프트웨어 리시버 디자인 책을 읽었습니다. 그래서 몇 가지 질문이 있습니다. 당신은 맥박에 대해 말했지만 책의 예에서 그들은 해밍 윈도우를 맥박으로 사용했습니다. 그렇다면 괜찮습니까? 그리고 내 이해가 정확합니다 : 먼저 ASK를 사용하여 신호를 변조 한 다음 펄스 형성을 사용하십시오. 그런 다음 수신기에서 먼저 변조 된 신호를 수신하기 위해 펄스 신호와 상관됩니다. 그런 다음 복조합니다. 맞습니까?
Dang Manh Truong

그리고 시작과 끝에 헤더가있는 패킷 형식으로 데이터를 보내려면 1 1 1 1 1 1 1 1과 같이 데이터를 추가하고 변조 한 다음 펄스 모양으로 만들어야합니다. 수신기에서 수신 된 신호를 펄스 모양 (제곱근 올림 코사인 등)과 상관시키고 헤더와 상관 관계가있는 신호를 복조해야합니다. 내 이해가 정확합니까?
Dang Manh Truong

4

결국 DTMF (Dual Tone Multi Frequency signaling)를 사용했습니다. 원래 DTMF에는 2 개의 주파수 조합을 사용하여 각각 16 개의 신호가 있습니다. 그러나 여기서는 "1"(697Hz 및 1209Hz)과 "0"(941Hz 및 1336Hz) 만 사용했습니다.

코드 작동 방식에 대한 개요 :

  • 발신자는 텍스트를 이진으로 변환 한 다음 "0"/ "1"DTMF 신호를 전송합니다 (여기서 톤 지속 시간은 0.3 초, 톤 사이의 무음 기간은 0.1 초). 전송 코드는 https://sites.google.com/a/nd.edu/adsp-nik-kleber/home/advanced-digital-signal-processing/project-3-touch-tone 에서 가져옵니다 . 저자는 디지털 오실레이터를 구현하기 위해 약간 안정적인 IIR 필터를 사용했을 것입니다.
  • 수신기 측은 먼저 "0"과 "1"주파수 성분을 각각 추출하기 위해 엄청나게 높은 순서로 그리고 엄청나게 좁은 대역 통과 필터를 사용합니다.

    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);
    

이 작업이 끝나면 각 "1"및 "0"신호의 시작과 끝을 찾을 수 있습니다. 코드는 https://github.com/codyaray/dtmf-signaling 입니다. 기본적으로 최소 10ms의 무음 기간과 100ms 이상의 톤 기간을 찾습니다.

여기에 이미지 설명을 입력하십시오

(위에서 아래로 : 영점 신호, 평균 필터 이동 후 신호, 임계 값 미만을 제거한 후 신호 차이, 임계 값 후 신호)

  • 먼저 이전 단계의 결과가 정규화되고 이동 평균 필터를 통과했습니다 (필터 크기는 10ms * Fs 임). 결과를 플롯하면 "0"과 "1"의 모양을 명확하게 볼 수 있습니다. 이 경우 봉투 탐지기로 작동하는 것 같습니다.
  • 그런 다음 특정 임계 값 아래의 모든 신호가 차단됩니다 (0.1을 선택했습니다).
  • 마지막으로 시간 간격이 100ms보다 큰 임계 값을 초과하는 모든 간격을 찾으십시오 (이미지에서 코드를 재현 할 수 없다는 점에 유의하십시오).

그런 다음 비트를 조립하고 텍스트로 다시 변환합니다. :)

비디오 데모 : https://www.youtube.com/watch?v=vwQVmNnWa4s , 여기서 내 노트북과 내 형제의 PC 사이에 "Xin chao"텍스트를 보냅니다. :)

P / S : 원래 디지털 커뮤니케이션 교사가 최종 시험을 수행하지 않아도 A를받을 수 있다고 말했기 때문에이 작업을 수행했지만 시험 후에 만이 작업을 수행 할 수있었습니다. 그래서 여기에 모든 노력이갑니다.

P / S2 : 나는 C +를 얻었다 :(


0

동기화가 매우 좋은 오픈 소스 라이브러리를 원한다면 msequences를 사용하여 정렬 한 다음 균등화를 수행하고 페이로드를 복조하는 https://github.com/jgaeddert/liquid-dsp 를 권장 합니다. 나는 정상에서 작동하는 오디오 모뎀을 만들었고 꽤 잘 작동하므로 액체가 없다면 액체의 방법이 도움이되어야합니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.