File: ofdm_tx.m

package info (click to toggle)
codec2 0.9.2-4
  • links: PTS, VCS
  • area: main
  • in suites: bullseye
  • size: 113,072 kB
  • sloc: ansic: 412,877; python: 4,004; sh: 1,540; objc: 817; asm: 683; makefile: 588
file content (141 lines) | stat: -rw-r--r-- 4,256 bytes parent folder | download
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