Transmitir dados através do som entre 2 computadores (distância muito próxima)

12

Estou escrevendo um exemplo de transmissão de dados através de som entre computadores. Alguns requisitos:

  • A distância é muito próxima, ou seja, os 2 computadores são basicamente adjacentes um ao outro

  • Muito pouco ruído (acho que meu professor não ligaria uma música de rock como fonte de ruído)

  • O erro é aceitável: por exemplo, se eu enviar "Radiocomunicação", se o outro computador receber "RadiQ communEcation", tudo bem.

  • Se possível: sem cabeçalho, sinalizador, soma de verificação, .... já que eu só quero um exemplo muito básico demonstrando o básico da transmissão de dados através do som. Não precisa ser chique.

Eu tentei usar o Audio Frequency Shift Keying de acordo com este link:

Laboratório 5 APRS (Sistema de Relatório Automático de Pacotes)

e obtive alguns resultados: minha página no Github

Mas não é suficiente. Eu não sei como fazer recuperação de relógio, sincronização, ... (o link tem um loop bloqueado de fase como mecanismo de recuperação de tempo, mas aparentemente não foi suficiente).

Então, acho que devo encontrar uma abordagem mais simples. Encontre um link aqui:

Dados para áudio e vice-versa. Modulação / desmodulação com código fonte

mas o OP não implementou o método sugerido na resposta, portanto, receio que possa ser muito complexo. Também não entendo claramente o método de decodificação sugerido na resposta:

O decodificador é um pouco mais complicado, mas aqui está um esboço:

Opcionalmente, passa-banda filtrar o sinal amostrado em torno de 11Khz. Isso melhorará o desempenho em um ambiente barulhento. Os filtros FIR são bem simples e existem alguns applets de design on-line que irão gerar o filtro para você.

Limite o sinal. Todo valor acima de 1/2 da amplitude máxima é 1 e todo valor abaixo é 0. Isso pressupõe que você tenha amostrado todo o sinal. Se for em tempo real, você escolhe um limite fixo ou realiza algum tipo de controle automático de ganho, onde monitora o nível máximo de sinal ao longo de algum tempo.

Procure o início do ponto ou traço. Você provavelmente deseja ver pelo menos um certo número de 1's no período de pontos para considerar as amostras como um ponto. Continue digitalizando para ver se isso é uma piada. Não espere um sinal perfeito - você verá alguns 0 no meio dos seus 1 e alguns 1 no meio dos seus 0. Se houver pouco ruído, diferenciar os períodos "ligado" dos períodos "desligado" deve ser bastante fácil.

Em seguida, inverta o processo acima. Se você vir o traço, empurre um bit para o buffer, se um ponto empurre um zero.

Eu não entendo quantos 1s são antes de classificá-lo como um ponto ... Então, há muitas coisas que eu não entendo agora. Sugira-me um método simples para transmitir dados através do som, para que eu possa entender o processo. Muito obrigado :)

ATUALIZAR:

Eu criei algum código do Matlab que parece estar (um pouco) operacional. Primeiro modulo o sinal usando a amplitude de mudança de amplitude (frequência de amostragem 48000 Hz, F_on = 5000 Hz, taxa de bits = 10 bits / s), depois adiciono-o com um cabeçalho e uma sequência final (é claro que também os modula). O cabeçalho e a sequência final foram escolhidos ad-hoc (sim, foi um 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];

Então eu os transmito através do som e gravei com o meu smartphone. Depois, envio o áudio gravado de volta para o meu computador, use outro código para ler o áudio. Então eu correlaciono o sinal recebido (ainda não desmodulado) com o cabeçalho modulado e a sequência final para descobrir o começo e o fim. Depois disso, pego apenas o sinal relevante (do começo ao fim, como encontrado na parte de correlação). Então eu desmodulo e faço uma amostra para encontrar os dados digitais. Aqui estão 3 arquivos de áudio:

  • "DigitalCommunication_ask": link aqui envia o texto "Comunicação digital". Relativamente livre de ruído, embora você possa ouvir algum ruído de fundo no início e no final. No entanto, o resultado mostrou apenas "Digital Commincatio"

  • "HelloWorld_ask": link aqui envia o texto "Hello world". Barulho livre como "DigitalCommunication_ask". No entanto, o resultado para este foi correto

  • "HelloWorld_noise_ask": link aqui envia o texto "Hello world". No entanto, houve algum ruído que eu fiz (acabei de dizer algumas coisas aleatórias "A, B, C, D, E, ...." durante a transmissão). Infelizmente este falhou

