¡Crea un módem (software)!

14

Objetivo

Diseñar un mo / dulator dem par odulator a transmitir los datos con precisión lo más rápidamente posible sobre simulado llanura de servicio telefónico antiguo (POTS) .

Pasos

  1. Genere algunos datos aleatorios ( /dev/randomo similares) que demorarán entre 3 y 4 segundos en transmitirse
  2. Modula los datos con tu modulador para producir un archivo de audio
  3. Pase el archivo de audio a través del simulador POTS . Si no tiene Python / Scipy, puede cargar un archivo con el formulario o hacer una solicitud de API JSON.
  4. Demodular el archivo de audio de nuevo a datos binarios
  5. Valide que la entrada y la salida son iguales * (el límite 1 de cada 1000 bits puede estar dañado)
  6. La puntuación es el número de bits transmitidos dividido por la longitud del archivo de audio (bits / segundo)

Reglas

  • El archivo de entrada debe ser de 3-4 segundos, 44,1 kHz, mono.
  • Ejecute el simulador con una SNR de 30 dB (es el valor predeterminado)
  • El demodulador debe reconstruir los datos transmitidos con una tasa de error de bits de no más de 10-3 (1 por cada mil bits).
  • No se permite la compresión digital (es decir, comprimir los datos. Está fuera del alcance del desafío).
  • No intentar introducir datos en frecuencias superiores a 4 kHz. (Mis filtros no son perfectos, pero son razonablemente similares a POTS con un número relativamente pequeño de toques).
  • Si su protocolo de módem requiere un preámbulo corto (no más de 1 segundo) para sincronizar / calibrar el receptor, no se penaliza.
  • Si es posible, aloje el archivo de audio en un lugar accesible para que podamos escuchar una cacofonía de pitidos y boops.

Ejemplo

Aquí hay un cuaderno de ejemplo que demuestra la modulación / demodulación con una simple "activación / desactivación" (¡muestras de audio incluidas!).

Anotaría 100 (bits / segundo). Tenga en cuenta que está transmitiendo con una SNR de 5 dB mucho peor.

Nick T
fuente
2
¿Es esto diferente de un desafío común de "comprimir estos datos binarios"? Si es así, ¿podría aclarar cuán exactamente difiere?
Pomo de la puerta
1
Aquí estás modulando datos (convirtiéndolos en algo analógico) y luego al revés. Uno podría llamarlo "compresión analógica"
Nick T
Lo siento, no estoy seguro de entender cómo funciona este desafío. La palabra "modular" ni siquiera aparece en el artículo de Wikipedia que vinculó. ¿Podría incluir más información de fondo o aclarar las especificaciones?
Pomo de la puerta
44
wget wikipedia.org/Special:Random | grep title | texttospeech audio.wav speechtotext POTSaudio.wav | wget wikipedia/wiki/$text
TessellatingHeckler
1
Este es un desafío increíble, ¡intentaré encontrar el tiempo para enviar una respuesta!
GoatInTheMachine

Respuestas:

7

MATLAB, 1960 pb

Aquí está mi intento actualizado:

fs = 44100; %44.1kHz audio rate
fc = 2450;  %2.45kHz carrier - nice fraction of fs!
fsym = fc/5; %symbol rate

tmax = 4; %about 4 seconds worth

preamblesyms = 6;

t = 1/fs:1/fs:(tmax+preamblesyms/fsym);

