(Yazılım) modem yapın!


14

Amaç

Simüle edilmiş düz eski telefon hizmeti (POTS) üzerinden verileri mümkün olduğunca hızlı bir şekilde iletmek için bir mo dulator / dem odulator çifti tasarlayın .

adımlar

  1. /dev/randomİletilmesi 3-4 saniye sürecek bazı rastgele ( veya benzeri) veriler oluşturun
  2. Bir ses dosyası oluşturmak için verileri modülatörünüzle değiştirin
  3. Ses dosyasını POTS simülatöründen geçirin . Python / Scipy'niz yoksa, formu içeren bir dosya yükleyebilir veya bir JSON API isteği yapabilirsiniz.
  4. Ses dosyasını ikili verilere dönüştürün
  5. Giriş ve çıkışın eşit ish * olduğunu doğrulayın (her 1000 bit için limit 1 bozulabilir)
  6. Skor, iletilen bit sayısının ses dosyasının uzunluğuna (bit / saniye) bölünmesidir

kurallar

  • Giriş dosyası 3-4 saniye, 44.1 kHz, mono olmalıdır.
  • Simülatörü 30 dB SNR ile çalıştırın (varsayılan)
  • Demodülatör, iletilen verileri 10-3'ten (bin bit başına 1) fazla olmayan bir hata oranıyla yeniden yapılandırmalıdır .
  • Dijital sıkıştırmaya izin verilmez (yani verilerin sıkıştırılması. Zorluğun kapsamı dışındadır.)
  • 4 kHz üzerindeki frekanslara veri aktarmaya çalışmaz. (Filtrelerim mükemmel değil, ancak nispeten az sayıda dokunuşla makul POTS benzeri.)
  • Modem protokolünüz alıcıyı senkronize etmek / kalibre etmek için kısa bir giriş (en fazla 1 saniye) gerektiriyorsa, cezalandırılmaz.
  • Mümkünse, ses dosyasını bir bip sesi ve bip seslerini dinleyebilmemiz için erişilebilir bir yerde barındırın.

Misal

İşte bir var örnek dizüstü "açma-kapama anahtarlama" basit ile modülasyon / demodülasyon göstermektedir (dahil ses örneklerinin!).

100 (bit / saniye) puanı alır. Çok daha kötü bir 5 dB SNR ile iletim yaptığını unutmayın.


2
Bu sıradan bir "bu ikili verileri sıkıştır" zorluğundan farklı mıdır? Eğer öyleyse, ne kadar kesin olarak farklı olduğunu açıklayabilir misiniz?
Kapı Tokmağı

1
Burada verileri modüle ediyorsunuz (analog bir şeye dönüştürüyorsunuz) ve bunun tersi. Biri buna "analog sıkıştırma" diyebilir
Nick T

Üzgünüm, bu zorluğun nasıl çalıştığını anladığımdan emin değilim. "Değiştir" kelimesi, bağladığınız Wikipedia makalesinde bile görünmüyor. Daha fazla arka plan bilgisi ekleyebilir veya spesifikasyonu açıklayabilir misiniz?
Kapı tokmağı

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

1
Bu harika bir meydan okuma, cevap vermek için zaman bulmaya çalışacağım!
GoatInTheMachine

Yanıtlar:


7

MATLAB, 1960 baz puan

İşte benim güncellenmiş girişimim:

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

İlk denememden beri biraz oynadım. Artık başlangıçta sadece bir kosinüs dalgası içeren küçük bir giriş vardır (18 bitlik dönemler, ancak daha kısa olabilir). Bunu ayıkladım ve demodülasyon için doğru aşamalı sinüs ve kosinüs taşıyıcıları oluşturmak için çoğalttım - çok kısa bir önsöz olduğu için, talimatlarınıza göre bit hızında saymadım.

Ayrıca ilk denemeden beri şimdi 2 yerine sembol başına 3 bit elde etmek için bir QAM8 takımyıldızı kullanıyorum. Bu, aktarım hızını etkili bir şekilde iki katına çıkarıyor. Yani ~ 2.4kHz'lik bir taşıyıcıyla şimdi 1960bps'ye ulaşıyorum.

Ayrıca sembol algılamayı geliştirdim, böylece ortalama, filtrelemenin neden olduğu yavaş yükselme sürelerinden etkilenmez - temel olarak yükselme sürelerinin etkisini ortadan kaldırmak için her bit döneminin yalnızca ikinci yarısının ortalaması alınır.

Shannon-Hartley teorisinden 40kbps teorik kanal bant genişliğine yakın bir yerde (30dB SNR olduğu varsayılarak)

Sadece korkunç sesleri sevenler için , bu yeni giriş:


Ve herhangi birinin ilgilenmesi durumunda, bu önceki 960bps girişi


Puanlama yalnızca aktarım hızıdır, bu nedenle kodunuzu açık tutun. Eğlenceler için kolaysa ses dosyanızı bir yere ev sahipliği yapmak için bir öneri ekledim: D
Nick T

Sesi siteme yükleyeceğim. Kulağa oldukça ürkütücü geliyor!
Tom Carpenter

@NickT ses dosyası yüklendi - yayının altındaki bağlantıya bakın.
Tom Carpenter

Bir SoundCloud hesabınız varsa, sesinizi yükleyebilir ve bir bağlantı gönderebilirsiniz; bu, yayınınızda çalınabilir. ( Örnek )
Calvin'in Hobileri

@NickT teşekkürler. Bir soundcloud hesabı oluşturdum ve yükledim. Ayrıca veri hızının iki katı ile güncellenmiş bir sürüm yaptım :)
Tom Carpenter
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.