Aqui está o código para o remetente (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);

Para o receptor (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

Código de modulação ASK (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

Desmodulação ASK (ask_demodulate.m) (Basicamente, é apenas detecção de envelope, para a qual eu usei a transformação Hilbert)

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

Por favor me diga por que não está funcionando? Muito obrigado

Dang Manh Truong
fonte
Em teoria (em um ambiente sem ruído), isso seria trivial de implementar, mas na prática isso é muito mais difícil. Ainda assim, depende do tipo de informação que você está tentando enviar. Seria extremamente difícil transmitir texto de maneira confiável, porque mesmo o menor ruído tornaria o texto irreconhecível.
dsp_user
@dsp_user Estou tentando enviar texto. Eu posso viver com algum erro (como "Áudio" -> "Apdio") :) Também não entendo muito bem, por exemplo, para Amplitude Shift Keying, quando você tem 1, envia uma onda senoidal, 0 e nada além de como você conhece o primeiro 0? Quero dizer, em um ambiente sem ruído, mas antes do primeiro 1 haveria muitos 0, certo? Então como você sabe disso?
Dang Manh Truong
Eu sugiro que você olhe para algo como um modem 14,4 antiquado para idéias.
@StanleyPawlukiewicz Eu fiz alguns progressos. Por favor, verifique a atualização. Muito obrigado.
Dang Manh Truong
Há muito o que comentar. Você pode querer olhar para as sequências Barker para o seu preâmbulo, dado que você está usando preâmbulos

Respostas:

8

Como você percebeu, a parte mais difícil da comunicação digital é a sincronização de portadora, símbolo e quadro e estimativa / equalização de canal.

A má notícia é que você não pode contornar esses problemas. A boa notícia é que implementar isso não é tão difícil, desde que você se limite ao BPSK de banda estreita. Eu sei, porque eu mesmo fiz isso, e também meus alunos (de graduação) (consulte http://ieeexplore.ieee.org/document/5739249/ )

Uma sugestão simples para contornar o problema da sincronização da operadora é usar o AM DSB-LC para converter o sinal da banda de base. Em seguida, você pode usar um detector de envelope sem sincronização de portadora e fase. Isso lhe custará eficiência de energia, mas isso não é uma prioridade no seu caso.

Outra sugestão simples é fazer "processamento em lote" em vez de "processamento em tempo real"; o que isso significa é, armazene todo o sinal recebido e processe-o posteriormente. Isso é muito mais fácil de implementar do que o processamento em fluxo ou em tempo real.

Minha sugestão mais substancial é ler este livro: Johnson, Sethares e Klein, "Software receiver design", Cambridge. Ele explica em termos muito claros todas as partes do receptor e tem muitos exemplos de código Matlab. Existe um livro semelhante de Steven Tretter, sobre a implementação de um sistema de comunicações em um DSP (não me lembro o título exato no momento).

Boa sorte; e faça perguntas novas e mais específicas, se você as tiver.

MBaz
fonte
Eu li o seu jornal. Mantenha o bom trabalho! Uma pergunta: no artigo, você falou sobre vários métodos usados ​​pelos alunos para encontrar a resposta do canal (usando impulso, ondas senoidais, etc.). Eu precisaria encontrar a resposta do canal também? :)
Dang Manh Truong
1
Obrigado por suas amáveis ​​palavras :) O importante é que você deseja transmitir uma faixa de frequência em que a resposta do canal é plana; caso contrário, você precisará de um equalizador no receptor. Se você não deseja estimar a resposta do canal, o que você pode fazer é usar uma taxa de dados muito baixa (por exemplo, 100 b / s) em uma frequência com a qual todos os equipamentos de áudio devem se sentir confortáveis ​​(por exemplo, 5000 Hz).
MBaz 5/17
1
@DangManhTruong Mais uma coisa: certifique-se de usar pulsos com largura de banda limitada, como cosseno elevado de raiz quadrada, não pulsos quadrados com grande largura de banda e provavelmente sofrerão distorções.
MBaz
Li o livro Design do receptor de software, como você sugeriu (na verdade, passei a maior parte do tempo e me concentrei no Capítulo 8: Bits para símbolos para sinais). Então, eu tenho algumas perguntas. Você disse algo sobre pulsos, mas no exemplo do livro eles usaram uma janela de Hamming como pulso, está tudo bem se eu fizer isso? E meu entendimento está correto: primeiro você modula o sinal usando, digamos, ASK, depois usa a modelagem de pulso. Em seguida, no receptor, você primeiro se correlaciona com o sinal de pulso para receber o sinal modulado. Então você desmodula. Está correto?
Dang Manh Truong
E se eu quiser enviar dados em um pacote, com um cabeçalho no início e no final, digamos 1 1 1 1 1 1 1 1, então devo anexá-los aos dados, modulá-los e modificá-los. No receptor, eu correlacionaria o sinal recebido com a forma do pulso (cosseno elevado de raiz quadrada, ...), depois eu tenho que desmodular o sinal, depois que ele estiver correlacionado com o cabeçalho. Meu entendimento está correto?
Dang Manh Truong
4

