Transmita datos a través del sonido entre 2 computadoras (muy cerca)

12

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

Dang Manh Truong
fuente
En teoría (en un entorno sin ruido), esto sería trivial de implementar, pero en la práctica esto es mucho más difícil. Aún así, depende del tipo de información que intente enviar. El texto sería extremadamente difícil de transmitir de manera confiable porque incluso el menor ruido haría que el texto fuera irreconocible.
dsp_user
@dsp_user Estoy intentando enviar mensajes de texto. Puedo vivir con algún error (como "Audio" -> "Apdio") :) Además, realmente no entiendo eso, por ejemplo, para Amplitud Shift Keying, cuando tienes 1, envías una onda sinusoidal, 0 y nada más que cómo conoces los primeros 0? Quiero decir, en un entorno libre de ruido, pero antes del primer 1 habría un montón de 0 ¿verdad? Entonces, ¿cómo lo sabes?
Dang Manh Truong
Le sugiero que mire algo como un módem 14.4 anticuado para obtener ideas.
@StanleyPawlukiewicz He progresado un poco. Por favor revise la actualización. Muchas gracias.
Dang Manh Truong
Hay mucho para comentar. Es posible que desee ver las secuencias de Barker para su preámbulo, dado que está usando preámbulos

Respuestas:

8

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.

MBaz
fuente
He leído tu periódico. ¡Sigan con el buen trabajo! Una pregunta: en el artículo, habló sobre varios métodos utilizados por los estudiantes para encontrar la respuesta del canal (usando impulso, ondas sinusoidales, ...). ¿Necesitaría encontrar la respuesta del canal también? :)
Dang Manh Truong
1
Gracias por sus amables palabras :) El hecho es que desea asegurarse de transmitir a través de una banda de frecuencia donde la respuesta del canal es plana; de lo contrario, necesitará un ecualizador en el receptor. Si no desea estimar la respuesta del canal, lo que puede hacer es utilizar una velocidad de datos muy baja (por ejemplo, 100 b / s) en una frecuencia con la que todos los equipos de audio se sientan cómodos (por ejemplo, 5000 Hz).
MBaz
1
@DangManhTruong Una cosa más: asegúrese de utilizar pulsos de ancho de banda limitado, como el coseno elevado de raíz cuadrada, no pulsos cuadrados que tienen un ancho de banda grande y muy probablemente sufrirán distorsiones.
MBaz
Leí el libro Diseño del receptor de software como usted sugirió (en realidad lo hojeé y me concentré en el Capítulo 8: Bits a símbolos a señales). Entonces tengo algunas preguntas. Dijiste algo sobre los pulsos, pero en el ejemplo del libro usaron una ventana de Hamming como pulso, ¿está bien si lo hago? Y entiendo que es correcto: primero modulas la señal usando, por ejemplo, PREGUNTAR, luego usas la configuración del pulso. Luego, en el receptor, primero se correlaciona con la señal de pulso para recibir la señal modulada. Entonces te demodulas. ¿Es correcto?
Dang Manh Truong
Y si deseo enviar datos en forma de paquete, con un encabezado al principio y al final, digamos 1 1 1 1 1 1 1 1, así que debería agregarlos con los datos, luego modularlos y luego darles forma de pulso. En el receptor, correlacionaría la señal recibida con la forma del pulso (coseno elevado de raíz cuadrada, ...) y luego tengo que demodular la señal, después de eso correlacionar con el encabezado. ¿Es correcto mi entendimiento?
Dang Manh Truong
4

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 emisor convierte el texto a binario, luego transmite señales DTMF "0" / "1" (aquí el tiempo es 0.3s para la duración del tono y 0.1s para el período de silencio entre tonos). El código de transmisión se toma de: https://sites.google.com/a/nd.edu/adsp-nik-kleber/home/advanced-digital-signal-processing/project-3-touch-tone . Aparentemente, el autor utilizó un filtro IIR marginalmente estable para implementar un oscilador digital.
  • 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;

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

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

ingrese la descripción de la imagen aquí

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

  • Primero, el resultado del paso anterior se normaliza y luego pasó por un filtro de media móvil (con un tamaño de filtro igual a 10 ms * Fs). Si graficamos el resultado, veríamos que la forma del "0" y "1" se puede ver claramente. Así que creo que en este caso funciona como un detector de sobres.
  • Luego, se corta toda la señal por debajo de cierto umbral (elegí 0.1).
  • Finalmente, encuentre todos los intervalos por encima del umbral que tiene un intervalo de tiempo superior a 100 ms (tenga en cuenta que la imagen no es reproducible desde el código, tendrá que cavar para hacerlo)

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 + :(

Dang Manh Truong
fuente
0

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

Brian Armstrong
fuente