制作(软件)调制解调器!


14

目的

设计一个MO dulator / DEM odulator对准确地传送数据尽可能快地经模拟普通老式电话服务(POTS)

脚步

  1. 生成一些随机(/dev/random或类似数据)的数据,将需要3-4秒来传输
  2. 使用您的调制器调制数据以生成音频文件
  3. 通过POTS模拟器传递音频文件。如果您没有Python / Scipy,则可以使用表单上传文件,或者发出JSON API请求。
  4. 将音频文件解调回二进制数据
  5. 验证输入和输出是否相等*(每1000位中的限制1个会损坏)
  6. 得分是传输的位数除以音频文件的长度(位数/秒)

规则

  • 输入文件必须为3-4秒,44.1 kHz,单声道。
  • 以30 dB的SNR运行模拟器(默认设置)
  • 解调器必须以不超过10 -3(每千位1个)的误码率重建传输的数据。
  • 不允许数字压缩(即压缩数据。这超出了挑战的范围。)
  • 请勿尝试将数据推入4 kHz以上的频率。(我的过滤器并不完美,但它们的抽头数量相对来说相当像POTS。)
  • 如果您的调制解调器协议需要简短的前同步码(不超过1秒)来同步/校准接收器,则不会受到影响。
  • 如果可能的话,请将音频文件存放在可访问的地方,以便我们听到嘟嘟声。

这是一个示例笔记本,通过简单的“开-关键控”(包括音频样本!)演示了调制/解调。

它将得分为100(位/秒)。请注意,它的发射信噪比差得多,为5 dB。


2
这与普通的“压缩此二进制数据”挑战不同吗?如果是这样,您能否澄清它们之间的差异有多精确?
门把手

1
在这里,您要调制数据(将其转换为模拟信号),然后进行相反的操作。可能有人称其为“模拟压缩”
Nick T

抱歉,我不确定我是否理解此挑战的工作方式。您链接的Wikipedia文章中甚至没有出现“调节”一词。您能否提供更多背景信息或澄清规格?
门把手

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

1
这是一个了不起的挑战,我将尝试寻找时间提交答案!
GoatInTheMachine 2015年

Answers:


7

MATLAB,1960 bps

这是我更新的尝试:

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

自从第一次尝试以来,我已经玩了一些。现在在开头有一个小的前同步码(18位周期,但可能会更短),其中仅包含一个余弦波。我提取并复制了它,以创建正确相位的正弦和余弦载波进行解调-因为这是很短的序言,所以我没有按照您的指示将其计入比特率。

另外,自第一次尝试以来,我现在使用QAM8星座图来实现每个符号3位而不是2位。这实际上使传输速率加倍。因此,使用〜2.4kHz载波,我现在达到1960bps。

我还改进了符号检测,以使平均不会受到滤波引起的缓慢上升时间的影响-基本上,只有每个比特周期的后半部分被平均才能消除上升时间的影响。

Shannon-Hartley理论(假设SNR为30dB)到40kbps理论信道带宽仍然相差甚远

对于那些喜欢恐怖声音的人,这是新条目:


如果有人感兴趣,这是以前的960bps条目


计分只是传输速率,因此请保持代码清晰。我添加了一个建议,可以将您的音频文件托管在易于娱乐的地方:D
Nick T

我将音频上传到我的网站。听起来很可怕!
汤姆·卡彭特

@NickT音频文件已上传-请参阅文章底部的链接。
汤姆·卡彭特

如果您拥有SoundCloud帐户,则可以上传音频并发布链接,该链接将在您的帖子中播放。(示例
加尔文的爱好2015年

@NickT谢谢。我已经创建了一个soundcloud帐户并上传了它。我还制作了更新版本,数据速率提高了一倍:)
汤姆·卡彭特
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.