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
|
% ofdm_tx.m
% David Rowe March 2018
%
% File based, uncoded OFDM tx. Generates a file of ofdm samples,
% including optional channel simulation. See also ofdm_ldpc_tx.m, and
% ofdm_mod.c
#{
Examples:
i) 10 seconds, AWGN channel at Eb/No=3dB
octave:4> ofdm_tx('awgn_ebno_3dB_700d.raw', "700D", 10, 3);
ii) 10 seconds, HF channel at Eb/No=6dB
ofdm_tx('hf_ebno_6dB_700d.raw', "700D", 10, 6, 'hf');
iii) 10 seconds, 2200 waveform, AWGN channel, Eb/No=100dB (effectively noise free)
ofdm_tx('hf_ebno_6dB_700d.raw', "2200", 10);
#}
% Note EbNodB is for payload data bits, so will be 10log10(rate) higher than
% raw EbNodB used in ofdm_tx() at uncoded bit rate
function ofdm_tx(filename, mode="700D", Nsec, EbNodB=100, channel='awgn', freq_offset_Hz=0, dfoff_hz_per_sec = 0, initial_noise_sams=0, tx_filter=0)
ofdm_lib;
% init modem
[bps Rs Tcp Ns Nc] = ofdm_init_mode(mode)
states = ofdm_init(bps, Rs, Tcp, Ns, Nc);
print_config(states);
ofdm_load_const;
% Generate fixed test frame of tx bits and run OFDM modulator
Nrows = Nsec*Rs;
Nframes = floor((Nrows-1)/Ns);
tx_bits = create_ldpc_test_frame(states, coded_frame=0);
tx = [];
for f=1:Nframes
tx = [tx ofdm_mod(states, tx_bits)];
end
Nsam = length(tx);
% channel simulation
EsNo = rate * bps * (10 .^ (EbNodB/10));
variance = 1/(M*EsNo/2);
woffset = 2*pi*freq_offset_Hz/Fs;
dwoffset = 2*pi*dfoff_hz_per_sec/(Fs*Fs);
SNRdB = EbNodB + 10*log10(Nc*bps*Rs/3000);
printf("EbNo: %3.1f dB SNR(3k) est: %3.1f dB foff: %3.1fHz ", EbNodB, SNRdB, freq_offset_Hz);
% set up HF model ---------------------------------------------------------------
if strcmp(channel, 'hf')
randn('seed',1);
% some typical values, or replace with user supplied
dopplerSpreadHz = 1; path_delay_ms = 1;
path_delay_samples = path_delay_ms*Fs/1000;
printf("Doppler Spread: %3.2f Hz Path Delay: %3.2f ms %d samples\n",
dopplerSpreadHz, path_delay_ms, path_delay_samples);
% generate same fading pattern for every run
randn('seed',1);
spread1 = doppler_spread(dopplerSpreadHz, Fs, (Nsec*(M+Ncp)/M)*Fs*1.1);
spread2 = doppler_spread(dopplerSpreadHz, Fs, (Nsec*(M+Ncp)/M)*Fs*1.1);
% sometimes doppler_spread() doesn't return exactly the number of samples we need
assert(length(spread1) >= Nsam, "not enough doppler spreading samples");
assert(length(spread2) >= Nsam, "not enough doppler spreading samples");
end
% experimental coarse amplitude quantisation
quant_tx = 0;
if quant_tx
tx_re = real(tx); tx_im = imag(tx);
tx_re = min(tx_re,0.5); tx_re = max(tx_re,-0.5);
tx_im = min(tx_im,0.5); tx_im = max(tx_im,-0.5);
step = 0.05/4;
tx_re = step*round(tx_re/step);
tx_im = step*round(tx_im/step);
tx = tx_re + j*tx_im;
figure(1); clf; subplot(211); plot(real(tx(1:100)),'+-'); subplot(212); plot(imag(tx(1:100)),'+-');
end
rx = tx;
if tx_filter
bpf_coeff = make_ofdm_bpf(write_c_header_file=0);
rx = filter(bpf_coeff,1,tx);
figure(1); clf;
subplot(211);
plot((1:length(tx))*8000/length(tx), 20*log10(abs(fft(tx))))
axis([1 4000 0 60])
subplot(212);
plot((1:length(tx))*8000/length(tx), 20*log10(abs(fft(rx))))
axis([1 4000 0 60])
end
if strcmp(channel, 'hf')
rx = tx(1:Nsam) .* spread1(1:Nsam);
rx += [zeros(1,path_delay_samples) tx(1:Nsam-path_delay_samples)] .* spread2(1:Nsam);
% normalise rx power to same as tx
nom_rx_pwr = 2/(Ns*(M*M)) + Nc/(M*M);
rx_pwr = var(rx);
rx *= sqrt(nom_rx_pwr/rx_pwr);
end
phase_offset = woffset*(1:Nsam) + 0.5*dwoffset*((1:Nsam).^2);
rx = rx .* exp(j*phase_offset);
rx = [zeros(1,initial_noise_sams) rx];
Nsam = length(rx);
% note variance/2 as we are using real() operator, mumble,
% reflection of -ve freq to +ve, mumble, hand wave
randn('seed',1);
noise = sqrt(variance/2)*0.5*randn(1,Nsam);
rx = real(rx) + noise;
printf("measured SNR: %3.2f dB\n", 10*log10(var(real(tx))/var(noise))+10*log10(4000) - 10*log10(3000));
% adjusted by experiment to match rms power of early test signals
frx=fopen(filename,"wb"); fwrite(frx, states.amp_scale*rx, "short"); fclose(frx);
endfunction
|