tfdmdv.m 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306
  1. % tfdmdv.m
  2. %
  3. % Octave script that tests the C port of the FDMDV modem. This script loads
  4. % the output of unittest/tfdmdv.c and compares it to the output of the
  5. % reference versions of the same functions written in Octave.
  6. %
  7. % Copyright David Rowe 2012
  8. % This program is distributed under the terms of the GNU General Public License
  9. % Version 2
  10. %
  11. fdmdv; % load modem code
  12. % Generate reference vectors using Octave implementation of FDMDV modem
  13. global passes;
  14. global fails;
  15. passes = fails = 0;
  16. frames = 25;
  17. prev_tx_symbols = ones(Nc+1,1);
  18. prev_rx_symbols = ones(Nc+1,1);
  19. foff_phase_rect = 1;
  20. coarse_fine = 0;
  21. fest_state = 0;
  22. channel = [];
  23. channel_count = 0;
  24. next_nin = M;
  25. sig_est = zeros(Nc+1,1);
  26. noise_est = zeros(Nc+1,1);
  27. % Octave outputs we want to collect for comparison to C version
  28. tx_bits_log = [];
  29. tx_symbols_log = [];
  30. tx_baseband_log = [];
  31. tx_fdm_log = [];
  32. pilot_baseband1_log = [];
  33. pilot_baseband2_log = [];
  34. pilot_lpf1_log = [];
  35. pilot_lpf2_log = [];
  36. S1_log = [];
  37. S2_log = [];
  38. foff_coarse_log = [];
  39. foff_fine_log = [];
  40. foff_log = [];
  41. rx_baseband_log = [];
  42. rx_filt_log = [];
  43. env_log = [];
  44. rx_timing_log = [];
  45. rx_symbols_log = [];
  46. rx_bits_log = [];
  47. sync_bit_log = [];
  48. coarse_fine_log = [];
  49. nin_log = [];
  50. sig_est_log = [];
  51. noise_est_log = [];
  52. for f=1:frames
  53. % modulator
  54. tx_bits = get_test_bits(Nc*Nb);
  55. tx_bits_log = [tx_bits_log tx_bits];
  56. tx_symbols = bits_to_qpsk(prev_tx_symbols, tx_bits, 'dqpsk');
  57. prev_tx_symbols = tx_symbols;
  58. tx_symbols_log = [tx_symbols_log tx_symbols];
  59. tx_baseband = tx_filter(tx_symbols);
  60. tx_baseband_log = [tx_baseband_log tx_baseband];
  61. tx_fdm = fdm_upconvert(tx_baseband);
  62. tx_fdm_log = [tx_fdm_log tx_fdm];
  63. % channel
  64. nin = next_nin;
  65. %nin = 120;
  66. %nin = M;
  67. %if (f == 3)
  68. % nin = 120;
  69. %elseif (f == 4)
  70. % nin = 200;
  71. %else
  72. % nin = M;
  73. %end
  74. channel = [channel real(tx_fdm)];
  75. channel_count += M;
  76. rx_fdm = channel(1:nin);
  77. channel = channel(nin+1:channel_count);
  78. channel_count -= nin;
  79. % demodulator
  80. [pilot prev_pilot pilot_lut_index prev_pilot_lut_index] = get_pilot(pilot_lut_index, prev_pilot_lut_index, nin);
  81. [foff_coarse S1 S2] = rx_est_freq_offset(rx_fdm, pilot, prev_pilot, nin);
  82. if coarse_fine == 0
  83. foff = foff_coarse;
  84. end
  85. foff_coarse_log = [foff_coarse_log foff_coarse];
  86. pilot_baseband1_log = [pilot_baseband1_log pilot_baseband1];
  87. pilot_baseband2_log = [pilot_baseband2_log pilot_baseband2];
  88. pilot_lpf1_log = [pilot_lpf1_log pilot_lpf1];
  89. pilot_lpf2_log = [pilot_lpf2_log pilot_lpf2];
  90. S1_log = [S1_log S1];
  91. S2_log = [S2_log S2];
  92. foff_rect = exp(j*2*pi*foff/Fs);
  93. for i=1:nin
  94. foff_phase_rect *= foff_rect';
  95. rx_fdm_fcorr(i) = rx_fdm(i)*foff_phase_rect;
  96. end
  97. rx_baseband = fdm_downconvert(rx_fdm_fcorr, nin);
  98. rx_baseband_log = [rx_baseband_log rx_baseband];
  99. rx_filt = rx_filter(rx_baseband, nin);
  100. rx_filt_log = [rx_filt_log rx_filt];
  101. [rx_symbols rx_timing env] = rx_est_timing(rx_filt, rx_baseband, nin);
  102. env_log = [env_log env];
  103. rx_timing_log = [rx_timing_log rx_timing];
  104. rx_symbols_log = [rx_symbols_log rx_symbols];
  105. next_nin = M;
  106. if rx_timing > 2*M/P
  107. next_nin += M/P;
  108. end
  109. if rx_timing < 0;
  110. next_nin -= M/P;
  111. end
  112. nin_log = [nin_log nin];
  113. [rx_bits sync_bit foff_fine pd] = qpsk_to_bits(prev_rx_symbols, rx_symbols, 'dqpsk');
  114. [sig_est noise_est] = snr_update(sig_est, noise_est, pd);
  115. sig_est_log = [sig_est_log sig_est];
  116. noise_est_log = [noise_est_log noise_est];
  117. prev_rx_symbols = rx_symbols;
  118. rx_bits_log = [rx_bits_log rx_bits];
  119. foff_fine_log = [foff_fine_log foff_fine];
  120. sync_bit_log = [sync_bit_log sync_bit];
  121. foff -= 0.5*foff_fine;
  122. foff_log = [foff_log foff];
  123. % freq est state machine
  124. [coarse_fine fest_state] = freq_state(sync_bit, fest_state);
  125. coarse_fine_log = [coarse_fine_log coarse_fine];
  126. end
  127. % Compare to the output from the C version
  128. load ../unittest/tfdmdv_out.txt
  129. % Helper functions to plot output of C verson and difference between Octave and C versions
  130. function stem_sig_and_error(plotnum, subplotnum, sig, error, titlestr, axisvec)
  131. figure(plotnum)
  132. subplot(subplotnum)
  133. stem(sig);
  134. hold on;
  135. stem(error,'g');
  136. hold off;
  137. if nargin == 6
  138. axis(axisvec);
  139. end
  140. title(titlestr);
  141. endfunction
  142. function plot_sig_and_error(plotnum, subplotnum, sig, error, titlestr, axisvec)
  143. figure(plotnum)
  144. subplot(subplotnum)
  145. plot(sig);
  146. hold on;
  147. plot(error,'g');
  148. hold off;
  149. if nargin == 6
  150. axis(axisvec);
  151. end
  152. title(titlestr);
  153. endfunction
  154. % ---------------------------------------------------------------------------------------
  155. % Plot output and test each C function
  156. % ---------------------------------------------------------------------------------------
  157. % fdmdv_get_test_bits() & bits_to_dqpsk_symbols()
  158. n = 28;
  159. stem_sig_and_error(1, 211, tx_bits_log_c(1:n), tx_bits_log(1:n) - tx_bits_log_c(1:n), 'tx bits', [1 n -1.5 1.5])
  160. stem_sig_and_error(1, 212, real(tx_symbols_log_c(1:n/2)), real(tx_symbols_log(1:n/2) - tx_symbols_log_c(1:n/2)), 'tx symbols real', [1 n/2 -1.5 1.5])
  161. % tx_filter()
  162. diff = tx_baseband_log - tx_baseband_log_c;
  163. c=15;
  164. plot_sig_and_error(2, 211, real(tx_baseband_log_c(c,:)), real(sum(diff)), 'tx baseband real')
  165. plot_sig_and_error(2, 212, imag(tx_baseband_log_c(c,:)), imag(sum(diff)), 'tx baseband imag')
  166. % fdm_upconvert()
  167. plot_sig_and_error(3, 211, real(tx_fdm_log_c), real(tx_fdm_log - tx_fdm_log_c), 'tx fdm real')
  168. plot_sig_and_error(3, 212, imag(tx_fdm_log_c), imag(tx_fdm_log - tx_fdm_log_c), 'tx fdm imag')
  169. % generate_pilot_lut()
  170. plot_sig_and_error(4, 211, real(pilot_lut_c), real(pilot_lut - pilot_lut_c), 'pilot lut real')
  171. plot_sig_and_error(4, 212, imag(pilot_lut_c), imag(pilot_lut - pilot_lut_c), 'pilot lut imag')
  172. % rx_est_freq_offset()
  173. st=1; en = 3*Npilotbaseband;
  174. plot_sig_and_error(5, 211, real(pilot_baseband1_log(st:en)), real(pilot_baseband1_log(st:en) - pilot_baseband1_log_c(st:en)), 'pilot baseband1 real' )
  175. plot_sig_and_error(5, 212, real(pilot_baseband2_log(st:en)), real(pilot_baseband2_log(st:en) - pilot_baseband2_log_c(st:en)), 'pilot baseband2 real' )
  176. st=1; en = 3*Npilotlpf;
  177. plot_sig_and_error(6, 211, real(pilot_lpf1_log(st:en)), real(pilot_lpf1_log(st:en) - pilot_lpf1_log_c(st:en)), 'pilot lpf1 real' )
  178. plot_sig_and_error(6, 212, real(pilot_lpf2_log(st:en)), real(pilot_lpf2_log(st:en) - pilot_lpf2_log_c(st:en)), 'pilot lpf2 real' )
  179. plot_sig_and_error(7, 211, real(S1_log), real(S1_log - S1_log_c), 'S1 real' )
  180. plot_sig_and_error(7, 212, imag(S1_log), imag(S1_log - S1_log_c), 'S1 imag' )
  181. plot_sig_and_error(8, 211, real(S2_log), real(S2_log - S2_log_c), 'S2 real' )
  182. plot_sig_and_error(8, 212, imag(S2_log), imag(S2_log - S2_log_c), 'S2 imag' )
  183. plot_sig_and_error(9, 211, foff_coarse_log, foff_coarse_log - foff_coarse_log_c, 'Coarse Freq Offset' )
  184. plot_sig_and_error(9, 212, foff_fine_log, foff_fine_log - foff_fine_log_c, 'Fine Freq Offset' )
  185. plot_sig_and_error(10, 211, foff_log, foff_log - foff_log_c, 'Freq Offset' )
  186. plot_sig_and_error(10, 212, coarse_fine_log, coarse_fine_log - coarse_fine_log_c, 'Freq Est Coarse(0) Fine(1)', [1 frames -0.5 1.5] )
  187. c=15;
  188. plot_sig_and_error(11, 211, real(rx_baseband_log(c,:)), real(rx_baseband_log(c,:) - rx_baseband_log_c(c,:)), 'Rx baseband real' )
  189. plot_sig_and_error(11, 212, imag(rx_baseband_log(c,:)), imag(rx_baseband_log(c,:) - rx_baseband_log_c(c,:)), 'Rx baseband imag' )
  190. plot_sig_and_error(12, 211, real(rx_filt_log(c,:)), real(rx_filt_log(c,:) - rx_filt_log_c(c,:)), 'Rx filt real' )
  191. plot_sig_and_error(12, 212, imag(rx_filt_log(c,:)), imag(rx_filt_log(c,:) - rx_filt_log_c(c,:)), 'Rx filt imag' )
  192. st=1; en=3*Nt*P;
  193. plot_sig_and_error(13, 211, env_log(st:en), env_log(st:en) - env_log_c(st:en), 'env' )
  194. stem_sig_and_error(13, 212, real(rx_symbols_log(c,:)), real(rx_symbols_log(c,:) - rx_symbols_log_c(c,:)), 'rx symbols' )
  195. st=10*28;
  196. en = 12*28;
  197. plot_sig_and_error(14, 211, rx_timing_log, rx_timing_log - rx_timing_log_c, 'Rx Timing' )
  198. stem_sig_and_error(14, 212, sync_bit_log_c, sync_bit_log - sync_bit_log_c, 'Sync bit', [1 n -1.5 1.5])
  199. stem_sig_and_error(15, 211, rx_bits_log_c(st:en), rx_bits_log(st:en) - rx_bits_log_c(st:en), 'RX bits', [1 en-st -1.5 1.5])
  200. stem_sig_and_error(15, 212, nin_log_c, nin_log - nin_log_c, 'nin')
  201. c = 1;
  202. plot_sig_and_error(16, 211, sig_est_log(c,:), sig_est_log(c,:) - sig_est_log_c(c,:), 'sig est for SNR' )
  203. plot_sig_and_error(16, 212, noise_est_log(c,:), noise_est_log(c,:) - noise_est_log_c(c,:), 'noise est for SNR' )
  204. % ---------------------------------------------------------------------------------------
  205. % AUTOMATED CHECKS ------------------------------------------
  206. % ---------------------------------------------------------------------------------------
  207. function check(a, b, test_name)
  208. global passes;
  209. global fails;
  210. [m n] = size(a);
  211. printf("%s", test_name);
  212. for i=1:(25-length(test_name))
  213. printf(".");
  214. end
  215. printf(": ");
  216. if sum(abs(a - b))/n < 1E-3
  217. printf("OK\n");
  218. passes++;
  219. else
  220. printf("FAIL\n");
  221. fails++;
  222. end
  223. endfunction
  224. check(tx_bits_log, tx_bits_log_c, 'tx_bits');
  225. check(tx_symbols_log, tx_symbols_log_c, 'tx_symbols');
  226. check(tx_baseband_log, tx_baseband_log_c, 'tx_baseband');
  227. check(tx_fdm_log, tx_fdm_log_c, 'tx_fdm');
  228. check(pilot_lut, pilot_lut_c, 'pilot_lut');
  229. check(pilot_baseband1_log, pilot_baseband1_log_c, 'pilot lpf1');
  230. check(pilot_baseband2_log, pilot_baseband2_log_c, 'pilot lpf2');
  231. check(S1_log, S1_log_c, 'S1');
  232. check(S2_log, S2_log_c, 'S2');
  233. check(foff_coarse_log, foff_coarse_log_c, 'foff_coarse');
  234. check(foff_fine_log, foff_fine_log_c, 'foff_fine');
  235. check(foff_log, foff_log_c, 'foff');
  236. check(rx_baseband_log, rx_baseband_log_c, 'rx baseband');
  237. check(rx_filt_log, rx_filt_log_c, 'rx filt');
  238. check(env_log, env_log_c, 'env');
  239. check(rx_timing_log, rx_timing_log_c, 'rx_timing');
  240. check(rx_symbols_log, rx_symbols_log_c, 'rx_symbols');
  241. check(rx_bits_log, rx_bits_log_c, 'rx bits');
  242. check(sync_bit_log, sync_bit_log_c, 'sync bit');
  243. check(coarse_fine_log, coarse_fine_log_c, 'coarse_fine');
  244. check(nin_log, nin_log_c, 'nin');
  245. check(sig_est_log, sig_est_log_c, 'sig_est');
  246. check(noise_est_log, noise_est_log_c, 'noise_est');
  247. printf("\npasses: %d fails: %d\n", passes, fails);