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, Ncodecframespermodemframe, Nbitspercodecframe);
% 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
|