2
0

fdmdv_ut.m 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318
  1. % fdmdv_ut.m
  2. %
  3. % Unit Test program for FDMDV modem. Useful for general development as it has
  4. % both tx and rx sides, and basic AWGN channel simulation.
  5. %
  6. % Copyright David Rowe 2012
  7. % This program is distributed under the terms of the GNU General Public License
  8. % Version 2
  9. %
  10. fdmdv; % load modem code
  11. % Simulation Parameters --------------------------------------
  12. frames = 25;
  13. EbNo_dB = 7.3;
  14. Foff_hz = 0;
  15. modulation = 'dqpsk';
  16. hpa_clip = 150;
  17. % ------------------------------------------------------------
  18. tx_filt = zeros(Nc,M);
  19. rx_symbols_log = [];
  20. rx_phase_log = 0;
  21. rx_timing_log = 0;
  22. tx_pwr = 0;
  23. noise_pwr = 0;
  24. rx_fdm_log = [];
  25. rx_baseband_log = [];
  26. rx_bits_offset = zeros(Nc*Nb*2);
  27. prev_tx_symbols = ones(Nc+1,1);
  28. prev_rx_symbols = ones(Nc+1,1);
  29. ferr = 0;
  30. foff = 0;
  31. foff_log = [];
  32. tx_baseband_log = [];
  33. tx_fdm_log = [];
  34. % BER stats
  35. total_bit_errors = 0;
  36. total_bits = 0;
  37. bit_errors_log = [];
  38. sync_log = [];
  39. test_frame_sync_log = [];
  40. test_frame_sync_state = 0;
  41. % SNR estimation states
  42. sig_est = zeros(Nc+1,1);
  43. noise_est = zeros(Nc+1,1);
  44. % fixed delay simuation
  45. Ndelay = M+20;
  46. rx_fdm_delay = zeros(Ndelay,1);
  47. % ---------------------------------------------------------------------
  48. % Eb/No calculations. We need to work out Eb/No for each FDM carrier.
  49. % Total power is sum of power in all FDM carriers
  50. % ---------------------------------------------------------------------
  51. C = 1; % power of each FDM carrier (energy/sample). Total Carrier power should = Nc*C = Nc
  52. N = 1; % total noise power (energy/sample) of noise source across entire bandwidth
  53. % Eb = Carrier power * symbol time / (bits/symbol)
  54. % = C *(1/Rs) / 2
  55. Eb_dB = 10*log10(C) - 10*log10(Rs) - 10*log10(2);
  56. No_dBHz = Eb_dB - EbNo_dB;
  57. % Noise power = Noise spectral density * bandwidth
  58. % Noise power = Noise spectral density * Fs/2 for real signals
  59. N_dB = No_dBHz + 10*log10(Fs/2);
  60. Ngain_dB = N_dB - 10*log10(N);
  61. Ngain = 10^(Ngain_dB/20);
  62. % C/No = Carrier Power/noise spectral density
  63. % = power per carrier*number of carriers / noise spectral density
  64. CNo_dB = 10*log10(C) + 10*log10(Nc) - No_dBHz;
  65. % SNR in equivalent 3000 Hz SSB channel
  66. B = 3000;
  67. SNR = CNo_dB - 10*log10(B);
  68. % freq offset simulation states
  69. phase_offset = 1;
  70. freq_offset = exp(j*2*pi*Foff_hz/Fs);
  71. foff_phase = 1;
  72. t = 0;
  73. foff = 0;
  74. fest_state = 0;
  75. track = 0;
  76. track_log = [];
  77. % ---------------------------------------------------------------------
  78. % Main loop
  79. % ---------------------------------------------------------------------
  80. for f=1:frames
  81. % -------------------
  82. % Modulator
  83. % -------------------
  84. tx_bits = get_test_bits(Nc*Nb);
  85. tx_symbols = bits_to_qpsk(prev_tx_symbols, tx_bits, modulation);
  86. prev_tx_symbols = tx_symbols;
  87. tx_baseband = tx_filter(tx_symbols);
  88. tx_baseband_log = [tx_baseband_log tx_baseband];
  89. tx_fdm = fdm_upconvert(tx_baseband);
  90. tx_pwr = 0.9*tx_pwr + 0.1*real(tx_fdm)*real(tx_fdm)'/(M);
  91. % -------------------
  92. % Channel simulation
  93. % -------------------
  94. % frequency offset
  95. %Foff_hz += 1/Rs;
  96. Foff = Foff_hz;
  97. for i=1:M
  98. % Time varying freq offset
  99. %Foff = Foff_hz + 100*sin(t*2*pi/(300*Fs));
  100. %t++;
  101. freq_offset = exp(j*2*pi*Foff/Fs);
  102. phase_offset *= freq_offset;
  103. tx_fdm(i) = phase_offset*tx_fdm(i);
  104. end
  105. tx_fdm = real(tx_fdm);
  106. % HPA non-linearity
  107. tx_fdm(find(abs(tx_fdm) > hpa_clip)) = hpa_clip;
  108. tx_fdm_log = [tx_fdm_log tx_fdm];
  109. rx_fdm = tx_fdm;
  110. % AWGN noise
  111. noise = Ngain*randn(1,M);
  112. noise_pwr = 0.9*noise_pwr + 0.1*noise*noise'/M;
  113. rx_fdm += noise;
  114. rx_fdm_log = [rx_fdm_log rx_fdm];
  115. % Delay
  116. rx_fdm_delay(1:Ndelay-M) = rx_fdm_delay(M+1:Ndelay);
  117. rx_fdm_delay(Ndelay-M+1:Ndelay) = rx_fdm;
  118. %rx_fdm_delay = rx_fdm;
  119. % -------------------
  120. % Demodulator
  121. % -------------------
  122. % frequency offset estimation and correction, need to call rx_est_freq_offset even in track
  123. % mode to keep states updated
  124. [pilot prev_pilot pilot_lut_index prev_pilot_lut_index] = get_pilot(pilot_lut_index, prev_pilot_lut_index, M);
  125. [foff_course S1 S2] = rx_est_freq_offset(rx_fdm_delay, pilot, prev_pilot, M);
  126. if track == 0
  127. foff = foff_course;
  128. end
  129. foff_log = [ foff_log foff ];
  130. foff_rect = exp(j*2*pi*foff/Fs);
  131. for i=1:M
  132. foff_phase *= foff_rect';
  133. rx_fdm_delay(i) = rx_fdm_delay(i)*foff_phase;
  134. end
  135. % baseband processing
  136. rx_baseband = fdm_downconvert(rx_fdm_delay(1:M), M);
  137. rx_baseband_log = [rx_baseband_log rx_baseband];
  138. rx_filt = rx_filter(rx_baseband, M);
  139. [rx_symbols rx_timing] = rx_est_timing(rx_filt, rx_baseband, M);
  140. rx_timing_log = [rx_timing_log rx_timing];
  141. %rx_phase = rx_est_phase(rx_symbols);
  142. %rx_phase_log = [rx_phase_log rx_phase];
  143. %rx_symbols = rx_symbols*exp(j*rx_phase);
  144. [rx_bits sync foff_fine pd] = qpsk_to_bits(prev_rx_symbols, rx_symbols, modulation);
  145. if strcmp(modulation,'dqpsk')
  146. %rx_symbols_log = [rx_symbols_log rx_symbols.*conj(prev_rx_symbols)*exp(j*pi/4)];
  147. rx_symbols_log = [rx_symbols_log pd];
  148. else
  149. rx_symbols_log = [rx_symbols_log rx_symbols];
  150. endif
  151. foff -= 0.5*ferr;
  152. prev_rx_symbols = rx_symbols;
  153. sync_log = [sync_log sync];
  154. % freq est state machine
  155. [track fest_state] = freq_state(sync, fest_state);
  156. track_log = [track_log track];
  157. % Update SNR est
  158. [sig_est noise_est] = snr_update(sig_est, noise_est, pd);
  159. % count bit errors if we find a test frame
  160. % Allow 15 frames for filter memories to fill and time est to settle
  161. [test_frame_sync bit_errors] = put_test_bits(rx_bits);
  162. if test_frame_sync == 1
  163. total_bit_errors = total_bit_errors + bit_errors;
  164. total_bits = total_bits + Ntest_bits;
  165. bit_errors_log = [bit_errors_log bit_errors];
  166. else
  167. bit_errors_log = [bit_errors_log 0];
  168. end
  169. % test frame sync state machine, just for more informative plots
  170. next_test_frame_sync_state = test_frame_sync_state;
  171. if (test_frame_sync_state == 0)
  172. if (test_frame_sync == 1)
  173. next_test_frame_sync_state = 1;
  174. test_frame_count = 0;
  175. end
  176. end
  177. if (test_frame_sync_state == 1)
  178. % we only expect another test_frame_sync pulse every 4 symbols
  179. test_frame_count++;
  180. if (test_frame_count == 4)
  181. test_frame_count = 0;
  182. if ((test_frame_sync == 0))
  183. next_test_frame_sync_state = 0;
  184. end
  185. end
  186. end
  187. test_frame_sync_state = next_test_frame_sync_state;
  188. test_frame_sync_log = [test_frame_sync_log test_frame_sync_state];
  189. end
  190. % ---------------------------------------------------------------------
  191. % Print Stats
  192. % ---------------------------------------------------------------------
  193. ber = total_bit_errors / total_bits;
  194. % Peak to Average Power Ratio calcs from http://www.dsplog.com
  195. papr = max(tx_fdm_log.*conj(tx_fdm_log)) / mean(tx_fdm_log.*conj(tx_fdm_log));
  196. papr_dB = 10*log10(papr);
  197. % Note Eb/No set point is for Nc data carriers only, exclduing pilot.
  198. % This is convenient for testing BER versus Eb/No. Measured Eb/No
  199. % includes power of pilot. Similar for SNR, first number is SNR excluding
  200. % pilot pwr for Eb/No set point, 2nd value is measured SNR which will be a little
  201. % higher as pilot power is included.
  202. printf("Eb/No (meas): %2.2f (%2.2f) dB\n", EbNo_dB, 10*log10(0.25*tx_pwr*Fs/(Rs*Nc*noise_pwr)));
  203. printf("bits........: %d\n", total_bits);
  204. printf("errors......: %d\n", total_bit_errors);
  205. printf("BER.........: %1.4f\n", ber);
  206. printf("PAPR........: %1.2f dB\n", papr_dB);
  207. printf("SNR...(meas): %2.2f (%2.2f) dB\n", SNR, calc_snr(sig_est, noise_est));
  208. % ---------------------------------------------------------------------
  209. % Plots
  210. % ---------------------------------------------------------------------
  211. figure(1)
  212. clf;
  213. [n m] = size(rx_symbols_log);
  214. plot(real(rx_symbols_log(1:Nc+1,15:m)),imag(rx_symbols_log(1:Nc+1,15:m)),'+')
  215. axis([-3 3 -3 3]);
  216. title('Scatter Diagram');
  217. figure(2)
  218. clf;
  219. subplot(211)
  220. plot(rx_timing_log)
  221. title('timing offset (samples)');
  222. subplot(212)
  223. plot(foff_log, '-;freq offset;')
  224. hold on;
  225. plot(track_log*75, 'r;course-fine;');
  226. hold off;
  227. title('Freq offset (Hz)');
  228. figure(3)
  229. clf;
  230. subplot(211)
  231. plot(real(tx_fdm_log));
  232. title('FDM Tx Signal');
  233. subplot(212)
  234. Nfft=Fs;
  235. S=fft(rx_fdm_log,Nfft);
  236. SdB=20*log10(abs(S));
  237. plot(SdB(1:Fs/4))
  238. title('FDM Rx Spectrum');
  239. figure(4)
  240. clf;
  241. subplot(311)
  242. stem(sync_log)
  243. axis([0 frames 0 1.5]);
  244. title('BPSK Sync')
  245. subplot(312)
  246. stem(bit_errors_log);
  247. title('Bit Errors for test frames')
  248. subplot(313)
  249. plot(test_frame_sync_log);
  250. axis([0 frames 0 1.5]);
  251. title('Test Frame Sync')