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
fonte
Respostas:
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.
fonte
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 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;
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):
(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)
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 + :(
fonte
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
fonte