diff options
| author | Marin Ivanov <[email protected]> | 2025-07-25 10:17:14 +0300 |
|---|---|---|
| committer | Marin Ivanov <[email protected]> | 2026-01-18 20:09:26 +0200 |
| commit | 0168586485e6310c598713c911b1dec5618d61a1 (patch) | |
| tree | 6aabc2a12ef8fef70683f5389bea00f948015f77 /octave/ofdm_ldpc_tx.m | |
* codec2 cut-down version 1.2.0
* Remove codebook and generation of sources
* remove c2dec c2enc binaries
* prepare for emscripten
Diffstat (limited to 'octave/ofdm_ldpc_tx.m')
| -rw-r--r-- | octave/ofdm_ldpc_tx.m | 144 |
1 files changed, 144 insertions, 0 deletions
diff --git a/octave/ofdm_ldpc_tx.m b/octave/ofdm_ldpc_tx.m new file mode 100644 index 0000000..1cdcef5 --- /dev/null +++ b/octave/ofdm_ldpc_tx.m @@ -0,0 +1,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 |
