Estoy escribiendo un ejemplo sobre la transmisión de datos a través del sonido entre 2 computadoras. Algunos requisitos:
La distancia es muy cercana, es decir, las 2 computadoras son básicamente adyacentes entre sí
Muy poco ruido (no creo que mi maestro encienda una canción de rock como fuente de ruido)
El error es aceptable: por ejemplo, si envío "Radiocomunicación", entonces si la otra computadora recibe "RadiQ communEcation", también está bien.
Si es posible: sin encabezado, bandera, suma de verificación, ... ya que solo quiero un ejemplo muy básico que demuestre los conceptos básicos de la transmisión de datos a través del sonido. No hay necesidad de ser elegante.
Intenté usar Audio Frequency Shift Keying de acuerdo con este enlace:
Lab 5 APRS (Sistema automático de informes de paquetes)
y obtuve algunos resultados: mi página de Github
Pero no es suficiente. No sé cómo hacer la recuperación del reloj, la sincronización, ... (el enlace tiene un bucle de fase bloqueada como mecanismo de recuperación de tiempo, pero aparentemente no fue suficiente).
Así que creo que debería encontrar un enfoque más simple. Encontrado un enlace aquí:
Datos a audio y viceversa. Modulación / demodulación con código fuente
pero el OP no implementó el método sugerido en la respuesta, por lo que me temo que podría ser muy complejo. Además, no entiendo claramente el método de decodificación sugerido en la respuesta:
El decodificador es un poco más complicado pero aquí hay un resumen:
Opcionalmente, el filtro de paso de banda filtra la señal muestreada alrededor de 11Khz. Esto mejorará el rendimiento en un entorno ruidoso. Los filtros FIR son bastante simples y hay algunos applets de diseño en línea que generarán el filtro por usted.
Umbral de la señal. Cada valor por encima de 1/2 amplitud máxima es 1, cada valor por debajo es 0. Esto supone que ha muestreado la señal completa. Si esto es en tiempo real, puede elegir un umbral fijo o hacer algún tipo de control automático de ganancia en el que rastrea el nivel máximo de señal durante un tiempo.
Escanee para el inicio del punto o guión. Probablemente desee ver al menos un cierto número de 1 en su período de puntos para considerar las muestras como un punto. Luego siga escaneando para ver si esto es un guión. No espere una señal perfecta: verá unos pocos 0 en el medio de sus 1 y unos pocos en el medio de sus 0. Si hay poco ruido, diferenciar los períodos de "encendido" de los períodos de "apagado" debería ser bastante fácil.
Luego invierta el proceso anterior. Si ve un guión empuje un bit a su búfer, si un punto empuja un cero.
No entiendo cuántos 1 antes de clasificarlo como un punto, ... Así que hay muchas cosas que no entiendo en este momento. Sugiéreme un método simple para transmitir datos a través del sonido para que pueda entender el proceso. Muchas gracias :)
ACTUALIZAR:
He creado un código de Matlab que parece estar (algo) operativo. Primero modulo la señal usando la codificación de cambio de amplitud (frecuencia de muestreo 48000 Hz, F_on = 5000 Hz, velocidad de bits = 10 bits / s), luego la agrego con un encabezado y una secuencia final (por supuesto, modúlelos también). El encabezado y la secuencia final se eligieron ad-hoc (sí, fue un truco):
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];
Luego los transmití a través del sonido y lo grabé con mi teléfono inteligente. Luego envío el audio grabado a mi computadora, uso otro código para leer el audio. Luego correlaciono la señal recibida (aún no demodulada) con el encabezado modulado y la secuencia final para descubrir el principio y el final. Después de eso, tomo solo la señal relevante (desde el principio hasta el final, como se encuentra en la parte de correlación). Luego demodulo y muestro para encontrar los datos digitales. Aquí hay 3 archivos de audio:
"DigitalCommunication_ask": el enlace aquí envía el texto "Comunicación digital". Relativamente libre de ruido, aunque puede escuchar algo de ruido de fondo al principio y al final. Sin embargo, el resultado mostró solo "Commincatio digital"
"HelloWorld_ask": el enlace aquí envía el texto "Hola mundo". Libre de ruido como "DigitalCommunication_ask". Sin embargo, el resultado para este fue correcto
"HelloWorld_noise_ask": el enlace aquí envía el texto "Hola mundo". Sin embargo, hay algo de ruido que he hecho (acabo de decir algunas cosas al azar "A, B, C, D, E, ...." durante la transmisión). Lamentablemente este falló
Aquí está el código para el remitente (remitente.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 el receptor (receptor.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
PIDA el código de modulación (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) (Básicamente es solo detección de envolvente, para lo cual utilicé la transformación de 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 dime por qué no funciona? Muchas gracias
fuente
Respuestas:
Como se habrá dado cuenta, la parte difícil de hacer comunicaciones digitales es la sincronización de portadores, símbolos y tramas, y la estimación / ecualización de canales.
La mala noticia es que no puede solucionar estos problemas. La buena noticia es que implementarlos no es tan difícil, siempre y cuando se limite a BPSK de banda estrecha. Lo sé, porque lo hice yo mismo, y también mis alumnos (de pregrado) (ver http://ieeexplore.ieee.org/document/5739249/ )
Una sugerencia simple para solucionar el problema de la sincronización de la portadora es usar AM DSB-LC para convertir su señal de banda base. Luego, puede usar un detector de envolvente sin portador y sincronización de fase. Esto le costará en eficiencia energética, pero eso no es una prioridad en su caso.
Otra sugerencia simple es hacer "procesamiento por lotes" en lugar de "procesamiento en tiempo real"; lo que eso significa es, almacenar toda la señal recibida y procesarla después. Esto es mucho más fácil de implementar que la transmisión o el procesamiento en tiempo real.
Mi sugerencia más sustancial es leer este libro: Johnson, Sethares y Klein, "Diseño del receptor de software", Cambridge. Explica en términos muy claros cada pieza del receptor y tiene muchos ejemplos de código Matlab. Hay un libro similar de Steven Tretter, sobre la implementación de un sistema de comunicaciones en un DSP (no puedo recordar el título exacto en este momento).
Buena suerte; y haga preguntas nuevas y más específicas si las tiene.
fuente
Al final, usé DTMF (señalización de frecuencia múltiple de doble tono). El DTMF original tiene 16 señales cada una usando una combinación de 2 frecuencias. Pero aquí solo usé "1" (697 Hz y 1209 Hz) y "0" (941Hz y 1336 Hz)
Un resumen de cómo funciona el código:
El lado del receptor primero utiliza 2 filtros de paso de banda ridículamente altos ordenados y ridículamente estrechos para extraer los componentes de frecuencia "0" y "1", respectivamente:
filter_order = 1000;
Una vez hecho esto, encontraremos el principio y el final de cada señal "1" y "0". El código es de https://github.com/codyaray/dtmf-signaling . Básicamente encuentra el período de silencio que es de al menos 10 ms y cualquier período de tono de más de 100 ms):
(De arriba a abajo: señal cero, señal después del filtro de promedio móvil, diferencia de señal después de eliminar las que están por debajo del umbral, señal después del umbral)
Luego ensamblamos los bits y los convertimos nuevamente en texto :)
Video de demostración: https://www.youtube.com/watch?v=vwQVmNnWa4s , donde envío el texto "Xin chao" entre mi computadora portátil y la PC de mi hermano :)
P / S: Originalmente hice esto porque mi maestro de Comunicación Digital dijo que quien hiciera esto obtendría una A sin tener que hacer el examen final, pero solo pude hacerlo después del examen. Así que aquí van todos mis esfuerzos :(
P / S2: obtuve un C + :(
fuente
Si desea una biblioteca de código abierto con muy buena sincronización, le recomiendo https://github.com/jgaeddert/liquid-dsp que usa secuencias m para alinear, luego iguala y demodula la carga útil. Creé un módem de audio que se ejecuta en la parte superior y funciona bastante bien, por lo que, si nada más, los métodos de líquido deberían ser de alguna ayuda
fuente