Tạo một modem (phần mềm)!


14

Mục tiêu

Thiết kế một cặp trình giả lập mo / dem od để truyền dữ liệu chính xác nhanh nhất có thể qua dịch vụ điện thoại cũ đơn giản mô phỏng (POTS) .

Các bước

  1. Tạo một số /dev/randomdữ liệu ngẫu nhiên ( hoặc tương tự) sẽ mất 3-4 giây để truyền
  2. Điều chỉnh dữ liệu với bộ điều biến của bạn để tạo tệp âm thanh
  3. Truyền tệp âm thanh qua trình giả lập POTS . Nếu bạn không có Python / Scipy, bạn có thể tải lên một tệp có biểu mẫu hoặc thực hiện một yêu cầu API JSON.
  4. Giải điều chế tệp âm thanh trở lại dữ liệu nhị phân
  5. Xác thực rằng đầu vào và đầu ra bằng nhau * (giới hạn 1 trong số 1000 bit có thể bị hỏng)
  6. Điểm là số bit được truyền chia cho chiều dài của tệp âm thanh (bit / giây)

Quy tắc

  • Tệp đầu vào phải là 3-4 giây, 44,1 kHz, đơn âm.
  • Chạy trình giả lập với SNR là 30 dB (mặc định)
  • Bộ giải mã phải xây dựng lại dữ liệu được truyền với tỷ lệ lỗi bit không quá 10 -3 (1 phần nghìn bit).
  • Không cho phép nén kỹ thuật số (tức là nén dữ liệu. Nó nằm ngoài phạm vi của thách thức.)
  • Không cố gắng chuyển dữ liệu thành tần số trên 4 kHz. (Bộ lọc của tôi không hoàn hảo, nhưng chúng tương đối giống POTS với số lượng vòi tương đối nhỏ.)
  • Nếu giao thức modem của bạn yêu cầu một lời mở đầu ngắn (không quá 1 giây) để đồng bộ hóa / hiệu chỉnh máy thu, nó sẽ không bị phạt.
  • Nếu có thể, vui lòng lưu trữ tệp âm thanh ở một nơi nào đó có thể truy cập để chúng tôi có thể nghe một âm thanh của tiếng bíp và tiếng kêu.

Thí dụ

Dưới đây là một sổ ghi chép ví dụ minh họa điều chế / giải điều chế với "khóa bật tắt" đơn giản (bao gồm các mẫu âm thanh!).

Nó sẽ đạt 100 điểm (bit / giây). Lưu ý rằng nó đang truyền với SNR 5 dB tồi tệ hơn nhiều.


2
Điều này có khác với một thách thức "nén dữ liệu nhị phân" thông thường này không? Nếu vậy, bạn có thể làm rõ chính xác nó khác nhau như thế nào?
Doorknob

1
Ở đây bạn đang điều chỉnh dữ liệu (biến nó thành một cái gì đó tương tự) sau đó ngược lại. Người ta có thể gọi nó là "nén tương tự"
Nick T

Xin lỗi, tôi không chắc tôi hiểu thử thách này hoạt động như thế nào. Từ "điều chế" thậm chí không xuất hiện trong bài viết Wikipedia mà bạn đã liên kết. Bạn có thể bao gồm thêm thông tin cơ bản, hoặc làm rõ thông số kỹ thuật?
Doorknob

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

1
Đây là một thử thách tuyệt vời, tôi sẽ cố gắng tìm thời gian để gửi câu trả lời!
DêInTheMachine

Câu trả lời:


7

MATLAB, 1960 bps

Đây là nỗ lực cập nhật của tôi:

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

Kể từ lần thử đầu tiên, tôi đã chơi xung quanh một chút. Bây giờ có một lời mở đầu nhỏ ở đầu (chu kỳ 18 bit, nhưng có thể ngắn hơn) chỉ chứa một sóng cosin. Tôi trích xuất cái này và sao chép nó để tạo ra các sóng mang sin và cosine chính xác để giải điều chế - vì nó là một đoạn đầu rất ngắn, tôi đã không tính nó theo tốc độ bit theo hướng dẫn của bạn.

Ngoài ra, kể từ lần thử đầu tiên, tôi hiện đang sử dụng chòm sao QAM8 để đạt được 3 bit cho mỗi ký hiệu thay vì 2. Điều này giúp tăng gấp đôi tốc độ truyền. Vì vậy, với sóng mang ~ 2,4kHz, giờ đây tôi đạt được 1960bps.

Tôi cũng đã cải thiện khả năng phát hiện biểu tượng để tính trung bình không bị ảnh hưởng bởi thời gian tăng chậm do quá trình lọc gây ra - về cơ bản chỉ nửa sau của mỗi giai đoạn bit được lấy trung bình để loại bỏ tác động của thời gian tăng.

Vẫn không có nơi nào gần băng thông kênh lý thuyết 40kbps từ lý thuyết Shannon-Hartley (giả sử SNR 30dB)

Chỉ dành cho những người thích âm thanh khủng khiếp , đây là mục mới:


Và trong trường hợp bất cứ ai quan tâm, đây là mục nhập 960bps trước đó


Ghi điểm chỉ là tốc độ truyền, vì vậy hãy giữ mã của bạn rõ ràng. Tôi đã thêm một đề xuất để lưu trữ tệp âm thanh của bạn ở đâu đó nếu dễ dàng cho các cuộc vui: D
Nick T

Tôi sẽ tải âm thanh lên trang web của tôi. Nghe có vẻ khá kỳ cục!
Tom Carpenter

@NickT tệp âm thanh được tải lên - xem liên kết ở cuối bài.
Tom Carpenter

Nếu bạn có tài khoản SoundCloud, bạn có thể tải lên âm thanh của mình và đăng một liên kết và nó sẽ có thể phát trong bài đăng của bạn. ( Ví dụ )
Sở thích của Calvin

@NickT cảm ơn. Tôi đã tạo một tài khoản soundcloud và tải nó lên. Tôi cũng đã tạo một phiên bản cập nhật với tốc độ dữ liệu gấp đôi :)
Tom Carpenter
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.