symbols = preamblesyms+fsym*tmax;
symbollength = length(t)/symbols;
bits = symbols*3;
bitstream = [zeros(1,preamblesyms*3),rand(1,bits-preamblesyms*3)>0.5]; %Add a little preamble of 18 bits
data = bin2dec(char(reshape(bitstream,3,symbols)'+'0'))';

greycode = [0 1 3 2 6 7 5 4];

%Encode the symbols using QAM8 - we use effectively grey code so that
%adjacent symbols in the constellation have only one bit difference
%(minimises error rate)
encoded = zeros(2,symbols);
encoded(1,data==1) = 1/sqrt(2);
encoded(1,data==3) = 1;
encoded(1,data==2) = 1/sqrt(2);
encoded(1,data==7) = -1/sqrt(2);
encoded(1,data==5) = -1;
encoded(1,data==4) = -1/sqrt(2);
encoded(2,data==0) = 1;
encoded(2,data==1) = 1/sqrt(2);
encoded(2,data==2) = -1/sqrt(2);
encoded(2,data==6) = -1;
encoded(2,data==7) = -1/sqrt(2);
encoded(2,data==4) = 1/sqrt(2);

%Modulate onto carrier
carrier = [sin(2*pi*fc*t);cos(2*pi*fc*t)];
signal = reshape(repmat(encoded(1,:)',1,symbollength)',1,[]);
signal(2,:) = reshape(repmat(encoded(2,:)',1,symbollength)',1,[]);
modulated = sum(signal.*carrier)';

%Write out an audio file
audiowrite('audio.wav',modulated,fs);

%Wait for the user to run through the POTS simulator
input('');

%Read in the filtered data
filtered=audioread('audio.pots-filtered.wav')';

%Recover the two carrier signals
preamblecos = filtered(symbollength+1:symbollength*2);
preamblesin = filtered(symbollength+1+round(symbollength*3/4):symbollength*2+round(symbollength*3/4));

%Replicated the recovered carriers for all symbols
carrierfiltered = [repmat(preamblesin,1,symbols);repmat(preamblecos,1,symbols)];

%Generate a demodulation filter (pass up to 0.66*fc, stop at 1.33*fc
%(really we just need to kill everything around 2*fc where the alias ends up)
d=fdesign.lowpass('Fp,Fst,Ap,Ast',0.05,0.1,0.5,60);
Hd = design(d,'equiripple');

%Demodulate the incoming stream
demodulated = carrierfiltered .* [filtered;filtered];
demodulated(1,:)=filtfilt(Hd.Numerator,1,demodulated(1,:));
demodulated(2,:)=filtfilt(Hd.Numerator,1,demodulated(2,:));

%Split signal up into bit periods
recovereddemodulated=[];
recovereddemodulated(1,:,:) = reshape(demodulated(1,:),symbollength,symbols);
recovereddemodulated(2,:,:) = reshape(demodulated(2,:),symbollength,symbols);

%Extract the average level for each bit period. Only look at the second
%half to account for slow rise times in the signal due to filtering
recoveredsignal=mean(recovereddemodulated(1,round(symbollength/2):symbollength,:));
recoveredsignal(2,:)=mean(recovereddemodulated(2,round(symbollength/2):symbollength,:));

%Convert the recovered signal into a complex number.
recoveredsignal=recoveredsignal(2,:) + 1j*recoveredsignal(1,:);

%Determine the magnitude and angle of the symbol. The phase is normalised
%to pi/4 as that is the angle between the symbols. Rounding this to the
%nearest integer will tell us which of the 8 phases it is closest to
recoveredphase = round(angle(recoveredsignal)/(pi/4));
recoveredphase = mod(recoveredphase+8,8)+1; %Remap to an index in the grey code vector.

%Determine the symbol in the QAM8 constellation
recoveredencoded=greycode(recoveredphase);
recoveredencoded(1:preamblesyms)=0; %Assume the preamble is correct for comparison

%Turn it back in to a bit stream
bitstreamRecovered = reshape(dec2bin(recoveredencoded)'-'0',1,[]);

%And check if they are all correct...
if(all(bitstream==bitstreamRecovered))
    disp(['Woop, ' num2str(fsym*4) 'bps']);
else
    error('Its corrupt Jim.');
end

Desde mi primer intento, he jugado un poco. Ahora hay un pequeño preámbulo al principio (períodos de 18 bits, pero podría ser más corto) que contiene solo una onda cosenoidal. Extraigo esto y lo repliqué para crear portadores de seno y coseno en fase correcta para la demodulación, ya que es un preámbulo muy corto, no lo he contado en la tasa de bits según sus instrucciones.

Además, desde el primer intento, ahora estoy usando una constelación QAM8 para lograr 3 bits por símbolo en lugar de 2. Esto efectivamente duplica la velocidad de transferencia. Entonces, con una portadora de ~ 2.4kHz, ahora estoy alcanzando 1960bps.

También he mejorado la detección de símbolos para que el promedio no se vea afectado por los tiempos de aumento lentos causados ​​por el filtrado; básicamente, solo se promedia la segunda mitad de cada período de bits para eliminar el impacto de los tiempos de aumento.

Todavía no está cerca del ancho de banda del canal teórico de 40 kbps de la teoría de Shannon-Hartley (suponiendo que la SNR de )

Solo para aquellos a quienes les gustan los sonidos horribles , esta es la nueva entrada:


Y en caso de que alguien esté interesado, esta es la entrada anterior de 960bps

Tom Carpenter
fuente
La puntuación es solo la tasa de transferencia, así que mantenga su código claro. Agregué una sugerencia para alojar su archivo de audio en algún lugar si es fácil para las diversiones: D
Nick T
Subiré el audio a mi sitio. ¡Suena bastante extraño!
Tom Carpenter el
Archivo de audio @NickT cargado: vea el enlace en la parte inferior de la publicación.
Tom Carpenter
Si tiene una cuenta de SoundCloud, puede cargar su audio y publicar un enlace y se podrá reproducir en su publicación. ( Ejemplo )
Hobbies de Calvin
@NickT gracias. He creado una cuenta de soundcloud y la he subido. También hice una versión actualizada con el doble de velocidad de datos :)
Tom Carpenter