No final, usei DTMF (sinalização multifreqüencial de tom duplo). O DTMF original possui 16 sinais, cada um usando uma combinação de 2 frequências. Mas aqui eu usei apenas "1" (697 Hz e 1209 Hz) e "0" (941Hz e 1336 Hz)

Um resumo de como o código funciona:

  • O remetente converte o texto em binário e depois transmite os sinais DTMF "0" / "1" (aqui o tempo é de 0,3s para a duração do tom e 0,1s para o período de silêncio entre os tons). O código de transmissão é obtido em: https://sites.google.com/a/nd.edu/adsp-nik-kleber/home/advanced-digital-signal-processing/project-3-touch-tone . Aparentemente, o autor usou um filtro IIR marginalmente estável para implementar um oscilador digital.
  • O lado do receptor primeiro usa 2 filtros passa-banda ridiculamente altos e ordenados e ridiculamente estreitos para extrair os componentes de frequência "0" e "1", respectivamente:

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

Depois disso, encontraremos o início e o fim de cada sinal "1" e "0". O código é de https://github.com/codyaray/dtmf-signaling . Basicamente, encontra o período de silêncio que é de pelo menos 10 ms e qualquer período de tom superior a 100 ms):

insira a descrição da imagem aqui

(De cima para baixo: sinal zero, sinal após mover o filtro médio, diferença de sinal após remover os abaixo do limite, sinal após limiar)

  • Primeiro, o resultado da etapa anterior é normalizado e, em seguida, passou por um filtro de média móvel (com tamanho de filtro igual a 10ms * Fs). Se traçarmos o resultado, veremos que a forma do "0" e "1" pode ser claramente vista. Então eu acho que funciona como um detector de envelope nesse caso.
  • Então todo o sinal abaixo de um certo limite é cortado (eu escolhi 0,1).
  • Por fim, encontre todos os intervalos acima do limite que tenham um intervalo de tempo maior que 100ms (observe que a imagem não é reproduzível a partir do código, você terá que procurar ao redor)

Em seguida, montamos os bits e convertemos novamente em texto :)

Demonstração em vídeo: https://www.youtube.com/watch?v=vwQVmNnWa4s , onde envio o texto "Xin chao" entre o meu laptop e o PC do meu irmão :)

P / S: Originalmente eu fiz isso porque meu professor de Comunicação Digital disse que quem fizesse isso receberia um A sem ter que fazer o exame final, mas só consegui fazer isso após o exame. Então, aqui vão todos os meus esforços :(

P / S2: Eu tenho um C + :(

Dang Manh Truong
fonte
0

Se você deseja uma biblioteca de código aberto com sincronização muito boa, recomendo https://github.com/jgaeddert/liquid-dsp que use sequências para alinhar, faça a equalização e desmodule a carga útil. Eu fiz um modem de áudio que roda em cima e funciona muito bem, então, se nada mais, os métodos da liquid devem ajudar

Brian Armstrong
fonte