Fabriquez un modem (logiciel)!


14

Objectif

Concevoir un mo dulator / dem paire odulator de données avec précision transmettre le plus rapidement possible sur simulé service téléphonique ordinaire (POTS) .

Pas

  1. Générez des données aléatoires ( /dev/randomou similaires) dont la transmission prendra 3 à 4 secondes
  2. Modulez les données avec votre modulateur pour produire un fichier audio
  3. Faites passer le fichier audio via le simulateur POTS . Si vous n'avez pas Python / Scipy, vous pouvez télécharger un fichier avec le formulaire ou faire une demande d'API JSON.
  4. Démoduler le fichier audio en données binaires
  5. Validez que l'entrée et la sortie sont égales * (la limite 1 sur 1000 bits peut être corrompue)
  6. Le score est le nombre de bits transmis divisé par la longueur du fichier audio (bits / seconde)

Règles

  • Le fichier d'entrée doit être de 3-4 secondes, 44,1 kHz, mono.
  • Exécutez le simulateur avec un SNR de 30 dB (c'est par défaut)
  • Le démodulateur doit reconstruire les données transmises avec un taux d'erreur sur les bits ne dépassant pas 10 -3 (1 pour mille bits).
  • Aucune compression numérique n'est autorisée (c.-à-d. Compresser les données. Cela sort du cadre du défi.)
  • Aucune tentative de pousser des données dans des fréquences supérieures à 4 kHz. (Mes filtres ne sont pas parfaits, mais ils sont raisonnablement de type POTS avec un nombre relativement faible de prises.)
  • Si votre protocole de modem nécessite un préambule court (pas plus d'une seconde) pour synchroniser / calibrer le récepteur, il n'est pas pénalisé.
  • Si possible, veuillez héberger le fichier audio dans un endroit accessible afin que nous puissions écouter une cacophonie de bips et de boops.

Exemple

Voici un exemple de cahier qui illustre la modulation / démodulation avec une simple "activation / désactivation" (échantillons audio inclus!).

Il marquerait 100 (bits / seconde). Notez qu'il transmet avec un SNR 5 dB bien pire.


2
Est-ce différent d'un défi ordinaire de "compresser ces données binaires"? Si oui, pourriez-vous préciser en quoi cela diffère précisément?
Poignée de porte

1
Ici, vous modulez des données (en les transformant en quelque chose d'analogue) puis l'inverse. On pourrait peut-être l'appeler "compression analogique"
Nick T

Désolé, je ne suis pas sûr de comprendre comment ce défi fonctionne. Le mot "moduler" n'apparaît même pas dans l'article Wikipedia que vous avez lié. Pourriez-vous inclure plus d'informations générales ou clarifier les spécifications?
Poignée de porte

4
wget wikipedia.org/Special:Random | grep title | texttospeech audio.wav speechtotext POTSaudio.wav | wget wikipedia/wiki/$text
TessellatingHeckler

1
Ceci est un formidable défi, je vais essayer de trouver le temps de soumettre une réponse!
GoatInTheMachine

Réponses:


7

MATLAB, 1960 bps

Voici ma tentative mise à jour:

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

Depuis ma première tentative, j'ai joué un peu. Il y a maintenant un petit préambule au début (périodes de 18 bits, mais pourrait être plus court) qui contient juste une onde cosinus. Je l'extrait et le reproduis pour créer des porteurs de sinus et cosinus correctement phasés pour la démodulation - comme il s'agit d'un préambule très court, je ne l'ai pas compté dans le débit binaire selon vos instructions.

De plus, depuis la première tentative, j'utilise maintenant une constellation QAM8 pour obtenir 3 bits par symbole au lieu de 2. Cela double effectivement le taux de transfert. Donc, avec une porteuse ~ 2,4 kHz, j'atteins maintenant 1960 bps.

J'ai également amélioré la détection des symboles afin que la moyenne ne soit pas affectée par les temps de montée lents causés par le filtrage - en gros, seule la seconde moitié de chaque période de bit est moyenne pour supprimer l'impact des temps de montée.

Toujours loin de la bande passante théorique de 40 kbps de la théorie de Shannon-Hartley (en supposant le SNR de 30 dB)

Juste pour ceux qui aiment les sons horribles , voici la nouvelle entrée:


Et si quelqu'un est intéressé, il s'agit de l'entrée précédente à 960 bps


La notation n'est que le taux de transfert, alors gardez votre code clair. J'ai ajouté une suggestion pour héberger votre fichier audio quelque part si c'est facile pour les drôles: D
Nick T

Je téléchargerai l'audio sur mon site. Cela semble plutôt inquiétant!
Tom Carpenter, du

@NickT audio file upload - see the link at the bottom of the post.
Tom Carpenter

Si vous avez un compte SoundCloud, vous pouvez télécharger votre audio et publier un lien et il sera jouable dans votre message. ( Exemple )
Hobbies de Calvin

@NickT merci. J'ai créé un compte soundcloud et l'ai téléchargé. J'ai également fait une version mise à jour avec le double du débit de données :)
Tom Carpenter
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.