1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144
|
% ofdm_ldpc_tx.m
% David Rowe April 2017
%
% File based ofdm tx with LDPC encoding and interleaver. Generates a
% file of ofdm samples, including optional channel simulation.
#{
1. 10 seconds, AWGN channel at SNR3k=3dB
octave:4> ofdm_ldpc_tx("test_700d.raw", "700D", 10, 3)
2. 10 seconds, multipath poor channel at SNR=6dB
octave:5> ofdm_ldpc_tx("test_700d.raw", "700D", 10, 6, "mpp")
3. Data mode example, three bursts of one packet each, SNR=100dB:
octave:6> ofdm_ldpc_tx("test_datac0.raw","datac0",1,100,"awgn","bursts",3)
4. Data mode example, three bursts of one packet each, SNR=100dB, with CRC
to enable demodulation by freedv_data_raw_rx:
octave:6> ofdm_ldpc_tx("test_datac0.raw","datac0",1,100,"awgn","bursts",3, "crc")
#}
function ofdm_ldpc_tx(filename, mode="700D", N, SNR3kdB=100, channel='awgn', varargin)
ofdm_lib;
ldpc;
gp_interleaver;
channel_lib;
pkg load signal;
randn('seed',1);
more off;
tx_clip_en = 0; freq_offset_Hz = 0.0; burst_mode = 0; Nbursts = 1;
crc_mode = 0;
i = 1;
while i<=length(varargin)
if strcmp(varargin{i},"txclip")
tx_clip_en = 1;
elseif strcmp(varargin{i},"bursts")
burst_mode = 1;
Nbursts = varargin{i+1}; i++;
elseif strcmp(varargin{i},"crc")
crc_mode = 1;
else
printf("\nERROR unknown argument: %s\n", varargin{i});
return;
end
i++;
end
% init modem
config = ofdm_init_mode(mode);
states = ofdm_init(config);
print_config(states);
ofdm_load_const;
if burst_mode
% burst mode: treat N as Npackets
Npackets = N;
else
% streaming mode: treat N as Nseconds
Npackets = round(N/states.Tpacket);
end
% some constants used for assembling modem frames
[code_param Nbitspercodecframe Ncodecframespermodemframe] = codec_to_frame_packing(states, mode);
% OK generate a modem frame using random payload bits
if strcmp(mode, "2020")
payload_bits = round(ofdm_rand(Ncodecframespermodemframe*Nbitspercodecframe)/32767);
else
payload_bits = round(ofdm_rand(code_param.data_bits_per_frame)/32767);
if crc_mode
unpacked_crc16 = crc16_unpacked(payload_bits(1:end-16));
payload_bits(end-15:end) = unpacked_crc16;
end
end
[packet_bits bits_per_packet] = fec_encode(states, code_param, mode, payload_bits);
% modulate to create symbols and interleave
tx_symbols = [];
for b=1:bps:bits_per_packet
if bps == 2 tx_symbols = [tx_symbols qpsk_mod(packet_bits(b:b+bps-1))]; end
if bps == 4 tx_symbols = [tx_symbols qam16_mod(states.qam16, packet_bits(b:b+bps-1))]; end
end
assert(gp_deinterleave(gp_interleave(tx_symbols)) == tx_symbols);
tx_symbols = gp_interleave(tx_symbols);
% generate txt (non FEC protected) symbols
txt_bits = zeros(1,Ntxtbits);
txt_symbols = [];
for b=1:bps:length(txt_bits)
if bps == 2 txt_symbols = [txt_symbols qpsk_mod(txt_bits(b:b+bps-1))]; end
if bps == 4 txt_symbols = [txt_symbols qam16_mod(states.qam16,txt_bits(b:b+bps-1))]; end
end
% assemble interleaved modem packet that include UW and txt symbols
modem_packet = assemble_modem_packet_symbols(states, tx_symbols, txt_symbols);
% sanity check
[rx_uw rx_codeword_syms payload_amps txt_bits] = disassemble_modem_packet(states, modem_packet, ones(1,length(modem_packet)));
assert(rx_uw == states.tx_uw);
% create a burst of concatenated packets
atx = ofdm_txframe(states, modem_packet); tx = [];
for f=1:Npackets
tx = [tx atx];
end
if length(states.data_mode)
% note for burst mode postamble provides a "column" of pilots at the end of the burst
tx = [states.tx_preamble tx states.tx_postamble];
end
% if burst mode concatenate multiple bursts with spaces
if burst_mode
atx = tx; tx = zeros(1,states.Fs); on_time = 0; off_time = states.Fs;
for b=1:Nbursts
tx = [tx atx zeros(1,states.Fs)];
on_time += length(atx);
off_time += states.Fs;
end
% adjust channel simulator SNR setpoint given (burst on length)/(total length including silence) ratio
mark_space_SNR_offset = 10*log10(on_time/(on_time+off_time));
SNRdB_setpoint = SNR3kdB + mark_space_SNR_offset;
printf("SNR3kdB: %4.2f Burst offset: %4.2f SNRdB_setpoint: %4.2f\n", SNR3kdB, mark_space_SNR_offset, SNRdB_setpoint)
else
SNRdB_setpoint = SNR3kdB; % no adjustment to SNR in streaming mode
end
printf("Npackets: %d Nbursts: %d ", Npackets, Nbursts);
states.verbose=1;
tx = ofdm_hilbert_clipper(states, tx, tx_clip_en);
[rx_real rx] = ofdm_channel(states, tx, SNRdB_setpoint, channel, freq_offset_Hz);
frx = fopen(filename,"wb"); fwrite(frx, rx_real, "short"); fclose(frx);
if length(rx) >= states.Fs
figure(1); clf; plot(20*log10(abs(fft(rx(1:states.Fs)/16384))));
axis([1 states.Fs -20 60])
end
endfunction
|