--- cml-orig/CmlStartup.m 2007-09-08 23:12:26.000000000 +0930
+++ cml/CmlStartup.m 2015-09-04 07:21:14.218455223 +0930
@@ -41,7 +41,7 @@
- addpath( strcat( cml_home, '/mex'), ...\r
- strcat( cml_home, '/mat'), ...\r
- strcat( cml_home, '/matalt' ), ...\r
-- strcat( cml_home, '/mexhelp'), ...\r
-+ %strcat( cml_home, '/mexhelp'), ...\r
- strcat( cml_home, '/demos' ), ...\r
- strcat( cml_home, '/scenarios'), ...\r
- strcat( cml_home, '/localscenarios'),...\r
+ addpath( strcat( cml_home, '/mex'), ...
+ strcat( cml_home, '/mat'), ...
+ strcat( cml_home, '/matalt' ), ...
+- strcat( cml_home, '/mexhelp'), ...
++ %strcat( cml_home, '/mexhelp'), ...
+ strcat( cml_home, '/demos' ), ...
+ strcat( cml_home, '/scenarios'), ...
+ strcat( cml_home, '/localscenarios'),...
@@ -59,4 +59,4 @@
- save_directory = strcat( cml_home, '/scenarios/CmlHome.mat' );\r
- end\r
- \r
+ save_directory = strcat( cml_home, '/scenarios/CmlHome.mat' );
+ end
+
-save( save_directory, save_flag, 'cml_home' );
\ No newline at end of file
-+save( save_directory, save_flag, 'cml_home' );\r
++save( save_directory, save_flag, 'cml_home' );
diff -ruN -x '*.o' -x '*.dll' -x '*.mex' -x '*.mat' cml-orig/source/matrix.h cml/source/matrix.h
--- cml-orig/source/matrix.h 1970-01-01 09:30:00.000000000 +0930
+++ cml/source/matrix.h 2015-09-04 07:06:46.907248420 +0930
-% ldpc.m\r
-%\r
-% David Rowe 2013\r
-% Octave functions to help us use the CML LDPC code.\r
-%\r
-% Installing CML library\r
-% ----------------------\r
-%\r
-% $ sudo apt-get install liboctave-dev\r
-% $ wget http://www.iterativesolutions.com/user/image/cml.1.10.zip\r
-% $ unzip cml.1.10.zip\r
-% $ patch < ~/codec2-dev/octave/cml.patch\r
-% $ cd source\r
-% $ octave\r
-% octave:> make\r
-\r
-1;\r
-\r
-\r
-function code_param = ldpc_init(rate, framesize, modulation, mod_order, mapping)\r
- [code_param.H_rows, code_param.H_cols, code_param.P_matrix] = InitializeWiMaxLDPC( rate, framesize, 0 );\r
- code_param.data_bits_per_frame = length(code_param.H_cols) - length( code_param.P_matrix );\r
- code_param.S_matrix = CreateConstellation( modulation, mod_order, mapping );\r
- code_param.bits_per_symbol = log2(mod_order);\r
- code_param.code_bits_per_frame = framesize;\r
- code_param.symbols_per_frame = framesize/2;\r
-endfunction\r
-\r
-\r
-\r
-function [codeword s] = ldpc_enc(data, code_param)\r
- codeword = LdpcEncode( data, code_param.H_rows, code_param.P_matrix );\r
- s = Modulate( codeword, code_param.S_matrix );\r
-endfunction\r
-\r
-\r
-function detected_data = ldpc_dec(code_param, max_iterations, demod_type, decoder_type, r, EsNo, fading)\r
- if nargin == 6\r
- fading = ones(1, length(r));\r
- end\r
-\r
- symbol_likelihood = Demod2D( r, code_param.S_matrix, EsNo, fading);\r
- \r
- % initialize the extrinsic decoder input\r
-\r
- input_somap_c = zeros(1, code_param.code_bits_per_frame );\r
- bit_likelihood = Somap( symbol_likelihood, demod_type, input_somap_c );\r
- \r
- input_decoder_c = bit_likelihood(1:code_param.code_bits_per_frame);\r
- \r
- x_hat= MpDecode( -input_decoder_c, code_param.H_rows, code_param.H_cols, ...\r
- max_iterations, decoder_type, 1, 1);\r
- detected_data = x_hat(max_iterations,:);\r
-endfunction\r
-\r
-\r
-% Packs a binary array into an array of 8 bit bytes, MSB first\r
-\r
-function packed = packmsb(unpacked)\r
- packed = zeros(1,floor(length(unpacked)+7)/8);\r
- bit = 7; byte = 1;\r
- for i=1:length(unpacked)\r
- packed(byte) = bitor(packed(byte), bitshift(unpacked(i),bit));\r
- bit--;\r
- if (bit < 0)\r
- bit = 7;\r
- byte++;\r
- end \r
- end\r
-endfunction\r
-\r
-\r
-% unpacks an array of 8 bit bytes into a binary array of unpacked bits, MSB first\r
-\r
-function unpacked = unpackmsb(packed)\r
- bit = 7; byte = 1;\r
- for i=1:length(packed)*8\r
- unpacked(i) = bitand(bitshift(packed(byte), -bit), 1);\r
- bit--;\r
- if (bit < 0)\r
- bit = 7;\r
- byte++;\r
- end \r
- end\r
-endfunction\r
-\r
-\r
-% symbol interleaver that acts on bits 2 at a time\r
-\r
-function y = interleave_bits(interleaver, x)\r
- y = zeros(1,length(x));\r
- for i = 1:length(interleaver)\r
- dst = interleaver(i);\r
- y(2*(dst-1)+1:2*dst) = x(2*(i-1)+1:2*(i));\r
- end\r
-endfunction\r
-\r
-% symbol de-interleaver\r
-\r
-function x = deinterleave_symbols(interleaver, y)\r
- for i = 1:length(interleaver)\r
- x(i) = y(interleaver(i));\r
- end\r
-endfunction\r
+% ldpc.m
+%
+% David Rowe 2013
+% Octave functions to help us use the CML LDPC code.
+%
+% Installing CML library
+% ----------------------
+%
+% $ sudo apt-get install liboctave-dev
+% $ wget http://www.iterativesolutions.com/user/image/cml.1.10.zip
+% $ unzip cml.1.10.zip
+% $ patch < ~/codec2-dev/octave/cml.patch
+% $ cd source
+% $ octave
+% octave:> make
+
+1;
+
+
+function code_param = ldpc_init(rate, framesize, modulation, mod_order, mapping)
+ [code_param.H_rows, code_param.H_cols, code_param.P_matrix] = InitializeWiMaxLDPC( rate, framesize, 0 );
+ code_param.data_bits_per_frame = length(code_param.H_cols) - length( code_param.P_matrix );
+ code_param.S_matrix = CreateConstellation( modulation, mod_order, mapping );
+ code_param.bits_per_symbol = log2(mod_order);
+ code_param.code_bits_per_frame = framesize;
+ code_param.symbols_per_frame = framesize/2;
+endfunction
+
+
+
+function [codeword s] = ldpc_enc(data, code_param)
+ codeword = LdpcEncode( data, code_param.H_rows, code_param.P_matrix );
+ s = Modulate( codeword, code_param.S_matrix );
+endfunction
+
+
+function detected_data = ldpc_dec(code_param, max_iterations, demod_type, decoder_type, r, EsNo, fading)
+ if nargin == 6
+ fading = ones(1, length(r));
+ end
+
+ symbol_likelihood = Demod2D( r, code_param.S_matrix, EsNo, fading);
+
+ % initialize the extrinsic decoder input
+
+ input_somap_c = zeros(1, code_param.code_bits_per_frame );
+ bit_likelihood = Somap( symbol_likelihood, demod_type, input_somap_c );
+
+ input_decoder_c = bit_likelihood(1:code_param.code_bits_per_frame);
+
+ x_hat= MpDecode( -input_decoder_c, code_param.H_rows, code_param.H_cols, ...
+ max_iterations, decoder_type, 1, 1);
+ detected_data = x_hat(max_iterations,:);
+endfunction
+
+
+% Packs a binary array into an array of 8 bit bytes, MSB first
+
+function packed = packmsb(unpacked)
+ packed = zeros(1,floor(length(unpacked)+7)/8);
+ bit = 7; byte = 1;
+ for i=1:length(unpacked)
+ packed(byte) = bitor(packed(byte), bitshift(unpacked(i),bit));
+ bit--;
+ if (bit < 0)
+ bit = 7;
+ byte++;
+ end
+ end
+endfunction
+
+
+% unpacks an array of 8 bit bytes into a binary array of unpacked bits, MSB first
+
+function unpacked = unpackmsb(packed)
+ bit = 7; byte = 1;
+ for i=1:length(packed)*8
+ unpacked(i) = bitand(bitshift(packed(byte), -bit), 1);
+ bit--;
+ if (bit < 0)
+ bit = 7;
+ byte++;
+ end
+ end
+endfunction
+
+
+% symbol interleaver that acts on bits 2 at a time
+
+function y = interleave_bits(interleaver, x)
+ y = zeros(1,length(x));
+ for i = 1:length(interleaver)
+ dst = interleaver(i);
+ y(2*(dst-1)+1:2*dst) = x(2*(i-1)+1:2*(i));
+ end
+endfunction
+
+% symbol de-interleaver
+
+function x = deinterleave_symbols(interleaver, y)
+ for i = 1:length(interleaver)
+ x(i) = y(interleaver(i));
+ end
+endfunction
-% ldpcdec.m\r
-% David Rowe 31 Dec 2013\r
-% \r
-% LDPC decoder test program, given a file of QPSK symbols (IQIQ floats), \r
-% performs frame sync, decodes, and measures BER.\r
-\r
-function ldpcdec(filename, Eprob)\r
-\r
- % Start CML library\r
-\r
- currentdir = pwd;\r
- addpath '/home/david/tmp/cml/mat' % assume the source files stored here\r
- cd /home/david/tmp/cml\r
- CmlStartup % note that this is not in the cml path!\r
- cd(currentdir)\r
-\r
- % Our LDPC library\r
-\r
- ldpc;\r
-\r
- % Start simulation\r
-\r
- rand('state',1);\r
-\r
- rate = 3/4; \r
- framesize = 576; \r
-\r
- mod_order = 4; \r
- modulation = 'QPSK';\r
- mapping = 'gray';\r
-\r
- demod_type = 0;\r
- decoder_type = 0;\r
- max_iterations = 100;\r
- EsNo = 4;\r
- if (nargin == 1)\r
- Eprob = 0.0;\r
- end\r
-\r
- nbitspervocoderframe = 52;\r
- nvocoderframes = 8;\r
- nbitspermodemframe = 72;\r
-\r
- code_param = ldpc_init(rate, framesize, modulation, mod_order, mapping);\r
- code_param.code_bits_per_frame = 576;\r
-\r
- data = [];\r
- r = []; \r
- load interleaver.txt\r
- interleaver = interleaver + 1;\r
-\r
- Nframes = 100;\r
- uw = [1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0];\r
-\r
- Nc = 18;\r
-\r
- % repeat same simulated vocoder data to ease testing\r
-\r
- vd = round( rand( 1, nbitspervocoderframe*nvocoderframes) );\r
-\r
- % Decoder: Sync with LDPC frames, de-interleave, LDPC decode, strip off UW, measure BER -------\r
-\r
- mcwfilename = strcat(filename,"_modcodeword.bin");\r
- fm=fopen(mcwfilename,"rb");\r
- etfilename = strcat(filename,"_modcodeword_et.bin");\r
- fet=fopen(etfilename ,"rb");\r
- epfilename = strcat(filename,".err");\r
- fep=fopen(epfilename ,"wb");\r
- printf("Input QPSK symbols: %s\n", mcwfilename);\r
- if (fet == -1)\r
- printf("Input entered track file: none\n");\r
- else\r
- printf("Input entered track file: %s\n", etfilename);\r
- end\r
- printf("Output error pattern file: %s\n", epfilename);\r
-\r
- mod_uw = build_mod_uw(uw, 2*length(vd)/length(uw));\r
-\r
- mod_codeword = zeros(1, code_param.code_bits_per_frame/2);\r
- lmod_codeword = code_param.code_bits_per_frame/2;\r
-\r
- Terrs = 0; Trawerrs = 0; Ferrs = 0; Tbits = 0; Tframes = 0; nerr = []; nrawerr = [];\r
- corr = []; n = 0;\r
- sync_state = 0; sync_count = 0;\r
- mod_unpackedmodem_log = [];\r
- sync_state_log = [];\r
- entered_track_log = [];\r
- sig_pwr_log = [];\r
-\r
- symbols = erasures = 0;\r
-\r
- [mod_unpackedmodem_float32, count] = fread(fm,nbitspermodemframe, "float32");\r
- if (fet == -1)\r
- entered_track = 0;\r
- else\r
- entered_track = fread(fet, 1, "int");\r
- end\r
-\r
- while (count == nbitspermodemframe)\r
- n++;\r
-\r
- mod_unpackedmodem = mod_unpackedmodem_float32(1:2:nbitspermodemframe) + j*mod_unpackedmodem_float32(2:2:nbitspermodemframe);\r
- mod_unpackedmodem_log = [mod_unpackedmodem_log mod_unpackedmodem];\r
- %erasures = rand(1,length(mod_unpackedmodem)) < Eprob; \r
- %mod_unpackedmodem(erasures) = 0;\r
-\r
- % keep buffer of one entire codeword\r
-\r
- mod_codeword(1:lmod_codeword-length(mod_unpackedmodem)) = mod_codeword(length(mod_unpackedmodem)+1:lmod_codeword);\r
- mod_codeword(lmod_codeword-length(mod_unpackedmodem)+1:lmod_codeword) = mod_unpackedmodem;\r
-\r
- [uw_sync corr(n)] = look_for_uw(mod_codeword(1:length(mod_uw)), mod_uw);\r
-\r
- next_sync_state = sync_state;\r
- if ((sync_state == 0) && (uw_sync == 1))\r
- next_sync_state = 1;\r
- sync_count = 0;\r
- end\r
- if ((sync_state == 1) && (entered_track != 0))\r
- next_sync_state = 0;\r
- end\r
- sync_state = next_sync_state;\r
- sync_state_log = [sync_state_log sync_state];\r
- entered_track_log = [entered_track_log entered_track];\r
-\r
- if (sync_state && (sync_count == 0))\r
- Tframes++;\r
-\r
- % remove UW symbols\r
-\r
- mod_codeword_no_uw = remove_uw_symbols(mod_codeword, code_param.data_bits_per_frame/2 - length(uw)/2, length(uw)/2);\r
- mod_codeword_no_uw = [mod_codeword_no_uw mod_codeword((code_param.data_bits_per_frame/2+1):code_param.code_bits_per_frame/2)];\r
-\r
- % de-interleave\r
-\r
- tmp = deinterleave_symbols(interleaver, mod_codeword_no_uw);\r
- \r
- % insert known symbols at end of data\r
-\r
- mod_codeword_deinter = [ tmp(1:(code_param.data_bits_per_frame/2 - length(uw)/2)) ...\r
- ones(1,length(uw)/2) * qpsk_mod([0 0]) ...\r
- tmp((code_param.data_bits_per_frame/2 - length(uw)/2+1):length(tmp)) ];\r
- \r
- % determine BER stats of raw data before decoding\r
-\r
- raw_bits = zeros(1, code_param.data_bits_per_frame - length(uw));\r
- for i=1:(code_param.data_bits_per_frame - length(uw))/2\r
- raw_bits(2*(i-1)+1:2*i) = qpsk_demod(mod_codeword_deinter(i));\r
- end\r
- error_positions = xor(vd, raw_bits);\r
- Nerrs = sum(error_positions);\r
- Trawerrs += Nerrs;\r
- nrawerr(Tframes) = Nerrs;\r
-\r
- % Determine Es/N for each carrier. For this codeword we assume\r
- % across codeword (currently 320ms) signal is stationary.\r
- % So for each carrier signal level is constant, so we can\r
- % average across all symols of that carrier to get a better\r
- % estimate of the carrier power. The spectral noise density\r
- % No will be the same for the bandwidth of each carrier. So\r
- % we can use noise samples from all symbols together to get\r
- % a better estimate of the noise power.\r
- \r
- sig_pwr(Tframes,:) = zeros(1,Nc);\r
- noise_samples = [];\r
- for n=1:Nc\r
-\r
- % extract a vector of one carrier's symbols for this codeword\r
- % rotate so that decision boundaries are now real and imag axis\r
-\r
- r = mod_codeword(n:Nc:length(mod_codeword)) .* exp(j*pi/4);\r
-\r
- sig_est = mean(abs(r));\r
-\r
- % The noise is the variance of symbols (samples) about the actual symbol position\r
- % we reflect all symbols into the first quadrant to simplify things, as the actual\r
- % received symbol isn't matter, just the noise around it. We model the received\r
- % symbol based on the estimated signal level.\r
-\r
- refl_symbols = abs(real(r)) + j*abs(imag(r)); \r
- est_symbols = exp(j*pi/4)*sig_est*ones(1,length(r));\r
- noise_samples = [ noise_samples (est_symbols - refl_symbols)];\r
- \r
- sig_pwr(Tframes,n) = sig_est .^ 2;\r
- end\r
- noise_pwr(Tframes) = var(noise_samples);\r
- %plot(real(refl_symbols), imag(refl_symbols), '+');\r
- %hold on;\r
- %plot(real(exp(j*pi/4)*sig_est*ones(1,length(r))), imag(exp(j*pi/4)*sig_est*ones(1,length(r))), 'r+');\r
- %hold off;\r
- %printf("SNR: %f\n", 10*log10(sig_est*sig_est/noise_pwr(Tframes)));\r
- \r
- % Set erasures for carrier beneath a certain Es/N\r
- \r
- for n=1:Nc\r
- symbols++;\r
- EsN(n) = 10*log10(sig_pwr(Tframes,n)/noise_pwr(Tframes));\r
- if (EsN(n) < 1)\r
- %mod_codeword(n:Nc:length(mod_codeword)) = 0; \r
- %printf("Tframes: %d n: %d EsN = %3.2fdB\n", Tframes, n, EsN(n)); \r
- erasures++; \r
- end\r
- end\r
-\r
- % De-interleave again with erasures set ----------------------\r
-\r
- % remove UW symbols\r
-\r
- mod_codeword_no_uw = remove_uw_symbols(mod_codeword, code_param.data_bits_per_frame/2 - length(uw)/2, length(uw)/2);\r
- mod_codeword_no_uw = [mod_codeword_no_uw mod_codeword((code_param.data_bits_per_frame/2+1):code_param.code_bits_per_frame/2)];\r
-\r
- tmp = deinterleave_symbols(interleaver, mod_codeword_no_uw);\r
- \r
- % insert known symbols at end of data\r
-\r
- mod_codeword_deinter = [ tmp(1:(code_param.data_bits_per_frame/2 - length(uw)/2)) ...\r
- ones(1,length(uw)/2) * qpsk_mod([0 0]) ...\r
- tmp((code_param.data_bits_per_frame/2 - length(uw)/2+1):length(tmp)) ];\r
-\r
- % LDPC decode ------------------------------------------------\r
-\r
- detected_data = ldpc_dec(code_param, max_iterations, demod_type, decoder_type, mod_codeword_deinter, EsNo);\r
-\r
- % unpack payload data, removing UW\r
-\r
- vd_rx = detected_data(1:(code_param.data_bits_per_frame - length(uw)));\r
-\r
- % measure coded BER\r
-\r
- error_positions = xor(vd, vd_rx);\r
- Nerrs = sum(error_positions);\r
- if Nerrs>0, fprintf(1,'x'); Ferrs++; , else fprintf(1,'.'), end\r
- Tbits += length(vd);\r
- Terrs += Nerrs;\r
- nerr(Tframes) = Nerrs;\r
-\r
- % save error patterns is simulated vocoder data to disk\r
-\r
- fwrite(fep, error_positions, "short");\r
- \r
- end\r
-\r
- if (sync_state)\r
- sync_count++;\r
- if (sync_count == 8)\r
- sync_count = 0;\r
- end\r
- end\r
-\r
- % read in one modulated modem frame at a time\r
-\r
- [mod_unpackedmodem_float32, count] = fread(fm, nbitspermodemframe, "float32");\r
- if (fet == -1)\r
- entered_track = 0;\r
- else\r
- entered_track = fread(fet, 1, "int");\r
- end\r
- end\r
-\r
- fclose(fep);\r
-\r
- printf("\nFrames: %d bits: %d errors: %d Raw BER = %f Coded BER = %f FER = %f\n", Tframes, Tbits, Terrs, Trawerrs/Tbits, Terrs/Tbits, Ferrs/Tframes);\r
- printf("Symbols: %d Erasures: %d %f\n", symbols, erasures, erasures/symbols);\r
- figure(8)\r
- clf;\r
- [n m] = size(mod_unpackedmodem_log);\r
- plot( real(mod_unpackedmodem_log), imag(mod_unpackedmodem_log), '+')\r
- axis([-2 2 -2 2]);\r
- title('Scatter Diagram');\r
-\r
- figure(9)\r
- subplot(311)\r
- plot(sync_state_log);\r
- subplot(312)\r
- plot(nrawerr);\r
- subplot(313)\r
- plot(nerr);\r
-\r
- figure(10);\r
- plot(10*log10(sig_pwr(:,3)./noise_pwr(:)),'b');\r
- hold on;\r
- plot(10+10*log10(noise_pwr(:)));\r
- plot(10+10*log10(sig_pwr(:,3)),'r');\r
-% for n=2:Nc\r
-% plot(n*10+10*log10(sig_pwr(:,n)./noise_pwr(:,n)));\r
-% plot(n*10+10*log10(sig_pwr(:,n)),'r');\r
-% end\r
- hold off;\r
-\r
- y = 1:Tframes;\r
- x = 1:Nc;\r
- z = 10*log10(sig_pwr(:,:)./((noise_pwr(:)*ones(1, Nc))));\r
- %printf("mean SNR = %3.2fdB\n", mean(z));\r
- figure(11);\r
- imagesc(x,y,z);\r
- figure(12);\r
- mesh(x,y,z);\r
- axis([1 Nc 1 Tframes 5 15]);\r
-\r
-endfunction\r
+% ldpcdec.m
+% David Rowe 31 Dec 2013
+%
+% LDPC decoder test program, given a file of QPSK symbols (IQIQ floats),
+% performs frame sync, decodes, and measures BER.
+
+function ldpcdec(filename, Eprob)
+
+ % Start CML library
+
+ currentdir = pwd;
+ addpath '/home/david/tmp/cml/mat' % assume the source files stored here
+ cd /home/david/tmp/cml
+ CmlStartup % note that this is not in the cml path!
+ cd(currentdir)
+
+ % Our LDPC library
+
+ ldpc;
+
+ % Start simulation
+
+ rand('state',1);
+
+ rate = 3/4;
+ framesize = 576;
+
+ mod_order = 4;
+ modulation = 'QPSK';
+ mapping = 'gray';
+
+ demod_type = 0;
+ decoder_type = 0;
+ max_iterations = 100;
+ EsNo = 4;
+ if (nargin == 1)
+ Eprob = 0.0;
+ end
+
+ nbitspervocoderframe = 52;
+ nvocoderframes = 8;
+ nbitspermodemframe = 72;
+
+ code_param = ldpc_init(rate, framesize, modulation, mod_order, mapping);
+ code_param.code_bits_per_frame = 576;
+
+ data = [];
+ r = [];
+ load interleaver.txt
+ interleaver = interleaver + 1;
+
+ Nframes = 100;
+ uw = [1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0];
+
+ Nc = 18;
+
+ % repeat same simulated vocoder data to ease testing
+
+ vd = round( rand( 1, nbitspervocoderframe*nvocoderframes) );
+
+ % Decoder: Sync with LDPC frames, de-interleave, LDPC decode, strip off UW, measure BER -------
+
+ mcwfilename = strcat(filename,"_modcodeword.bin");
+ fm=fopen(mcwfilename,"rb");
+ etfilename = strcat(filename,"_modcodeword_et.bin");
+ fet=fopen(etfilename ,"rb");
+ epfilename = strcat(filename,".err");
+ fep=fopen(epfilename ,"wb");
+ printf("Input QPSK symbols: %s\n", mcwfilename);
+ if (fet == -1)
+ printf("Input entered track file: none\n");
+ else
+ printf("Input entered track file: %s\n", etfilename);
+ end
+ printf("Output error pattern file: %s\n", epfilename);
+
+ mod_uw = build_mod_uw(uw, 2*length(vd)/length(uw));
+
+ mod_codeword = zeros(1, code_param.code_bits_per_frame/2);
+ lmod_codeword = code_param.code_bits_per_frame/2;
+
+ Terrs = 0; Trawerrs = 0; Ferrs = 0; Tbits = 0; Tframes = 0; nerr = []; nrawerr = [];
+ corr = []; n = 0;
+ sync_state = 0; sync_count = 0;
+ mod_unpackedmodem_log = [];
+ sync_state_log = [];
+ entered_track_log = [];
+ sig_pwr_log = [];
+
+ symbols = erasures = 0;
+
+ [mod_unpackedmodem_float32, count] = fread(fm,nbitspermodemframe, "float32");
+ if (fet == -1)
+ entered_track = 0;
+ else
+ entered_track = fread(fet, 1, "int");
+ end
+
+ while (count == nbitspermodemframe)
+ n++;
+
+ mod_unpackedmodem = mod_unpackedmodem_float32(1:2:nbitspermodemframe) + j*mod_unpackedmodem_float32(2:2:nbitspermodemframe);
+ mod_unpackedmodem_log = [mod_unpackedmodem_log mod_unpackedmodem];
+ %erasures = rand(1,length(mod_unpackedmodem)) < Eprob;
+ %mod_unpackedmodem(erasures) = 0;
+
+ % keep buffer of one entire codeword
+
+ mod_codeword(1:lmod_codeword-length(mod_unpackedmodem)) = mod_codeword(length(mod_unpackedmodem)+1:lmod_codeword);
+ mod_codeword(lmod_codeword-length(mod_unpackedmodem)+1:lmod_codeword) = mod_unpackedmodem;
+
+ [uw_sync corr(n)] = look_for_uw(mod_codeword(1:length(mod_uw)), mod_uw);
+
+ next_sync_state = sync_state;
+ if ((sync_state == 0) && (uw_sync == 1))
+ next_sync_state = 1;
+ sync_count = 0;
+ end
+ if ((sync_state == 1) && (entered_track != 0))
+ next_sync_state = 0;
+ end
+ sync_state = next_sync_state;
+ sync_state_log = [sync_state_log sync_state];
+ entered_track_log = [entered_track_log entered_track];
+
+ if (sync_state && (sync_count == 0))
+ Tframes++;
+
+ % remove UW symbols
+
+ mod_codeword_no_uw = remove_uw_symbols(mod_codeword, code_param.data_bits_per_frame/2 - length(uw)/2, length(uw)/2);
+ mod_codeword_no_uw = [mod_codeword_no_uw mod_codeword((code_param.data_bits_per_frame/2+1):code_param.code_bits_per_frame/2)];
+
+ % de-interleave
+
+ tmp = deinterleave_symbols(interleaver, mod_codeword_no_uw);
+
+ % insert known symbols at end of data
+
+ mod_codeword_deinter = [ tmp(1:(code_param.data_bits_per_frame/2 - length(uw)/2)) ...
+ ones(1,length(uw)/2) * qpsk_mod([0 0]) ...
+ tmp((code_param.data_bits_per_frame/2 - length(uw)/2+1):length(tmp)) ];
+
+ % determine BER stats of raw data before decoding
+
+ raw_bits = zeros(1, code_param.data_bits_per_frame - length(uw));
+ for i=1:(code_param.data_bits_per_frame - length(uw))/2
+ raw_bits(2*(i-1)+1:2*i) = qpsk_demod(mod_codeword_deinter(i));
+ end
+ error_positions = xor(vd, raw_bits);
+ Nerrs = sum(error_positions);
+ Trawerrs += Nerrs;
+ nrawerr(Tframes) = Nerrs;
+
+ % Determine Es/N for each carrier. For this codeword we assume
+ % across codeword (currently 320ms) signal is stationary.
+ % So for each carrier signal level is constant, so we can
+ % average across all symols of that carrier to get a better
+ % estimate of the carrier power. The spectral noise density
+ % No will be the same for the bandwidth of each carrier. So
+ % we can use noise samples from all symbols together to get
+ % a better estimate of the noise power.
+
+ sig_pwr(Tframes,:) = zeros(1,Nc);
+ noise_samples = [];
+ for n=1:Nc
+
+ % extract a vector of one carrier's symbols for this codeword
+ % rotate so that decision boundaries are now real and imag axis
+
+ r = mod_codeword(n:Nc:length(mod_codeword)) .* exp(j*pi/4);
+
+ sig_est = mean(abs(r));
+
+ % The noise is the variance of symbols (samples) about the actual symbol position
+ % we reflect all symbols into the first quadrant to simplify things, as the actual
+ % received symbol isn't matter, just the noise around it. We model the received
+ % symbol based on the estimated signal level.
+
+ refl_symbols = abs(real(r)) + j*abs(imag(r));
+ est_symbols = exp(j*pi/4)*sig_est*ones(1,length(r));
+ noise_samples = [ noise_samples (est_symbols - refl_symbols)];
+
+ sig_pwr(Tframes,n) = sig_est .^ 2;
+ end
+ noise_pwr(Tframes) = var(noise_samples);
+ %plot(real(refl_symbols), imag(refl_symbols), '+');
+ %hold on;
+ %plot(real(exp(j*pi/4)*sig_est*ones(1,length(r))), imag(exp(j*pi/4)*sig_est*ones(1,length(r))), 'r+');
+ %hold off;
+ %printf("SNR: %f\n", 10*log10(sig_est*sig_est/noise_pwr(Tframes)));
+
+ % Set erasures for carrier beneath a certain Es/N
+
+ for n=1:Nc
+ symbols++;
+ EsN(n) = 10*log10(sig_pwr(Tframes,n)/noise_pwr(Tframes));
+ if (EsN(n) < 1)
+ %mod_codeword(n:Nc:length(mod_codeword)) = 0;
+ %printf("Tframes: %d n: %d EsN = %3.2fdB\n", Tframes, n, EsN(n));
+ erasures++;
+ end
+ end
+
+ % De-interleave again with erasures set ----------------------
+
+ % remove UW symbols
+
+ mod_codeword_no_uw = remove_uw_symbols(mod_codeword, code_param.data_bits_per_frame/2 - length(uw)/2, length(uw)/2);
+ mod_codeword_no_uw = [mod_codeword_no_uw mod_codeword((code_param.data_bits_per_frame/2+1):code_param.code_bits_per_frame/2)];
+
+ tmp = deinterleave_symbols(interleaver, mod_codeword_no_uw);
+
+ % insert known symbols at end of data
+
+ mod_codeword_deinter = [ tmp(1:(code_param.data_bits_per_frame/2 - length(uw)/2)) ...
+ ones(1,length(uw)/2) * qpsk_mod([0 0]) ...
+ tmp((code_param.data_bits_per_frame/2 - length(uw)/2+1):length(tmp)) ];
+
+ % LDPC decode ------------------------------------------------
+
+ detected_data = ldpc_dec(code_param, max_iterations, demod_type, decoder_type, mod_codeword_deinter, EsNo);
+
+ % unpack payload data, removing UW
+
+ vd_rx = detected_data(1:(code_param.data_bits_per_frame - length(uw)));
+
+ % measure coded BER
+
+ error_positions = xor(vd, vd_rx);
+ Nerrs = sum(error_positions);
+ if Nerrs>0, fprintf(1,'x'); Ferrs++; , else fprintf(1,'.'), end
+ Tbits += length(vd);
+ Terrs += Nerrs;
+ nerr(Tframes) = Nerrs;
+
+ % save error patterns is simulated vocoder data to disk
+
+ fwrite(fep, error_positions, "short");
+
+ end
+
+ if (sync_state)
+ sync_count++;
+ if (sync_count == 8)
+ sync_count = 0;
+ end
+ end
+
+ % read in one modulated modem frame at a time
+
+ [mod_unpackedmodem_float32, count] = fread(fm, nbitspermodemframe, "float32");
+ if (fet == -1)
+ entered_track = 0;
+ else
+ entered_track = fread(fet, 1, "int");
+ end
+ end
+
+ fclose(fep);
+
+ printf("\nFrames: %d bits: %d errors: %d Raw BER = %f Coded BER = %f FER = %f\n", Tframes, Tbits, Terrs, Trawerrs/Tbits, Terrs/Tbits, Ferrs/Tframes);
+ printf("Symbols: %d Erasures: %d %f\n", symbols, erasures, erasures/symbols);
+ figure(8)
+ clf;
+ [n m] = size(mod_unpackedmodem_log);
+ plot( real(mod_unpackedmodem_log), imag(mod_unpackedmodem_log), '+')
+ axis([-2 2 -2 2]);
+ title('Scatter Diagram');
+
+ figure(9)
+ subplot(311)
+ plot(sync_state_log);
+ subplot(312)
+ plot(nrawerr);
+ subplot(313)
+ plot(nerr);
+
+ figure(10);
+ plot(10*log10(sig_pwr(:,3)./noise_pwr(:)),'b');
+ hold on;
+ plot(10+10*log10(noise_pwr(:)));
+ plot(10+10*log10(sig_pwr(:,3)),'r');
+% for n=2:Nc
+% plot(n*10+10*log10(sig_pwr(:,n)./noise_pwr(:,n)));
+% plot(n*10+10*log10(sig_pwr(:,n)),'r');
+% end
+ hold off;
+
+ y = 1:Tframes;
+ x = 1:Nc;
+ z = 10*log10(sig_pwr(:,:)./((noise_pwr(:)*ones(1, Nc))));
+ %printf("mean SNR = %3.2fdB\n", mean(z));
+ figure(11);
+ imagesc(x,y,z);
+ figure(12);
+ mesh(x,y,z);
+ axis([1 Nc 1 Tframes 5 15]);
+
+endfunction
-% ldpcenc.m\r
-% David Rowe 20 Dec 2013\r
-% \r
-% LDPC encoder function. Takes a random data pattern, LDPC Encodes and\r
-% inserts Unique Word (UW) sync bits and ouputs this as a packed\r
-% binary file suitable for the Nc=18 carrier FDMDV modulator,\r
-% fdmdv_mod. Also produces a "modulated" output file of QPSK\r
-% symbols, suitable for feeding into ldpcdec for testing.\r
-\r
-function ldpcenc(filename)\r
-\r
- % Start CML library\r
-\r
- currentdir = pwd;\r
- addpath '/home/david/tmp/cml/mat' % assume the source files stored here\r
- cd /home/david/tmp/cml\r
- CmlStartup % note that this is not in the cml path!\r
- cd(currentdir)\r
- \r
- % Our LDPC library\r
-\r
- ldpc;\r
-\r
- % Start simulation\r
-\r
- rand('state',1);\r
-\r
- rate = 3/4; \r
- framesize = 576; \r
-\r
- mod_order = 4; \r
- modulation = 'QPSK';\r
- mapping = 'gray';\r
-\r
- demod_type = 0;\r
- decoder_type = 0;\r
- max_iterations = 100;\r
-\r
- nbitspervocoderframe = 52;\r
- nvocoderframes = 8;\r
- nbitspermodemframe = 72;\r
-\r
- code_param = ldpc_init(rate, framesize, modulation, mod_order, mapping);\r
-\r
- data = [];\r
- r = []; \r
- load interleaver.txt\r
- interleaver = interleaver + 1;\r
-\r
- % Encoder: Generate simulated vocoder data\r
- % LPDC encode\r
- % interleave \r
- % insert UW bits\r
-\r
- Nframes = 100;\r
- uw = [1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0];\r
-\r
- % repeat same simulated vocoder data to ease testing\r
-\r
- vd = round( rand( 1, nbitspervocoderframe*nvocoderframes) );\r
-\r
- % pad data with zeros the size of UW\r
-\r
- vdpad = [vd zeros(1, length(uw))];\r
-\r
- % LDPC encode\r
-\r
- [codewordpad, s] = ldpc_enc(vdpad, code_param);\r
- code_param.code_bits_per_frame = length(codewordpad);\r
- code_param.symbols_per_frame = length(s);\r
-\r
- % remove padded zeros after encoding to leave room for UW bits (code\r
- % is systematic)\r
-\r
- codeword = [ codewordpad(1:length(vd)) codewordpad((length(vd)+length(uw)+1):length(codewordpad)) ];\r
-\r
- % interleave, insert UW bits, and pack bits (as C modulator likes packed bits)\r
-\r
- codeword_interleaved = interleave_bits(interleaver, codeword);\r
- codeword_interleaved_uw = [insert_uw(codeword_interleaved(1:length(vd)), uw) codeword_interleaved(length(vd)+1:length(codeword_interleaved)) ];\r
- packedcodeword = packmsb(codeword_interleaved_uw);\r
-\r
- cwfilename = strcat(filename,"_codeword.bin");\r
- fc=fopen(cwfilename,"wb");\r
- for nn = 1: Nframes \r
- fwrite(fc,packedcodeword,"uchar");\r
- end\r
- fclose(fc);\r
-\r
- %printf("framesize: %d data_bits_per_frame: %d code_bits_per_frame: %d\n", ...\r
- % framesize, code_param.data_bits_per_frame, code_param.code_bits_per_frame);\r
-\r
- printf("Encoded %d LDPC codewords, saved in packed file: %s\n", Nframes, cwfilename);\r
-\r
- % Modulator: Modulate to QPSK symbols ------------------------------------------\r
-\r
- nbytespackedcodeword=length(packedcodeword);\r
- fc=fopen(cwfilename,"rb");\r
- mcwfilename = strcat(filename,"_modcodeword.bin");\r
- fm=fopen(mcwfilename,"wb");\r
- nbytespackedmodemframe = nbitspermodemframe/8;\r
- n = 0;\r
-\r
- [packedmodem, count] = fread(fc,nbytespackedmodemframe,"uchar");\r
- while (count == nbytespackedmodemframe)\r
- n++;\r
- unpackedmodem = unpackmsb(packedmodem);\r
-\r
- ii = 1;\r
- for i=1:2:length(unpackedmodem)\r
- mod_unpackedmodem(ii) = qpsk_mod(unpackedmodem(i:i+1));\r
- mod_unpackedmodem_float32(i) = real(mod_unpackedmodem(ii));\r
- mod_unpackedmodem_float32(i+1) = imag(mod_unpackedmodem(ii));\r
- ii += 1;\r
- end\r
-\r
- fwrite(fm, mod_unpackedmodem_float32, "float32");\r
- [packedmodem, count] = fread(fc,nbytespackedmodemframe,"uchar");\r
- end\r
- fclose(fc);\r
- fclose(fm);\r
- printf("Modulated %d modem frames to file: %s\n", n, mcwfilename);\r
-endfunction\r
-\r
-\r
+% ldpcenc.m
+% David Rowe 20 Dec 2013
+%
+% LDPC encoder function. Takes a random data pattern, LDPC Encodes and
+% inserts Unique Word (UW) sync bits and ouputs this as a packed
+% binary file suitable for the Nc=18 carrier FDMDV modulator,
+% fdmdv_mod. Also produces a "modulated" output file of QPSK
+% symbols, suitable for feeding into ldpcdec for testing.
+
+function ldpcenc(filename)
+
+ % Start CML library
+
+ currentdir = pwd;
+ addpath '/home/david/tmp/cml/mat' % assume the source files stored here
+ cd /home/david/tmp/cml
+ CmlStartup % note that this is not in the cml path!
+ cd(currentdir)
+
+ % Our LDPC library
+
+ ldpc;
+
+ % Start simulation
+
+ rand('state',1);
+
+ rate = 3/4;
+ framesize = 576;
+
+ mod_order = 4;
+ modulation = 'QPSK';
+ mapping = 'gray';
+
+ demod_type = 0;
+ decoder_type = 0;
+ max_iterations = 100;
+
+ nbitspervocoderframe = 52;
+ nvocoderframes = 8;
+ nbitspermodemframe = 72;
+
+ code_param = ldpc_init(rate, framesize, modulation, mod_order, mapping);
+
+ data = [];
+ r = [];
+ load interleaver.txt
+ interleaver = interleaver + 1;
+
+ % Encoder: Generate simulated vocoder data
+ % LPDC encode
+ % interleave
+ % insert UW bits
+
+ Nframes = 100;
+ uw = [1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0];
+
+ % repeat same simulated vocoder data to ease testing
+
+ vd = round( rand( 1, nbitspervocoderframe*nvocoderframes) );
+
+ % pad data with zeros the size of UW
+
+ vdpad = [vd zeros(1, length(uw))];
+
+ % LDPC encode
+
+ [codewordpad, s] = ldpc_enc(vdpad, code_param);
+ code_param.code_bits_per_frame = length(codewordpad);
+ code_param.symbols_per_frame = length(s);
+
+ % remove padded zeros after encoding to leave room for UW bits (code
+ % is systematic)
+
+ codeword = [ codewordpad(1:length(vd)) codewordpad((length(vd)+length(uw)+1):length(codewordpad)) ];
+
+ % interleave, insert UW bits, and pack bits (as C modulator likes packed bits)
+
+ codeword_interleaved = interleave_bits(interleaver, codeword);
+ codeword_interleaved_uw = [insert_uw(codeword_interleaved(1:length(vd)), uw) codeword_interleaved(length(vd)+1:length(codeword_interleaved)) ];
+ packedcodeword = packmsb(codeword_interleaved_uw);
+
+ cwfilename = strcat(filename,"_codeword.bin");
+ fc=fopen(cwfilename,"wb");
+ for nn = 1: Nframes
+ fwrite(fc,packedcodeword,"uchar");
+ end
+ fclose(fc);
+
+ %printf("framesize: %d data_bits_per_frame: %d code_bits_per_frame: %d\n", ...
+ % framesize, code_param.data_bits_per_frame, code_param.code_bits_per_frame);
+
+ printf("Encoded %d LDPC codewords, saved in packed file: %s\n", Nframes, cwfilename);
+
+ % Modulator: Modulate to QPSK symbols ------------------------------------------
+
+ nbytespackedcodeword=length(packedcodeword);
+ fc=fopen(cwfilename,"rb");
+ mcwfilename = strcat(filename,"_modcodeword.bin");
+ fm=fopen(mcwfilename,"wb");
+ nbytespackedmodemframe = nbitspermodemframe/8;
+ n = 0;
+
+ [packedmodem, count] = fread(fc,nbytespackedmodemframe,"uchar");
+ while (count == nbytespackedmodemframe)
+ n++;
+ unpackedmodem = unpackmsb(packedmodem);
+
+ ii = 1;
+ for i=1:2:length(unpackedmodem)
+ mod_unpackedmodem(ii) = qpsk_mod(unpackedmodem(i:i+1));
+ mod_unpackedmodem_float32(i) = real(mod_unpackedmodem(ii));
+ mod_unpackedmodem_float32(i+1) = imag(mod_unpackedmodem(ii));
+ ii += 1;
+ end
+
+ fwrite(fm, mod_unpackedmodem_float32, "float32");
+ [packedmodem, count] = fread(fc,nbytespackedmodemframe,"uchar");
+ end
+ fclose(fc);
+ fclose(fm);
+ printf("Modulated %d modem frames to file: %s\n", n, mcwfilename);
+endfunction
+
+
-% ldpcut.m\r
-%\r
-% David Rowe 18 Dec 2013\r
-%\r
-% Octave LDPC unit test script, based on simulation by Bill Cowley VK5DSP\r
-%\r
-\r
-% Start CML library (see CML set up instructions in ldpc.m)\r
-\r
-currentdir = pwd;\r
-addpath '/home/david/tmp/cml/mat' % assume the source files stored here\r
-cd /home/david/tmp/cml\r
-CmlStartup % note that this is not in the cml path!\r
-cd(currentdir)\r
-\r
-% Our LDPC library\r
-\r
-ldpc;\r
-qpsk_;\r
-\r
-function sim_out = run_simulation(sim_in)\r
-\r
- rate = sim_in.rate; \r
- framesize = sim_in.framesize; \r
- Ntrials = sim_in.Ntrials;\r
- EsNodBvec = sim_in.EsNodBvec;\r
- verbose = sim_in.verbose;\r
-\r
- % Start simulation\r
-\r
- mod_order = 4; \r
- modulation = 'QPSK';\r
- mapping = 'gray';\r
-\r
- demod_type = 0;\r
- decoder_type = 0;\r
- max_iterations = 100;\r
-\r
- code_param = ldpc_init(rate, framesize, modulation, mod_order, mapping);\r
-\r
- for ne = 1:length(EsNodBvec)\r
- EsNodB = EsNodBvec(ne);\r
- EsNo = 10^(EsNodB/10);\r
- variance = 1/EsNo;\r
-\r
- Tbits = Terrs = Ferrs = 0;\r
- \r
- tx_bits = [];\r
- tx_symbols = []; \r
- rx_symbols = [];\r
-\r
- % Encode a bunch of frames\r
-\r
- for nn = 1: Ntrials \r
- atx_bits = round(rand( 1, code_param.data_bits_per_frame));\r
- tx_bits = [tx_bits atx_bits];\r
- [tx_codeword atx_symbols] = ldpc_enc(atx_bits, code_param);\r
- tx_symbols = [tx_symbols atx_symbols];\r
- end\r
-\r
- % Add AWGN noise, 0.5 factor ensures var(noise) == variance , i.e. splits power between Re & Im\r
-\r
- noise = sqrt(variance*0.5)*(randn(1,length(tx_symbols)) + j*randn(1,length(tx_symbols)));\r
- rx_symbols = tx_symbols + noise;\r
-\r
- % Decode a bunch of frames\r
-\r
- for nn = 1: Ntrials \r
- st = (nn-1)*code_param.symbols_per_frame + 1;\r
- en = (nn)*code_param.symbols_per_frame;\r
- arx_codeword = ldpc_dec(code_param, max_iterations, demod_type, decoder_type, rx_symbols(st:en), EsNo, ones(1,code_param.symbols_per_frame));\r
- st = (nn-1)*code_param.data_bits_per_frame + 1;\r
- en = (nn)*code_param.data_bits_per_frame;\r
- error_positions = xor(arx_codeword(1:code_param.data_bits_per_frame), tx_bits(st:en));\r
- Nerrs = sum( error_positions);\r
- \r
- if verbose == 2\r
- % print "." if frame decoded without errors, 'x' if we can't decode\r
-\r
- if Nerrs > 0, printf('x'), else printf('.'), end\r
- if (rem(nn, 50)==0), printf('\n'), end \r
- end\r
-\r
- if Nerrs > 0, Ferrs = Ferrs + 1; end\r
- Terrs = Terrs + Nerrs;\r
- Tbits = Tbits + code_param.data_bits_per_frame; \r
- end\r
-\r
- if verbose\r
- printf("\nEsNodB: %3.2f BER: %f Tbits: %d Terrs: %d Ferrs: %d\n", EsNodB, Terrs/Tbits, Tbits, Terrs, Ferrs)\r
- end\r
-\r
- sim_out.Tbits(ne) = Tbits;\r
- sim_out.Terrs(ne) = Terrs;\r
- sim_out.Ferrs(ne) = Ferrs;\r
- sim_out.BER(ne) = Terrs/Tbits;\r
- sim_out.FER(ne) = Ferrs/Ntrials;\r
- end\r
-\r
-endfunction\r
-\r
-% START SIMULATIONS ---------------------------------------------------------------\r
-\r
-more off;\r
-\r
-% 1/ Simplest possible one frame simulation ---------------------------------------\r
-\r
-printf("Test 1\n------\n");\r
-\r
-mod_order = 4; \r
-modulation = 'QPSK';\r
-mapping = 'gray';\r
-framesize = 576; % CML library has a bunch of different framesizes available\r
-rate = 1/2;\r
-demod_type = 0;\r
-decoder_type = 0;\r
-max_iterations = 100;\r
-EsNo = 10; % decoder needs an estimated channel EsNo (linear ratio, not dB)\r
-\r
-code_param = ldpc_init(rate, framesize, modulation, mod_order, mapping);\r
-tx_bits = round(rand(1, code_param.data_bits_per_frame));\r
-[tx_codeword, qpsk_symbols] = ldpc_enc(tx_bits, code_param);\r
-rx_codeword = ldpc_dec(code_param, max_iterations, demod_type, decoder_type, qpsk_symbols, EsNo);\r
-\r
-errors_positions = xor(tx_bits, rx_codeword(1:framesize*rate));\r
-Nerr = sum(errors_positions);\r
-printf("Nerr: %d\n\n", Nerr);\r
-\r
-% 2/ Run a bunch of trials at just one EsNo point --------------------------------------\r
-\r
-printf("Test 2\n------\n");\r
-\r
-sim_in.rate = 0.5; \r
-sim_in.framesize = 2*576; \r
-sim_in.verbose = 2;\r
-sim_in.Ntrials = 100;\r
-sim_in.EsNodBvec = 5;\r
-run_simulation(sim_in);\r
-\r
-% 3/ Lets draw a Eb/No versus BER curve -------------------------------------------------\r
-\r
-printf("\n\nTest 3\n------\n");\r
-\r
-sim_in.EsNodBvec = -2:10;\r
-sim_out = run_simulation(sim_in);\r
-\r
-EbNodB = sim_in.EsNodBvec - 10*log10(2); % QPSK has two bits/symbol\r
-uncoded_BER_theory = 0.5*erfc(sqrt(10.^(EbNodB/10)));\r
-\r
-figure(1)\r
-clf\r
-semilogy(EbNodB, uncoded_BER_theory,'r;uncoded QPSK theory;')\r
-hold on;\r
-semilogy(EbNodB-10*log10(sim_in.rate), sim_out.BER+1E-10,'g;LDPC coded QPSK simulation;');\r
-hold off;\r
-grid('minor')\r
-xlabel('Eb/No (dB)')\r
-ylabel('BER')\r
-axis([min(EbNodB) max(EbNodB) min(uncoded_BER_theory) 1])\r
+% ldpcut.m
+%
+% David Rowe 18 Dec 2013
+%
+% Octave LDPC unit test script, based on simulation by Bill Cowley VK5DSP
+%
+
+% Start CML library (see CML set up instructions in ldpc.m)
+
+currentdir = pwd;
+addpath '/home/david/tmp/cml/mat' % assume the source files stored here
+cd /home/david/tmp/cml
+CmlStartup % note that this is not in the cml path!
+cd(currentdir)
+
+% Our LDPC library
+
+ldpc;
+qpsk_;
+
+function sim_out = run_simulation(sim_in)
+
+ rate = sim_in.rate;
+ framesize = sim_in.framesize;
+ Ntrials = sim_in.Ntrials;
+ EsNodBvec = sim_in.EsNodBvec;
+ verbose = sim_in.verbose;
+
+ % Start simulation
+
+ mod_order = 4;
+ modulation = 'QPSK';
+ mapping = 'gray';
+
+ demod_type = 0;
+ decoder_type = 0;
+ max_iterations = 100;
+
+ code_param = ldpc_init(rate, framesize, modulation, mod_order, mapping);
+
+ for ne = 1:length(EsNodBvec)
+ EsNodB = EsNodBvec(ne);
+ EsNo = 10^(EsNodB/10);
+ variance = 1/EsNo;
+
+ Tbits = Terrs = Ferrs = 0;
+
+ tx_bits = [];
+ tx_symbols = [];
+ rx_symbols = [];
+
+ % Encode a bunch of frames
+
+ for nn = 1: Ntrials
+ atx_bits = round(rand( 1, code_param.data_bits_per_frame));
+ tx_bits = [tx_bits atx_bits];
+ [tx_codeword atx_symbols] = ldpc_enc(atx_bits, code_param);
+ tx_symbols = [tx_symbols atx_symbols];
+ end
+
+ % Add AWGN noise, 0.5 factor ensures var(noise) == variance , i.e. splits power between Re & Im
+
+ noise = sqrt(variance*0.5)*(randn(1,length(tx_symbols)) + j*randn(1,length(tx_symbols)));
+ rx_symbols = tx_symbols + noise;
+
+ % Decode a bunch of frames
+
+ for nn = 1: Ntrials
+ st = (nn-1)*code_param.symbols_per_frame + 1;
+ en = (nn)*code_param.symbols_per_frame;
+ arx_codeword = ldpc_dec(code_param, max_iterations, demod_type, decoder_type, rx_symbols(st:en), EsNo, ones(1,code_param.symbols_per_frame));
+ st = (nn-1)*code_param.data_bits_per_frame + 1;
+ en = (nn)*code_param.data_bits_per_frame;
+ error_positions = xor(arx_codeword(1:code_param.data_bits_per_frame), tx_bits(st:en));
+ Nerrs = sum( error_positions);
+
+ if verbose == 2
+ % print "." if frame decoded without errors, 'x' if we can't decode
+
+ if Nerrs > 0, printf('x'), else printf('.'), end
+ if (rem(nn, 50)==0), printf('\n'), end
+ end
+
+ if Nerrs > 0, Ferrs = Ferrs + 1; end
+ Terrs = Terrs + Nerrs;
+ Tbits = Tbits + code_param.data_bits_per_frame;
+ end
+
+ if verbose
+ printf("\nEsNodB: %3.2f BER: %f Tbits: %d Terrs: %d Ferrs: %d\n", EsNodB, Terrs/Tbits, Tbits, Terrs, Ferrs)
+ end
+
+ sim_out.Tbits(ne) = Tbits;
+ sim_out.Terrs(ne) = Terrs;
+ sim_out.Ferrs(ne) = Ferrs;
+ sim_out.BER(ne) = Terrs/Tbits;
+ sim_out.FER(ne) = Ferrs/Ntrials;
+ end
+
+endfunction
+
+% START SIMULATIONS ---------------------------------------------------------------
+
+more off;
+
+% 1/ Simplest possible one frame simulation ---------------------------------------
+
+printf("Test 1\n------\n");
+
+mod_order = 4;
+modulation = 'QPSK';
+mapping = 'gray';
+framesize = 576; % CML library has a bunch of different framesizes available
+rate = 1/2;
+demod_type = 0;
+decoder_type = 0;
+max_iterations = 100;
+EsNo = 10; % decoder needs an estimated channel EsNo (linear ratio, not dB)
+
+code_param = ldpc_init(rate, framesize, modulation, mod_order, mapping);
+tx_bits = round(rand(1, code_param.data_bits_per_frame));
+[tx_codeword, qpsk_symbols] = ldpc_enc(tx_bits, code_param);
+rx_codeword = ldpc_dec(code_param, max_iterations, demod_type, decoder_type, qpsk_symbols, EsNo);
+
+errors_positions = xor(tx_bits, rx_codeword(1:framesize*rate));
+Nerr = sum(errors_positions);
+printf("Nerr: %d\n\n", Nerr);
+
+% 2/ Run a bunch of trials at just one EsNo point --------------------------------------
+
+printf("Test 2\n------\n");
+
+sim_in.rate = 0.5;
+sim_in.framesize = 2*576;
+sim_in.verbose = 2;
+sim_in.Ntrials = 100;
+sim_in.EsNodBvec = 5;
+run_simulation(sim_in);
+
+% 3/ Lets draw a Eb/No versus BER curve -------------------------------------------------
+
+printf("\n\nTest 3\n------\n");
+
+sim_in.EsNodBvec = -2:10;
+sim_out = run_simulation(sim_in);
+
+EbNodB = sim_in.EsNodBvec - 10*log10(2); % QPSK has two bits/symbol
+uncoded_BER_theory = 0.5*erfc(sqrt(10.^(EbNodB/10)));
+
+figure(1)
+clf
+semilogy(EbNodB, uncoded_BER_theory,'r;uncoded QPSK theory;')
+hold on;
+semilogy(EbNodB-10*log10(sim_in.rate), sim_out.BER+1E-10,'g;LDPC coded QPSK simulation;');
+hold off;
+grid('minor')
+xlabel('Eb/No (dB)')
+ylabel('BER')
+axis([min(EbNodB) max(EbNodB) min(uncoded_BER_theory) 1])
-function [ar,e,k]=lpcauto(s,p,t)\r
-%LPCAUTO performs autocorrelation LPC analysis [AR,E,K]=(S,P,T)\r
-% Inputs:\r
-% s(ns) is the input signal\r
-% p is the order (default: 12)\r
-% t(nf,3) specifies the frames size details: each row specifies\r
-% up to three values per frame: [len anal skip] where:\r
-% len is the length of the frame (default: length(s))\r
-% anal is the analysis length (default: len)\r
-% skip is the number of samples to skip at the beginning (default: 0)\r
-% If t contains only one row, it will be used repeatedly\r
-% until there are no more samples left in s.\r
-%\r
-% Outputs:\r
-% ar(nf,p+1) are the AR coefficients with ar(1) = 1\r
-% e(nf) is the energy in the residual.\r
-% sqrt(e) is often called the 'gain' of the filter.\r
-% k(nf,2) gives the first and last sample of the analysis interval\r
-\r
-% Notes:\r
-%\r
-% (1) The first frame always starts at sample s(1) and the analysis window starts at s(t(1,3)+1).\r
-% (2) The elements of t need not be integers.\r
-% (3) The analysis interval is always multiplied by a hamming window\r
-% (4) As an example, if p=3 and t=[10 5 2], then the illustration below shows\r
-% successive frames labelled a, b, c, ... with capitals for the\r
-% analysis regions. Note that the first frame starts at s(1)\r
-%\r
-% a a A A A A A a a a b b B B B B B b b b c c C C C C C c c c d ...\r
-%\r
-% For speech processing, it can be advantageous to restrict the analysis regions\r
-% to time intervals when the glottis is closed.\r
-%\r
-% (5) Frames can overlap: e.g. t=[10 20] will use analysis frames of\r
-% length 20 overlapped by 10 samples.\r
-% (6) For speech processing p should be at least 2*f*l/c where f is the sampling\r
-% frequency, l the vocal tract length and c the speed of sound. For a typical\r
-% male (l=17 cm) this gives f/1000.\r
-\r
-% Copyright (C) Mike Brookes 1997\r
-% Version: $Id: lpcauto.m 713 2011-10-16 14:45:43Z dmb $\r
-%\r
-% VOICEBOX is a MATLAB toolbox for speech processing.\r
-% Home page: http://www.ee.ic.ac.uk/hp/staff/dmb/voicebox/voicebox.html\r
-%\r
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\r
-% This program is free software; you can redistribute it and/or modify\r
-% it under the terms of the GNU General Public License as published by\r
-% the Free Software Foundation; either version 2 of the License, or\r
-% (at your option) any later version.\r
-%\r
-% This program is distributed in the hope that it will be useful,\r
-% but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
-% GNU General Public License for more details.\r
-%\r
-% You can obtain a copy of the GNU General Public License from\r
-% http://www.gnu.org/copyleft/gpl.html or by writing to\r
-% Free Software Foundation, Inc.,675 Mass Ave, Cambridge, MA 02139, USA.\r
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\r
-\r
-s = s(:); % make it a column vector\r
-if nargin < 2 p=12; end;\r
-if nargin < 3 t=length(s); end;\r
-%if nargin < 4 w='ham'; end;\r
-[nf,ng]=size(t);\r
-if ng<2 t=[t t]; end;\r
-if ng<3 t=[t zeros(nf,1)]; end;\r
-if nf==1\r
- nf=floor(1+(length(s)-t(2)-t(3))/t(1));\r
- tr=0;\r
-else\r
- tr=1;\r
-end;\r
-\r
-ar=zeros(nf,p+1);\r
-ar(:,1)=1;\r
-e=zeros(nf,1);\r
-\r
-t1=1;\r
-it=1;\r
-nw=-1;\r
-zp=zeros(1,p);\r
-r=(0:p);\r
-for jf=1:nf\r
- k(jf,1) = ceil(t1+t(it,3));\r
- k(jf,2) = ceil(t1+t(it,3)+t(it,2)-1);\r
- cs = (k(jf,1):k(jf,2)).';\r
- nc = length(cs);\r
- pp=min(p,nc);\r
- dd=s(cs);\r
- if nc~=nw\r
- % possibly we should have a window whose square integral equals unity\r
- ww=hamming(nc); nw=nc;\r
- y=zeros(1,nc+p);\r
- c=(1:nc)';\r
- end\r
- wd=dd(:).*ww; % windowed data vector\r
- y(1:nc)=wd; % data vector with p appended zeros\r
- z=zeros(nc,pp+1); % data matrix\r
- % was previously z(:)=y(c(:,ones(1,pp+1))+r(ones(nc,1),1:pp+1));\r
- z(:)=y(repmat(c,1,pp+1)+repmat(r,nc,1));\r
- rr=wd'*z;\r
- rm=toeplitz(rr(1:pp));\r
- rk=rank(rm);\r
- if rk\r
- if rk<pp\r
- rm=rm(1:rk,1:rk);\r
- end\r
- ar(jf,2:rk+1)=-rr(2:rk+1)/rm;\r
- end\r
- e(jf)=rr*ar(jf,1:pp+1)';\r
- t1=t1+t(it,1);\r
- it=it+tr;\r
-end\r
-\r
+function [ar,e,k]=lpcauto(s,p,t)
+%LPCAUTO performs autocorrelation LPC analysis [AR,E,K]=(S,P,T)
+% Inputs:
+% s(ns) is the input signal
+% p is the order (default: 12)
+% t(nf,3) specifies the frames size details: each row specifies
+% up to three values per frame: [len anal skip] where:
+% len is the length of the frame (default: length(s))
+% anal is the analysis length (default: len)
+% skip is the number of samples to skip at the beginning (default: 0)
+% If t contains only one row, it will be used repeatedly
+% until there are no more samples left in s.
+%
+% Outputs:
+% ar(nf,p+1) are the AR coefficients with ar(1) = 1
+% e(nf) is the energy in the residual.
+% sqrt(e) is often called the 'gain' of the filter.
+% k(nf,2) gives the first and last sample of the analysis interval
+
+% Notes:
+%
+% (1) The first frame always starts at sample s(1) and the analysis window starts at s(t(1,3)+1).
+% (2) The elements of t need not be integers.
+% (3) The analysis interval is always multiplied by a hamming window
+% (4) As an example, if p=3 and t=[10 5 2], then the illustration below shows
+% successive frames labelled a, b, c, ... with capitals for the
+% analysis regions. Note that the first frame starts at s(1)
+%
+% a a A A A A A a a a b b B B B B B b b b c c C C C C C c c c d ...
+%
+% For speech processing, it can be advantageous to restrict the analysis regions
+% to time intervals when the glottis is closed.
+%
+% (5) Frames can overlap: e.g. t=[10 20] will use analysis frames of
+% length 20 overlapped by 10 samples.
+% (6) For speech processing p should be at least 2*f*l/c where f is the sampling
+% frequency, l the vocal tract length and c the speed of sound. For a typical
+% male (l=17 cm) this gives f/1000.
+
+% Copyright (C) Mike Brookes 1997
+% Version: $Id: lpcauto.m 713 2011-10-16 14:45:43Z dmb $
+%
+% VOICEBOX is a MATLAB toolbox for speech processing.
+% Home page: http://www.ee.ic.ac.uk/hp/staff/dmb/voicebox/voicebox.html
+%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% This program is free software; you can redistribute it and/or modify
+% it under the terms of the GNU General Public License as published by
+% the Free Software Foundation; either version 2 of the License, or
+% (at your option) any later version.
+%
+% This program is distributed in the hope that it will be useful,
+% but WITHOUT ANY WARRANTY; without even the implied warranty of
+% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+% GNU General Public License for more details.
+%
+% You can obtain a copy of the GNU General Public License from
+% http://www.gnu.org/copyleft/gpl.html or by writing to
+% Free Software Foundation, Inc.,675 Mass Ave, Cambridge, MA 02139, USA.
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+s = s(:); % make it a column vector
+if nargin < 2 p=12; end;
+if nargin < 3 t=length(s); end;
+%if nargin < 4 w='ham'; end;
+[nf,ng]=size(t);
+if ng<2 t=[t t]; end;
+if ng<3 t=[t zeros(nf,1)]; end;
+if nf==1
+ nf=floor(1+(length(s)-t(2)-t(3))/t(1));
+ tr=0;
+else
+ tr=1;
+end;
+
+ar=zeros(nf,p+1);
+ar(:,1)=1;
+e=zeros(nf,1);
+
+t1=1;
+it=1;
+nw=-1;
+zp=zeros(1,p);
+r=(0:p);
+for jf=1:nf
+ k(jf,1) = ceil(t1+t(it,3));
+ k(jf,2) = ceil(t1+t(it,3)+t(it,2)-1);
+ cs = (k(jf,1):k(jf,2)).';
+ nc = length(cs);
+ pp=min(p,nc);
+ dd=s(cs);
+ if nc~=nw
+ % possibly we should have a window whose square integral equals unity
+ ww=hamming(nc); nw=nc;
+ y=zeros(1,nc+p);
+ c=(1:nc)';
+ end
+ wd=dd(:).*ww; % windowed data vector
+ y(1:nc)=wd; % data vector with p appended zeros
+ z=zeros(nc,pp+1); % data matrix
+ % was previously z(:)=y(c(:,ones(1,pp+1))+r(ones(nc,1),1:pp+1));
+ z(:)=y(repmat(c,1,pp+1)+repmat(r,nc,1));
+ rr=wd'*z;
+ rm=toeplitz(rr(1:pp));
+ rk=rank(rm);
+ if rk
+ if rk<pp
+ rm=rm(1:rk,1:rk);
+ end
+ ar(jf,2:rk+1)=-rr(2:rk+1)/rm;
+ end
+ e(jf)=rr*ar(jf,1:pp+1)';
+ t1=t1+t(it,1);
+ it=it+tr;
+end
+
-% test_dqpsk.m\r
-% David Rowe March 2014\r
-%\r
-% Single sample/symbol DQPSK modem simulation to test modulating modem\r
-% tx power based on speech energy.\r
-\r
-1;\r
-\r
-% main test function \r
-\r
-function sim_out = ber_test(sim_in)\r
- Fs = 8000;\r
-\r
- verbose = sim_in.verbose;\r
- framesize = sim_in.framesize;\r
- Ntrials = sim_in.Ntrials;\r
- Esvec = sim_in.Esvec;\r
- phase_offset = sim_in.phase_offset;\r
- w_offset = sim_in.w_offset;\r
- plot_scatter = sim_in.plot_scatter;\r
- Rs = sim_in.Rs;\r
- hf_sim = sim_in.hf_sim;\r
- nhfdelay = sim_in.hf_delay_ms*Rs/1000;\r
- hf_phase_only = sim_in.hf_phase_only;\r
- hf_mag_only = sim_in.hf_mag_only;\r
- Nc = sim_in.Nc;\r
- symbol_amp = sim_in.symbol_amp;\r
-\r
- bps = 2;\r
- Nsymb = framesize/bps;\r
- for k=1:Nc\r
- prev_sym_tx(k) = qpsk_mod([0 0]);\r
- prev_sym_rx(k) = qpsk_mod([0 0]);\r
- end\r
-\r
- rate = 1;\r
-\r
- % Init HF channel model from stored sample files of spreading signal ----------------------------------\r
-\r
- % convert "spreading" samples from 1kHz carrier at Fs to complex\r
- % baseband, generated by passing a 1kHz sine wave through PathSim\r
- % with the ccir-poor model, enabling one path at a time.\r
- \r
- Fc = 1000; M = Fs/Rs;\r
- fspread = fopen("../raw/sine1k_2Hz_spread.raw","rb");\r
- spread1k = fread(fspread, "int16")/10000;\r
- fclose(fspread);\r
- fspread = fopen("../raw/sine1k_2ms_delay_2Hz_spread.raw","rb");\r
- spread1k_2ms = fread(fspread, "int16")/10000;\r
- fclose(fspread);\r
-\r
- % down convert to complex baseband\r
- spreadbb = spread1k.*exp(-j*(2*pi*Fc/Fs)*(1:length(spread1k))');\r
- spreadbb_2ms = spread1k_2ms.*exp(-j*(2*pi*Fc/Fs)*(1:length(spread1k_2ms))');\r
-\r
- % remove -2000 Hz image\r
- b = fir1(50, 5/Fs);\r
- spread = filter(b,1,spreadbb);\r
- spread_2ms = filter(b,1,spreadbb_2ms);\r
-\r
- % discard first 1000 samples as these were near 0, probably as\r
- % PathSim states were ramping up\r
-\r
- spread = spread(1000:length(spread));\r
- spread_2ms = spread_2ms(1000:length(spread_2ms));\r
-\r
- % decimate down to Rs\r
-\r
- spread = spread(1:M:length(spread));\r
- spread_2ms = spread_2ms(1:M:length(spread_2ms));\r
-\r
- % Determine "gain" of HF channel model, so we can normalise\r
- % carrier power during HF channel sim to calibrate SNR. I imagine\r
- % different implementations of ccir-poor would do this in\r
- % different ways, leading to different BER results. Oh Well!\r
-\r
- hf_gain = 1.0/sqrt(var(spread)+var(spread_2ms));\r
-\r
- % Start Simulation ----------------------------------------------------------------\r
-\r
- for ne = 1:length(Esvec)\r
- EsNodB = Esvec(ne);\r
- EsNo = 10^(EsNodB/10);\r
- \r
- variance = 1/EsNo;\r
- if verbose > 1\r
- printf("EsNo (dB): %f EsNo: %f variance: %f\n", EsNodB, EsNo, variance);\r
- end\r
- \r
- Terrs = 0; Tbits = 0;\r
-\r
- tx_symb_log = [];\r
- rx_symb_log = [];\r
- noise_log = [];\r
- sim_out.errors_log = [];\r
-\r
- % init HF channel\r
-\r
- hf_n = 1;\r
- hf_angle_log = [];\r
- hf_fading = ones(1,Nsymb); % default input for ldpc dec\r
- hf_model = ones(Ntrials*Nsymb/Nc, Nc); % defaults for plotting surface\r
-\r
- sim_out.errors_log = [];\r
- sim_out.Nerrs = [];\r
- sim_out.snr_log = [];\r
- sim_out.hf_model_pwr = [];\r
-\r
- symbol_amp_index = 1;\r
-\r
- for nn = 1: Ntrials\r
- \r
- tx_bits = round( rand( 1, framesize*rate ) );\r
- \r
- % modulate --------------------------------------------\r
-\r
- s = zeros(1, Nsymb);\r
- for i=1:Nc:Nsymb\r
- for k=1:Nc\r
- tx_symb = qpsk_mod(tx_bits(2*(i-1+k-1)+1:2*(i+k-1)));\r
- tx_symb *= prev_sym_tx(k);\r
- prev_sym_tx(k) = tx_symb;\r
- s(i+k-1) = symbol_amp(symbol_amp_index)*tx_symb;\r
- end\r
- end\r
- s_ch = s;\r
- symbol_amp_index++;\r
-\r
- % HF channel simulation ------------------------------------\r
- \r
- if hf_sim\r
-\r
- % separation between carriers. Note this is\r
- % effectively under samples at Rs, I dont think this\r
- % matters. Equivalent to doing freq shift at Fs, then\r
- % decimating to Rs.\r
-\r
- wsep = 2*pi*(1+0.5); % e.g. 75Hz spacing at Rs=50Hz, alpha=0.5 filters\r
-\r
- if Nsymb/Nc != floor(Nsymb/Nc)\r
- printf("Error: Nsymb/Nc must be an integrer\n")\r
- return;\r
- end\r
-\r
- % arrange symbols in Nsymb/Nc by Nc matrix\r
-\r
- for i=1:Nc:Nsymb\r
-\r
- % Determine HF channel at each carrier for this symbol\r
-\r
- for k=1:Nc\r
- hf_model(hf_n, k) = hf_gain*(spread(hf_n) + exp(-j*k*wsep*nhfdelay)*spread_2ms(hf_n));\r
- hf_fading(i+k-1) = abs(hf_model(hf_n, k));\r
- if hf_mag_only\r
- s_ch(i+k-1) *= abs(hf_model(hf_n, k));\r
- else\r
- s_ch(i+k-1) *= hf_model(hf_n, k);\r
- end\r
- end\r
- hf_n++;\r
- end\r
- end\r
- \r
- tx_symb_log = [tx_symb_log s_ch];\r
-\r
- % "genie" SNR estimate \r
- \r
- snr = (s_ch*s_ch')/(Nsymb*variance);\r
- sim_out.snr_log = [sim_out.snr_log snr];\r
- sim_out.hf_model_pwr = [sim_out.hf_model_pwr mean(hf_fading.^2)];\r
-\r
- % AWGN noise and phase/freq offset channel simulation\r
- % 0.5 factor ensures var(noise) == variance , i.e. splits power between Re & Im\r
-\r
- noise = sqrt(variance*0.5)*(randn(1,Nsymb) + j*randn(1,Nsymb));\r
- noise_log = [noise_log noise];\r
- \r
- % organise into carriers to apply frequency and phase offset\r
-\r
- for i=1:Nc:Nsymb\r
- for k=1:Nc\r
- s_ch(i+k-1) = s_ch(i+k-1)*exp(j*phase_offset) + noise(i+k-1);\r
- end \r
- phase_offset += w_offset;\r
- end\r
- \r
- % de-modulate\r
-\r
- rx_bits = zeros(1, framesize);\r
- for i=1:Nc:Nsymb\r
- for k=1:Nc\r
- rx_symb = s_ch(i+k-1);\r
- tmp = rx_symb;\r
- rx_symb *= conj(prev_sym_rx(k)/abs(prev_sym_rx(k)));\r
- prev_sym_rx(k) = tmp;\r
- rx_bits((2*(i-1+k-1)+1):(2*(i+k-1))) = qpsk_demod(rx_symb);\r
- rx_symb_log = [rx_symb_log rx_symb];\r
- end\r
- end\r
-\r
- error_positions = xor(rx_bits, tx_bits);\r
- Nerrs = sum(error_positions);\r
- sim_out.Nerrs = [sim_out.Nerrs Nerrs];\r
- Terrs += Nerrs;\r
- Tbits += length(tx_bits);\r
- \r
- sim_out.errors_log = [sim_out.errors_log error_positions];\r
- end\r
-\r
- TERvec(ne) = Terrs;\r
- BERvec(ne) = Terrs/Tbits;\r
-\r
- if verbose \r
- printf("EsNo (dB): %f Terrs: %d BER %f ", EsNodB, Terrs, Terrs/Tbits);\r
- printf("\n");\r
- end\r
- if verbose > 1\r
- printf("Terrs: %d BER %f C %f N %f Es %f No %f Es/No %f\n\n", Terrs,\r
- Terrs/Tbits, var(tx_symb_log), var(noise_log),\r
- var(tx_symb_log), var(noise_log), var(tx_symb_log)/var(noise_log));\r
- end\r
- end\r
- \r
- Ebvec = Esvec - 10*log10(bps);\r
-\r
- sim_out.BERvec = BERvec;\r
- sim_out.Ebvec = Ebvec;\r
- sim_out.TERvec = TERvec;\r
-\r
- if plot_scatter\r
- figure(2);\r
- clf;\r
- scat = rx_symb_log .* exp(j*pi/4);\r
- plot(real(scat), imag(scat),'+');\r
- title('Scatter plot');\r
-\r
- figure(3);\r
- clf; \r
- y = 1:Rs*2;\r
- x = 1:Nc;\r
- EsNodBSurface = 20*log10(abs(hf_model(y,:))) - 10*log10(variance);\r
- mesh(x,y,EsNodBSurface);\r
- grid\r
- title('HF Channel Es/No');\r
-\r
- if 0 \r
- figure(4);\r
- clf;\r
- subplot(211)\r
- plot(y,abs(hf_model(y,1)))\r
- title('HF Channel Carrier 1 Mag');\r
- subplot(212)\r
- plot(y,angle(hf_model(y,1)))\r
- title('HF Channel Carrier 1 Phase');\r
- end\r
- end\r
-\r
-endfunction\r
-\r
-% Gray coded QPSK modulation function\r
-\r
-function symbol = qpsk_mod(two_bits)\r
- two_bits_decimal = sum(two_bits .* [2 1]); \r
- switch(two_bits_decimal)\r
- case (0) symbol = 1;\r
- case (1) symbol = j;\r
- case (2) symbol = -j;\r
- case (3) symbol = -1;\r
- endswitch\r
-endfunction\r
-\r
-% Gray coded QPSK demodulation function\r
-\r
-function two_bits = qpsk_demod(symbol)\r
- if isscalar(symbol) == 0\r
- printf("only works with scalars\n");\r
- return;\r
- end\r
- bit0 = real(symbol*exp(j*pi/4)) < 0;\r
- bit1 = imag(symbol*exp(j*pi/4)) < 0;\r
- two_bits = [bit1 bit0];\r
-endfunction\r
-\r
-function sim_in = standard_init\r
- sim_in.verbose = 1;\r
- sim_in.plot_scatter = 0;\r
-\r
- sim_in.Esvec = 5:15; \r
- sim_in.Ntrials = 100;\r
- sim_in.framesize = 64;\r
- sim_in.Rs = 100;\r
- sim_in.Nc = 8;\r
-\r
- sim_in.phase_offset = 0;\r
- sim_in.w_offset = 0;\r
- sim_in.phase_noise_amp = 0;\r
-\r
- sim_in.hf_delay_ms = 2;\r
- sim_in.hf_sim = 0;\r
- sim_in.hf_phase_only = 0;\r
- sim_in.hf_mag_only = 0;\r
-endfunction\r
-\r
-function awgn_hf_ber_curves()\r
- sim_in = standard_init();\r
-\r
- Ebvec = sim_in.Esvec - 10*log10(2);\r
- BER_theory = 0.5*erfc(sqrt(10.^(Ebvec/10)));\r
-\r
- dpsk_awgn = ber_test(sim_in);\r
- sim_in.hf_sim = 1;\r
- dpsk_hf = ber_test(sim_in);\r
-\r
- figure(1); \r
- clf;\r
- semilogy(Ebvec, BER_theory,'r;QPSK theory;')\r
- hold on;\r
- semilogy(dpsk_awgn.Ebvec, dpsk_awgn.BERvec,'g;DQPSK;')\r
- semilogy(dpsk_hf.Ebvec, dpsk_hf.BERvec,'g;DQPSK HF;')\r
- hold off;\r
- xlabel('Eb/N0')\r
- ylabel('BER')\r
- grid("minor")\r
- axis([min(Ebvec) max(Ebvec) 1E-3 1])\r
-end\r
-\r
-sim_in = standard_init();\r
-\r
-% energy file sampled every 10ms\r
-\r
-load ../src/ve9qrp.txt\r
-pdB=10*log10(ve9qrp);\r
-for i=1:length(pdB)\r
- if pdB(i) < 0\r
- pdB(i) = 0;\r
- end\r
-end\r
-\r
-% Down sample to 40ms rate used for 1300 bit/s codec, every 4th sample is transmitted\r
-\r
-pdB = pdB(4:4:length(pdB));\r
-\r
-% Use linear mapping function in dB domain to map to symbol power\r
-\r
-power_map_x = [ 0 20 24 40 50 ];\r
-power_map_y = [-6 -6 0 6 6];\r
-mapped_pdB = interp1(power_map_x, power_map_y, pdB);\r
-\r
-%sim_in.symbol_amp = 10 .^ (mapped_pdB/20);\r
-sim_in.symbol_amp = ones(1,length(pdB));\r
-sim_in.plot_scatter = 1;\r
-sim_in.verbose = 2;\r
-sim_in.hf_sim = 1;\r
-sim_in.Esvec = 10;\r
-sim_in.Ntrials = 400;\r
-\r
-dqpsk_pwr_hf = ber_test(sim_in);\r
-\r
-% note: need way to test that power is aligned with speech\r
-\r
-figure(4)\r
-clf;\r
-plot((1:sim_in.Ntrials)*80*4, pdB(1:sim_in.Ntrials));\r
-hold on;\r
-plot((1:sim_in.Ntrials)*80*4, mapped_pdB(1:sim_in.Ntrials),'r');\r
-hold off;\r
-\r
-figure(5)\r
-clf;\r
-\r
-s = load_raw("../raw/ve9qrp.raw");\r
-M=320; M_on_2 = M/2; % processing delay between input speech and centre of analysis window\r
-plot(M_on_2:(M_on_2-1+sim_in.Ntrials*M),s(1:sim_in.Ntrials*M))\r
-hold on;\r
-plot((1:sim_in.Ntrials)*M, 5000*sim_in.symbol_amp(1:sim_in.Ntrials),'r');\r
-hold off;\r
-axis([1 sim_in.Ntrials*M -3E4 3E4]);\r
-\r
-figure(6)\r
-clf;\r
-plot((1:sim_in.Ntrials)*M, 20*log10(sim_in.symbol_amp(1:sim_in.Ntrials)),'b;Es (dB);');\r
-hold on;\r
-plot((1:sim_in.Ntrials)*M, 10*log10(dqpsk_pwr_hf.hf_model_pwr),'g;Fading (dB);');\r
-plot((1:sim_in.Ntrials)*M, 10*log10(dqpsk_pwr_hf.snr_log),'r;Es/No (dB);');\r
-\r
-ber = dqpsk_pwr_hf.Nerrs/sim_in.framesize;\r
-ber_clip = ber;\r
-ber_clip(find(ber > 0.2)) = 0.2;\r
-plot((1:sim_in.Ntrials)*M, -20+100*ber_clip,'k;BER (0-20%);');\r
-hold off;\r
-axis([1 sim_in.Ntrials*M -20 20])\r
-\r
-fep=fopen("dqpsk_errors_pwr.bin","wb"); fwrite(fep, dqpsk_pwr_hf.errors_log, "short"); fclose(fep);\r
-fber=fopen("ber.bin","wb"); fwrite(fber, ber, "float"); fclose(fber);\r
+% test_dqpsk.m
+% David Rowe March 2014
+%
+% Single sample/symbol DQPSK modem simulation to test modulating modem
+% tx power based on speech energy.
+
+1;
+
+% main test function
+
+function sim_out = ber_test(sim_in)
+ Fs = 8000;
+
+ verbose = sim_in.verbose;
+ framesize = sim_in.framesize;
+ Ntrials = sim_in.Ntrials;
+ Esvec = sim_in.Esvec;
+ phase_offset = sim_in.phase_offset;
+ w_offset = sim_in.w_offset;
+ plot_scatter = sim_in.plot_scatter;
+ Rs = sim_in.Rs;
+ hf_sim = sim_in.hf_sim;
+ nhfdelay = sim_in.hf_delay_ms*Rs/1000;
+ hf_phase_only = sim_in.hf_phase_only;
+ hf_mag_only = sim_in.hf_mag_only;
+ Nc = sim_in.Nc;
+ symbol_amp = sim_in.symbol_amp;
+
+ bps = 2;
+ Nsymb = framesize/bps;
+ for k=1:Nc
+ prev_sym_tx(k) = qpsk_mod([0 0]);
+ prev_sym_rx(k) = qpsk_mod([0 0]);
+ end
+
+ rate = 1;
+
+ % Init HF channel model from stored sample files of spreading signal ----------------------------------
+
+ % convert "spreading" samples from 1kHz carrier at Fs to complex
+ % baseband, generated by passing a 1kHz sine wave through PathSim
+ % with the ccir-poor model, enabling one path at a time.
+
+ Fc = 1000; M = Fs/Rs;
+ fspread = fopen("../raw/sine1k_2Hz_spread.raw","rb");
+ spread1k = fread(fspread, "int16")/10000;
+ fclose(fspread);
+ fspread = fopen("../raw/sine1k_2ms_delay_2Hz_spread.raw","rb");
+ spread1k_2ms = fread(fspread, "int16")/10000;
+ fclose(fspread);
+
+ % down convert to complex baseband
+ spreadbb = spread1k.*exp(-j*(2*pi*Fc/Fs)*(1:length(spread1k))');
+ spreadbb_2ms = spread1k_2ms.*exp(-j*(2*pi*Fc/Fs)*(1:length(spread1k_2ms))');
+
+ % remove -2000 Hz image
+ b = fir1(50, 5/Fs);
+ spread = filter(b,1,spreadbb);
+ spread_2ms = filter(b,1,spreadbb_2ms);
+
+ % discard first 1000 samples as these were near 0, probably as
+ % PathSim states were ramping up
+
+ spread = spread(1000:length(spread));
+ spread_2ms = spread_2ms(1000:length(spread_2ms));
+
+ % decimate down to Rs
+
+ spread = spread(1:M:length(spread));
+ spread_2ms = spread_2ms(1:M:length(spread_2ms));
+
+ % Determine "gain" of HF channel model, so we can normalise
+ % carrier power during HF channel sim to calibrate SNR. I imagine
+ % different implementations of ccir-poor would do this in
+ % different ways, leading to different BER results. Oh Well!
+
+ hf_gain = 1.0/sqrt(var(spread)+var(spread_2ms));
+
+ % Start Simulation ----------------------------------------------------------------
+
+ for ne = 1:length(Esvec)
+ EsNodB = Esvec(ne);
+ EsNo = 10^(EsNodB/10);
+
+ variance = 1/EsNo;
+ if verbose > 1
+ printf("EsNo (dB): %f EsNo: %f variance: %f\n", EsNodB, EsNo, variance);
+ end
+
+ Terrs = 0; Tbits = 0;
+
+ tx_symb_log = [];
+ rx_symb_log = [];
+ noise_log = [];
+ sim_out.errors_log = [];
+
+ % init HF channel
+
+ hf_n = 1;
+ hf_angle_log = [];
+ hf_fading = ones(1,Nsymb); % default input for ldpc dec
+ hf_model = ones(Ntrials*Nsymb/Nc, Nc); % defaults for plotting surface
+
+ sim_out.errors_log = [];
+ sim_out.Nerrs = [];
+ sim_out.snr_log = [];
+ sim_out.hf_model_pwr = [];
+
+ symbol_amp_index = 1;
+
+ for nn = 1: Ntrials
+
+ tx_bits = round( rand( 1, framesize*rate ) );
+
+ % modulate --------------------------------------------
+
+ s = zeros(1, Nsymb);
+ for i=1:Nc:Nsymb
+ for k=1:Nc
+ tx_symb = qpsk_mod(tx_bits(2*(i-1+k-1)+1:2*(i+k-1)));
+ tx_symb *= prev_sym_tx(k);
+ prev_sym_tx(k) = tx_symb;
+ s(i+k-1) = symbol_amp(symbol_amp_index)*tx_symb;
+ end
+ end
+ s_ch = s;
+ symbol_amp_index++;
+
+ % HF channel simulation ------------------------------------
+
+ if hf_sim
+
+ % separation between carriers. Note this is
+ % effectively under samples at Rs, I dont think this
+ % matters. Equivalent to doing freq shift at Fs, then
+ % decimating to Rs.
+
+ wsep = 2*pi*(1+0.5); % e.g. 75Hz spacing at Rs=50Hz, alpha=0.5 filters
+
+ if Nsymb/Nc != floor(Nsymb/Nc)
+ printf("Error: Nsymb/Nc must be an integrer\n")
+ return;
+ end
+
+ % arrange symbols in Nsymb/Nc by Nc matrix
+
+ for i=1:Nc:Nsymb
+
+ % Determine HF channel at each carrier for this symbol
+
+ for k=1:Nc
+ hf_model(hf_n, k) = hf_gain*(spread(hf_n) + exp(-j*k*wsep*nhfdelay)*spread_2ms(hf_n));
+ hf_fading(i+k-1) = abs(hf_model(hf_n, k));
+ if hf_mag_only
+ s_ch(i+k-1) *= abs(hf_model(hf_n, k));
+ else
+ s_ch(i+k-1) *= hf_model(hf_n, k);
+ end
+ end
+ hf_n++;
+ end
+ end
+
+ tx_symb_log = [tx_symb_log s_ch];
+
+ % "genie" SNR estimate
+
+ snr = (s_ch*s_ch')/(Nsymb*variance);
+ sim_out.snr_log = [sim_out.snr_log snr];
+ sim_out.hf_model_pwr = [sim_out.hf_model_pwr mean(hf_fading.^2)];
+
+ % AWGN noise and phase/freq offset channel simulation
+ % 0.5 factor ensures var(noise) == variance , i.e. splits power between Re & Im
+
+ noise = sqrt(variance*0.5)*(randn(1,Nsymb) + j*randn(1,Nsymb));
+ noise_log = [noise_log noise];
+
+ % organise into carriers to apply frequency and phase offset
+
+ for i=1:Nc:Nsymb
+ for k=1:Nc
+ s_ch(i+k-1) = s_ch(i+k-1)*exp(j*phase_offset) + noise(i+k-1);
+ end
+ phase_offset += w_offset;
+ end
+
+ % de-modulate
+
+ rx_bits = zeros(1, framesize);
+ for i=1:Nc:Nsymb
+ for k=1:Nc
+ rx_symb = s_ch(i+k-1);
+ tmp = rx_symb;
+ rx_symb *= conj(prev_sym_rx(k)/abs(prev_sym_rx(k)));
+ prev_sym_rx(k) = tmp;
+ rx_bits((2*(i-1+k-1)+1):(2*(i+k-1))) = qpsk_demod(rx_symb);
+ rx_symb_log = [rx_symb_log rx_symb];
+ end
+ end
+
+ error_positions = xor(rx_bits, tx_bits);
+ Nerrs = sum(error_positions);
+ sim_out.Nerrs = [sim_out.Nerrs Nerrs];
+ Terrs += Nerrs;
+ Tbits += length(tx_bits);
+
+ sim_out.errors_log = [sim_out.errors_log error_positions];
+ end
+
+ TERvec(ne) = Terrs;
+ BERvec(ne) = Terrs/Tbits;
+
+ if verbose
+ printf("EsNo (dB): %f Terrs: %d BER %f ", EsNodB, Terrs, Terrs/Tbits);
+ printf("\n");
+ end
+ if verbose > 1
+ printf("Terrs: %d BER %f C %f N %f Es %f No %f Es/No %f\n\n", Terrs,
+ Terrs/Tbits, var(tx_symb_log), var(noise_log),
+ var(tx_symb_log), var(noise_log), var(tx_symb_log)/var(noise_log));
+ end
+ end
+
+ Ebvec = Esvec - 10*log10(bps);
+
+ sim_out.BERvec = BERvec;
+ sim_out.Ebvec = Ebvec;
+ sim_out.TERvec = TERvec;
+
+ if plot_scatter
+ figure(2);
+ clf;
+ scat = rx_symb_log .* exp(j*pi/4);
+ plot(real(scat), imag(scat),'+');
+ title('Scatter plot');
+
+ figure(3);
+ clf;
+ y = 1:Rs*2;
+ x = 1:Nc;
+ EsNodBSurface = 20*log10(abs(hf_model(y,:))) - 10*log10(variance);
+ mesh(x,y,EsNodBSurface);
+ grid
+ title('HF Channel Es/No');
+
+ if 0
+ figure(4);
+ clf;
+ subplot(211)
+ plot(y,abs(hf_model(y,1)))
+ title('HF Channel Carrier 1 Mag');
+ subplot(212)
+ plot(y,angle(hf_model(y,1)))
+ title('HF Channel Carrier 1 Phase');
+ end
+ end
+
+endfunction
+
+% Gray coded QPSK modulation function
+
+function symbol = qpsk_mod(two_bits)
+ two_bits_decimal = sum(two_bits .* [2 1]);
+ switch(two_bits_decimal)
+ case (0) symbol = 1;
+ case (1) symbol = j;
+ case (2) symbol = -j;
+ case (3) symbol = -1;
+ endswitch
+endfunction
+
+% Gray coded QPSK demodulation function
+
+function two_bits = qpsk_demod(symbol)
+ if isscalar(symbol) == 0
+ printf("only works with scalars\n");
+ return;
+ end
+ bit0 = real(symbol*exp(j*pi/4)) < 0;
+ bit1 = imag(symbol*exp(j*pi/4)) < 0;
+ two_bits = [bit1 bit0];
+endfunction
+
+function sim_in = standard_init
+ sim_in.verbose = 1;
+ sim_in.plot_scatter = 0;
+
+ sim_in.Esvec = 5:15;
+ sim_in.Ntrials = 100;
+ sim_in.framesize = 64;
+ sim_in.Rs = 100;
+ sim_in.Nc = 8;
+
+ sim_in.phase_offset = 0;
+ sim_in.w_offset = 0;
+ sim_in.phase_noise_amp = 0;
+
+ sim_in.hf_delay_ms = 2;
+ sim_in.hf_sim = 0;
+ sim_in.hf_phase_only = 0;
+ sim_in.hf_mag_only = 0;
+endfunction
+
+function awgn_hf_ber_curves()
+ sim_in = standard_init();
+
+ Ebvec = sim_in.Esvec - 10*log10(2);
+ BER_theory = 0.5*erfc(sqrt(10.^(Ebvec/10)));
+
+ dpsk_awgn = ber_test(sim_in);
+ sim_in.hf_sim = 1;
+ dpsk_hf = ber_test(sim_in);
+
+ figure(1);
+ clf;
+ semilogy(Ebvec, BER_theory,'r;QPSK theory;')
+ hold on;
+ semilogy(dpsk_awgn.Ebvec, dpsk_awgn.BERvec,'g;DQPSK;')
+ semilogy(dpsk_hf.Ebvec, dpsk_hf.BERvec,'g;DQPSK HF;')
+ hold off;
+ xlabel('Eb/N0')
+ ylabel('BER')
+ grid("minor")
+ axis([min(Ebvec) max(Ebvec) 1E-3 1])
+end
+
+sim_in = standard_init();
+
+% energy file sampled every 10ms
+
+load ../src/ve9qrp.txt
+pdB=10*log10(ve9qrp);
+for i=1:length(pdB)
+ if pdB(i) < 0
+ pdB(i) = 0;
+ end
+end
+
+% Down sample to 40ms rate used for 1300 bit/s codec, every 4th sample is transmitted
+
+pdB = pdB(4:4:length(pdB));
+
+% Use linear mapping function in dB domain to map to symbol power
+
+power_map_x = [ 0 20 24 40 50 ];
+power_map_y = [-6 -6 0 6 6];
+mapped_pdB = interp1(power_map_x, power_map_y, pdB);
+
+%sim_in.symbol_amp = 10 .^ (mapped_pdB/20);
+sim_in.symbol_amp = ones(1,length(pdB));
+sim_in.plot_scatter = 1;
+sim_in.verbose = 2;
+sim_in.hf_sim = 1;
+sim_in.Esvec = 10;
+sim_in.Ntrials = 400;
+
+dqpsk_pwr_hf = ber_test(sim_in);
+
+% note: need way to test that power is aligned with speech
+
+figure(4)
+clf;
+plot((1:sim_in.Ntrials)*80*4, pdB(1:sim_in.Ntrials));
+hold on;
+plot((1:sim_in.Ntrials)*80*4, mapped_pdB(1:sim_in.Ntrials),'r');
+hold off;
+
+figure(5)
+clf;
+
+s = load_raw("../raw/ve9qrp.raw");
+M=320; M_on_2 = M/2; % processing delay between input speech and centre of analysis window
+plot(M_on_2:(M_on_2-1+sim_in.Ntrials*M),s(1:sim_in.Ntrials*M))
+hold on;
+plot((1:sim_in.Ntrials)*M, 5000*sim_in.symbol_amp(1:sim_in.Ntrials),'r');
+hold off;
+axis([1 sim_in.Ntrials*M -3E4 3E4]);
+
+figure(6)
+clf;
+plot((1:sim_in.Ntrials)*M, 20*log10(sim_in.symbol_amp(1:sim_in.Ntrials)),'b;Es (dB);');
+hold on;
+plot((1:sim_in.Ntrials)*M, 10*log10(dqpsk_pwr_hf.hf_model_pwr),'g;Fading (dB);');
+plot((1:sim_in.Ntrials)*M, 10*log10(dqpsk_pwr_hf.snr_log),'r;Es/No (dB);');
+
+ber = dqpsk_pwr_hf.Nerrs/sim_in.framesize;
+ber_clip = ber;
+ber_clip(find(ber > 0.2)) = 0.2;
+plot((1:sim_in.Ntrials)*M, -20+100*ber_clip,'k;BER (0-20%);');
+hold off;
+axis([1 sim_in.Ntrials*M -20 20])
+
+fep=fopen("dqpsk_errors_pwr.bin","wb"); fwrite(fep, dqpsk_pwr_hf.errors_log, "short"); fclose(fep);
+fber=fopen("ber.bin","wb"); fwrite(fber, ber, "float"); fclose(fber);
-% test_dqpsk2.m\r
-% David Rowe April 2014\r
-%\r
-% DQPSK modem simulation inclduing filtering to test modulating modem\r
-% tx power based on speech energy. Unlike test_dpsk runs at sample\r
-% rate Fs.\r
-\r
-1;\r
-\r
-% main test function \r
-\r
-function sim_out = ber_test(sim_in)\r
- Fs = 8000;\r
-\r
- verbose = sim_in.verbose;\r
- framesize = sim_in.framesize;\r
- Ntrials = sim_in.Ntrials;\r
- Esvec = sim_in.Esvec;\r
- phase_offset = sim_in.phase_offset;\r
- w_offset = sim_in.w_offset;\r
- plot_scatter = sim_in.plot_scatter;\r
- Rs = sim_in.Rs;\r
- hf_sim = sim_in.hf_sim;\r
- Nhfdelay = floor(sim_in.hf_delay_ms*Fs/1000);\r
- Nc = sim_in.Nc;\r
- symbol_amp = sim_in.symbol_amp;\r
-\r
- bps = 2;\r
- Nsymb = framesize/bps;\r
- for k=1:Nc\r
- prev_sym_tx(k) = qpsk_mod([0 0]);\r
- prev_sym_rx(k) = qpsk_mod([0 0]);\r
- end\r
-\r
- % design root nyquist (root raised cosine) filter and init tx and rx filter states\r
-\r
- alpha = 0.5; T=1/Fs; Nfiltsym=7; M=Fs/Rs;\r
- if floor(Fs/Rs) != Fs/Rs\r
- printf("oversampling ratio must be an integer\n");\r
- return;\r
- end\r
- hrn = gen_rn_coeffs(alpha, T, Rs, Nfiltsym, M);\r
- Nfilter = length(hrn);\r
-\r
- % convert "spreading" samples from 1kHz carrier at Fs to complex\r
- % baseband, generated by passing a 1kHz sine wave through PathSim\r
- % with the ccir-poor model, enabling one path at a time.\r
- \r
- Fc = 1000;\r
- fspread = fopen("../raw/sine1k_2Hz_spread.raw","rb");\r
- spread1k = fread(fspread, "int16")/10000;\r
- fclose(fspread);\r
- fspread = fopen("../raw/sine1k_2ms_delay_2Hz_spread.raw","rb");\r
- spread1k_2ms = fread(fspread, "int16")/10000;\r
- fclose(fspread);\r
-\r
- % down convert to complex baseband\r
- spreadbb = spread1k.*exp(-j*(2*pi*Fc/Fs)*(1:length(spread1k))');\r
- spreadbb_2ms = spread1k_2ms.*exp(-j*(2*pi*Fc/Fs)*(1:length(spread1k_2ms))');\r
-\r
- % remove -2000 Hz image\r
- b = fir1(50, 5/Fs);\r
- spread = filter(b,1,spreadbb);\r
- spread_2ms = filter(b,1,spreadbb_2ms);\r
-\r
- % discard first 1000 samples as these were near 0, probably as\r
- % PathSim states were ramping up. Transpose for convenience\r
-\r
- spread = transpose(spread(1000:length(spread)));\r
- spread_2ms = transpose(spread_2ms(1000:length(spread_2ms)));\r
-\r
- % Determine "gain" of HF channel model, so we can normalise\r
- % carrier power during HF channel sim to calibrate SNR. I imagine\r
- % different implementations of ccir-poor would do this in\r
- % different ways, leading to different BER results. Oh Well!\r
-\r
- hf_gain = 1.0/sqrt(var(spread)+var(spread_2ms));\r
- \r
- % Start Simulation ----------------------------------------------------------------\r
-\r
- for ne = 1:length(Esvec)\r
- EsNodB = Esvec(ne);\r
- EsNo = 10^(EsNodB/10);\r
- \r
- variance = Fs/(Rs*EsNo);\r
- if verbose > 1\r
- printf("EsNo (dB): %f EsNo: %f variance: %f\n", EsNodB, EsNo, variance);\r
- end\r
- \r
- Terrs = 0; Tbits = 0;\r
-\r
- tx_symb_log = [];\r
- rx_symb_log = [];\r
- noise_log = [];\r
- sim_out.errors_log = [];\r
- sim_out.tx_baseband_log = [];\r
- sim_out.rx_filt_log = [];\r
- symbol_amp_index = 1;\r
- \r
- % init filter memories and LOs\r
-\r
- tx_filter_memory = zeros(Nc, Nfilter);\r
- rx_filter_memory = zeros(Nc, Nfilter);\r
- s_delay_line_filt = zeros(Nc, Nfiltsym);\r
- phase_tx = ones(1,Nc);\r
- phase_rx = ones(1,Nc);\r
- Fcentre = 1500; Fsep = (1+alpha)*Rs;\r
- freq = Fcentre + Fsep*((-Nc/2+0.5):(Nc/2-0.5));\r
- freq = exp(j*freq*2*pi/Fs);\r
-\r
- % init HF channel\r
-\r
- sc = 1; hf_n = 1;\r
- hf_sim_delay_line = zeros(1,M+Nhfdelay);\r
- freq_sample_hz = Fcentre + ((Fsep*(-Nc/2)):50:(Fsep*(Nc/2)));\r
- freq_sample_rads = (2*pi/Fs)*freq_sample_hz;\r
- hf_model = ones(Ntrials*Nsymb/Nc, length(freq_sample_rads)); % defaults for plotting surface\r
-\r
- % bunch of outputs we log for graphing\r
-\r
- sim_out.errors_log = [];\r
- sim_out.Nerrs = [];\r
- sim_out.snr_log = [];\r
- sim_out.hf_model_pwr = [];\r
- sim_out.tx_fdm_log = [];\r
- C_log = [];\r
-\r
- for nn = 1: Ntrials\r
- \r
- tx_bits = round( rand( 1, framesize ) );\r
- \r
- % modulate --------------------------------------------\r
-\r
- s = zeros(1, Nsymb);\r
- for i=1:Nc:Nsymb\r
- for k=1:Nc\r
- tx_symb = qpsk_mod(tx_bits(2*(i-1+k-1)+1:2*(i+k-1)));\r
- s_qpsk(i+k-1) = tx_symb;\r
- tx_symb *= prev_sym_tx(k);\r
- prev_sym_tx(k) = tx_symb;\r
- s(i+k-1) = symbol_amp(symbol_amp_index)*tx_symb;\r
- end\r
- end\r
- symbol_amp_index++;\r
- s_ch = s;\r
-\r
- % Now we start processing frame Nc symbols at a time to model parallel carriers\r
-\r
- tx_fdm_sym_log = [];\r
- for i=1:Nc:Nsymb\r
-\r
- % Delay tx symbols to match delay due to filters. qpsk\r
- % (rather than dqpsk) symbols used for convenience as\r
- % it's easy to shift symbols than pairs of bits\r
-\r
- s_delay_line_filt(:,1:Nfiltsym-1) = s_delay_line_filt(:,2:Nfiltsym);\r
- s_delay_line_filt(:,Nfiltsym) = s_qpsk(i:i+Nc-1);\r
- s_qpsk(i:i+Nc-1) = s_delay_line_filt(:,1); \r
- for k=1:Nc\r
- tx_bits(2*(i-1+k-1)+1:2*(i+k-1)) = qpsk_demod(s_qpsk(i+k-1));\r
- end\r
-\r
- % tx filter\r
-\r
- tx_baseband = zeros(Nc,M);\r
-\r
- % tx filter each symbol, generate M filtered output samples for each symbol.\r
- % Efficient polyphase filter techniques used as tx_filter_memory is sparse\r
-\r
- tx_filter_memory(:,Nfilter) = s(i:i+Nc-1);\r
-\r
- for k=1:M\r
- tx_baseband(:,k) = M*tx_filter_memory(:,M:M:Nfilter) * hrn(M-k+1:M:Nfilter)';\r
- end\r
- tx_filter_memory(:,1:Nfilter-M) = tx_filter_memory(:,M+1:Nfilter);\r
- tx_filter_memory(:,Nfilter-M+1:Nfilter) = zeros(Nc,M);\r
-\r
- sim_out.tx_baseband_log = [sim_out.tx_baseband_log tx_baseband];\r
-\r
- % upconvert\r
- \r
- tx_fdm = zeros(1,M);\r
-\r
- for c=1:Nc\r
- for k=1:M\r
- phase_tx(c) = phase_tx(c) * freq(c);\r
- tx_fdm(k) = tx_fdm(k) + tx_baseband(c,k)*phase_tx(c);\r
- end\r
- end\r
- \r
- sim_out.tx_fdm_log = [sim_out.tx_fdm_log tx_fdm];\r
- \r
- % HF channel\r
- \r
- if hf_sim\r
- hf_sim_delay_line(1:Nhfdelay) = hf_sim_delay_line(M+1:M+Nhfdelay);\r
- hf_sim_delay_line(Nhfdelay+1:M+Nhfdelay) = tx_fdm;\r
-\r
- tx_fdm = tx_fdm.*spread(sc:sc+M-1) + hf_sim_delay_line(1:M).*spread_2ms(sc:sc+M-1);\r
- tx_fdm *= hf_gain;\r
-\r
- % sample HF channel spectrum in middle of this symbol for plotting\r
-\r
- hf_model(hf_n,:) = hf_gain*(spread(sc+M/2) + exp(-j*freq_sample_rads*Nhfdelay)*spread_2ms(sc+M/2));\r
-\r
- sc += M;\r
- hf_n++;\r
- end\r
-\r
- tx_fdm_sym_log = [tx_fdm_sym_log tx_fdm ];\r
-\r
- % AWGN noise and phase/freq offset channel simulation\r
- % 0.5 factor ensures var(noise) == variance , i.e. splits power between Re & Im\r
-\r
- noise = sqrt(variance*0.5)*(randn(1,M) + j*randn(1,M));\r
- noise_log = [noise_log noise];\r
-\r
- % apply frequency and phase offset and noise\r
-\r
- for k=1:M\r
- rx_fdm(k) = tx_fdm(k)*exp(j*phase_offset) + noise(k);\r
- phase_offset += w_offset;\r
- end\r
-\r
- % downconvert\r
-\r
- rx_baseband = zeros(Nc,M);\r
- for c=1:Nc\r
- for k=1:M\r
- phase_rx(c) = phase_rx(c) * freq(c);\r
- rx_baseband(c,k) = rx_fdm(k)*phase_rx(c)';\r
- end\r
- end\r
-\r
- % rx filter\r
-\r
- rx_filter_memory(:,Nfilter-M+1:Nfilter) = rx_baseband;\r
- rx_filt = rx_filter_memory * hrn';\r
- rx_filter_memory(:,1:Nfilter-M) = rx_filter_memory(:,1+M:Nfilter);\r
- sim_out.rx_filt_log = [sim_out.rx_filt_log rx_filt];\r
-\r
- s_ch(i:i+Nc-1) = rx_filt;\r
- end\r
-\r
- % est HF model power for entire code frame (which could be several symbols)\r
-\r
- if hf_sim\r
- frame_hf_model = reshape(hf_model(hf_n-Nsymb/Nc:hf_n-1,:),1,(Nsymb/Nc)*length(freq_sample_hz)); \r
- sim_out.hf_model_pwr = [sim_out.hf_model_pwr mean(abs(frame_hf_model).^2)];\r
- else \r
- sim_out.hf_model_pwr = [sim_out.hf_model_pwr 1];\r
- end\r
-\r
- % "genie" SNR estimate \r
- \r
- snr = (tx_fdm_sym_log*tx_fdm_sym_log')/(M*variance);\r
- sim_out.snr_log = [sim_out.snr_log snr];\r
- \r
- % de-modulate\r
-\r
- rx_bits = zeros(1, framesize);\r
- for i=1:Nc:Nsymb\r
- for k=1:Nc\r
- rx_symb = s_ch(i+k-1);\r
- tmp = rx_symb;\r
- rx_symb *= conj(prev_sym_rx(k)/abs(prev_sym_rx(k)));\r
- prev_sym_rx(k) = tmp;\r
- rx_bits((2*(i-1+k-1)+1):(2*(i+k-1))) = qpsk_demod(rx_symb);\r
- rx_symb_log = [rx_symb_log rx_symb];\r
- end\r
- end\r
-\r
- % ignore data until we have enough frames to fill filter memory\r
- % then count errors\r
-\r
- if nn > ceil(Nfiltsym/(Nsymb/Nc))\r
- error_positions = xor(rx_bits, tx_bits);\r
- sim_out.errors_log = [sim_out.errors_log error_positions];\r
- Nerrs = sum(error_positions);\r
- sim_out.Nerrs = [sim_out.Nerrs Nerrs];\r
- Terrs += Nerrs;\r
- Tbits += length(tx_bits);\r
- end\r
-\r
- end\r
-\r
- TERvec(ne) = Terrs;\r
- BERvec(ne) = Terrs/Tbits;\r
-\r
- if verbose \r
- printf("EsNo (dB): %f Terrs: %d BER %f ", EsNodB, Terrs, Terrs/Tbits);\r
- printf("\n");\r
- end\r
- if verbose > 1\r
- printf("Terrs: %d BER %f C %f N %f Es %f No %f Es/No %f\n\n", Terrs,\r
- Terrs/Tbits, var(sim_out.tx_fdm_log), var(noise_log),\r
- var(sim_out.tx_fdm_log)/(Nc*Rs), var(noise_log)/Fs, (var(sim_out.tx_fdm_log)/(Nc*Rs))/(var(noise_log)/Fs));\r
- end\r
- end\r
- \r
- Ebvec = Esvec - 10*log10(bps);\r
-\r
- sim_out.BERvec = BERvec;\r
- sim_out.Ebvec = Ebvec;\r
- sim_out.TERvec = TERvec;\r
-\r
- if plot_scatter\r
- figure(2);\r
- clf;\r
- scat = rx_symb_log(Nfiltsym*Nc:length(rx_symb_log)) .* exp(j*pi/4);\r
- plot(real(scat), imag(scat),'+');\r
- title('Scatter plot');\r
-\r
- figure(3);\r
- clf; \r
- y = 1:Rs*2;\r
- EsNodBSurface = 20*log10(abs(hf_model(y,:))) + EsNodB;\r
- mesh(1:length(freq_sample_hz),y,EsNodBSurface);\r
- grid\r
- title('HF Channel Es/No');\r
- end\r
-\r
-endfunction\r
-\r
-% Gray coded QPSK modulation function\r
-\r
-function symbol = qpsk_mod(two_bits)\r
- two_bits_decimal = sum(two_bits .* [2 1]); \r
- switch(two_bits_decimal)\r
- case (0) symbol = 1;\r
- case (1) symbol = j;\r
- case (2) symbol = -j;\r
- case (3) symbol = -1;\r
- endswitch\r
-endfunction\r
-\r
-% Gray coded QPSK demodulation function\r
-\r
-function two_bits = qpsk_demod(symbol)\r
- if isscalar(symbol) == 0\r
- printf("only works with scalars\n");\r
- return;\r
- end\r
- bit0 = real(symbol*exp(j*pi/4)) < 0;\r
- bit1 = imag(symbol*exp(j*pi/4)) < 0;\r
- two_bits = [bit1 bit0];\r
-endfunction\r
-\r
-function sim_in = standard_init\r
- sim_in.verbose = 1;\r
- sim_in.plot_scatter = 0;\r
-\r
- sim_in.Esvec = 5:15; \r
- sim_in.Ntrials = 100;\r
- sim_in.framesize = 64;\r
- sim_in.Rs = 100;\r
- sim_in.Nc = 8;\r
-\r
- sim_in.phase_offset = 0;\r
- sim_in.w_offset = 0;\r
- sim_in.phase_noise_amp = 0;\r
-\r
- sim_in.hf_delay_ms = 2;\r
- sim_in.hf_sim = 0;\r
- sim_in.hf_phase_only = 0;\r
- sim_in.hf_mag_only = 0;\r
-endfunction\r
-\r
-function awgn_hf_ber_curves()\r
- sim_in = standard_init();\r
-\r
- Ebvec = sim_in.Esvec - 10*log10(2);\r
- BER_theory = 0.5*erfc(sqrt(10.^(Ebvec/10)));\r
-\r
- dpsk_awgn = ber_test(sim_in);\r
- sim_in.hf_sim = 1;\r
- dpsk_hf = ber_test(sim_in);\r
-\r
- figure(1); \r
- clf;\r
- semilogy(Ebvec, BER_theory,'r;QPSK theory;')\r
- hold on;\r
- semilogy(dpsk_awgn.Ebvec, dpsk_awgn.BERvec,'g;DQPSK;')\r
- semilogy(dpsk_hf.Ebvec, dpsk_hf.BERvec,'g;DQPSK HF;')\r
- hold off;\r
- xlabel('Eb/N0')\r
- ylabel('BER')\r
- grid("minor")\r
- axis([min(Ebvec) max(Ebvec) 1E-3 1])\r
-end\r
-\r
-sim_in = standard_init();\r
-\r
-% energy file sampled every 10ms\r
-\r
-load ../src/ve9qrp.txt\r
-pdB=10*log10(ve9qrp);\r
-for i=1:length(pdB)\r
- if pdB(i) < 0\r
- pdB(i) = 0;\r
- end\r
-end\r
-\r
-% Down sample to 40ms rate used for 1300 bit/s codec, every 4th sample is transmitted\r
-\r
-pdB = pdB(4:4:length(pdB));\r
-\r
-% Use linear mapping function in dB domain to map to symbol power\r
-\r
-%power_map_x = [ 0 20 24 40 50 ];\r
-%power_map_y = [--6 -6 0 6 6];\r
-power_map_x = [ 0 50 ];\r
-power_map_y = [ -15 12];\r
-mapped_pdB = interp1(power_map_x, power_map_y, pdB);\r
-\r
-sim_in.symbol_amp = 10 .^ (mapped_pdB/20);\r
-%sim_in.symbol_amp = ones(1,length(pdB));\r
-sim_in.plot_scatter = 1;\r
-sim_in.verbose = 2;\r
-sim_in.hf_delay_ms = 2;\r
-sim_in.hf_sim = 1;\r
-sim_in.Esvec = 10;\r
-sim_in.Ntrials = 400;\r
-\r
-dqpsk_pwr_hf = ber_test(sim_in);\r
-\r
-% note: need way to test that power is aligned with speech\r
-\r
-figure(4)\r
-clf;\r
-plot((1:sim_in.Ntrials)*80*4, pdB(1:sim_in.Ntrials));\r
-hold on;\r
-plot((1:sim_in.Ntrials)*80*4, mapped_pdB(1:sim_in.Ntrials),'r');\r
-hold off;\r
-\r
-figure(5)\r
-clf;\r
-s = load_raw("../raw/ve9qrp.raw");\r
-M=320; M_on_2 = M/2; % processing delay between input speech and centre of analysis window\r
-subplot(211)\r
-plot(M_on_2:(M_on_2-1+sim_in.Ntrials*M),s(1:sim_in.Ntrials*M))\r
-hold on;\r
-plot((1:sim_in.Ntrials)*M, 5000*sim_in.symbol_amp(1:sim_in.Ntrials),'r');\r
-hold off;\r
-axis([1 sim_in.Ntrials*M -3E4 3E4]);\r
-subplot(212)\r
-plot(real(dqpsk_pwr_hf.tx_fdm_log));\r
-\r
-\r
-figure(6)\r
-clf;\r
-plot((1:sim_in.Ntrials)*M, 20*log10(sim_in.symbol_amp(1:sim_in.Ntrials)),'b;Es (dB);');\r
-hold on;\r
-plot((1:sim_in.Ntrials)*M, 10*log10(dqpsk_pwr_hf.hf_model_pwr),'g;Fading (dB);');\r
-plot((1:sim_in.Ntrials)*M, 10*log10(dqpsk_pwr_hf.snr_log),'r;Es/No (dB);');\r
-\r
-ber = dqpsk_pwr_hf.Nerrs/sim_in.framesize;\r
-ber_clip = ber;\r
-ber_clip(find(ber > 0.2)) = 0.2;\r
-plot((1:length(ber_clip))*M, -20+100*ber_clip,'k;BER (0-20%);');\r
-hold off;\r
-axis([1 sim_in.Ntrials*M -20 20])\r
-\r
-fep=fopen("dqpsk_errors_pwr.bin","wb"); fwrite(fep, dqpsk_pwr_hf.errors_log, "short"); fclose(fep);\r
-fber=fopen("ber.bin","wb"); fwrite(fber, ber, "float"); fclose(fber);\r
+% test_dqpsk2.m
+% David Rowe April 2014
+%
+% DQPSK modem simulation inclduing filtering to test modulating modem
+% tx power based on speech energy. Unlike test_dpsk runs at sample
+% rate Fs.
+
+1;
+
+% main test function
+
+function sim_out = ber_test(sim_in)
+ Fs = 8000;
+
+ verbose = sim_in.verbose;
+ framesize = sim_in.framesize;
+ Ntrials = sim_in.Ntrials;
+ Esvec = sim_in.Esvec;
+ phase_offset = sim_in.phase_offset;
+ w_offset = sim_in.w_offset;
+ plot_scatter = sim_in.plot_scatter;
+ Rs = sim_in.Rs;
+ hf_sim = sim_in.hf_sim;
+ Nhfdelay = floor(sim_in.hf_delay_ms*Fs/1000);
+ Nc = sim_in.Nc;
+ symbol_amp = sim_in.symbol_amp;
+
+ bps = 2;
+ Nsymb = framesize/bps;
+ for k=1:Nc
+ prev_sym_tx(k) = qpsk_mod([0 0]);
+ prev_sym_rx(k) = qpsk_mod([0 0]);
+ end
+
+ % design root nyquist (root raised cosine) filter and init tx and rx filter states
+
+ alpha = 0.5; T=1/Fs; Nfiltsym=7; M=Fs/Rs;
+ if floor(Fs/Rs) != Fs/Rs
+ printf("oversampling ratio must be an integer\n");
+ return;
+ end
+ hrn = gen_rn_coeffs(alpha, T, Rs, Nfiltsym, M);
+ Nfilter = length(hrn);
+
+ % convert "spreading" samples from 1kHz carrier at Fs to complex
+ % baseband, generated by passing a 1kHz sine wave through PathSim
+ % with the ccir-poor model, enabling one path at a time.
+
+ Fc = 1000;
+ fspread = fopen("../raw/sine1k_2Hz_spread.raw","rb");
+ spread1k = fread(fspread, "int16")/10000;
+ fclose(fspread);
+ fspread = fopen("../raw/sine1k_2ms_delay_2Hz_spread.raw","rb");
+ spread1k_2ms = fread(fspread, "int16")/10000;
+ fclose(fspread);
+
+ % down convert to complex baseband
+ spreadbb = spread1k.*exp(-j*(2*pi*Fc/Fs)*(1:length(spread1k))');
+ spreadbb_2ms = spread1k_2ms.*exp(-j*(2*pi*Fc/Fs)*(1:length(spread1k_2ms))');
+
+ % remove -2000 Hz image
+ b = fir1(50, 5/Fs);
+ spread = filter(b,1,spreadbb);
+ spread_2ms = filter(b,1,spreadbb_2ms);
+
+ % discard first 1000 samples as these were near 0, probably as
+ % PathSim states were ramping up. Transpose for convenience
+
+ spread = transpose(spread(1000:length(spread)));
+ spread_2ms = transpose(spread_2ms(1000:length(spread_2ms)));
+
+ % Determine "gain" of HF channel model, so we can normalise
+ % carrier power during HF channel sim to calibrate SNR. I imagine
+ % different implementations of ccir-poor would do this in
+ % different ways, leading to different BER results. Oh Well!
+
+ hf_gain = 1.0/sqrt(var(spread)+var(spread_2ms));
+
+ % Start Simulation ----------------------------------------------------------------
+
+ for ne = 1:length(Esvec)
+ EsNodB = Esvec(ne);
+ EsNo = 10^(EsNodB/10);
+
+ variance = Fs/(Rs*EsNo);
+ if verbose > 1
+ printf("EsNo (dB): %f EsNo: %f variance: %f\n", EsNodB, EsNo, variance);
+ end
+
+ Terrs = 0; Tbits = 0;
+
+ tx_symb_log = [];
+ rx_symb_log = [];
+ noise_log = [];
+ sim_out.errors_log = [];
+ sim_out.tx_baseband_log = [];
+ sim_out.rx_filt_log = [];
+ symbol_amp_index = 1;
+
+ % init filter memories and LOs
+
+ tx_filter_memory = zeros(Nc, Nfilter);
+ rx_filter_memory = zeros(Nc, Nfilter);
+ s_delay_line_filt = zeros(Nc, Nfiltsym);
+ phase_tx = ones(1,Nc);
+ phase_rx = ones(1,Nc);
+ Fcentre = 1500; Fsep = (1+alpha)*Rs;
+ freq = Fcentre + Fsep*((-Nc/2+0.5):(Nc/2-0.5));
+ freq = exp(j*freq*2*pi/Fs);
+
+ % init HF channel
+
+ sc = 1; hf_n = 1;
+ hf_sim_delay_line = zeros(1,M+Nhfdelay);
+ freq_sample_hz = Fcentre + ((Fsep*(-Nc/2)):50:(Fsep*(Nc/2)));
+ freq_sample_rads = (2*pi/Fs)*freq_sample_hz;
+ hf_model = ones(Ntrials*Nsymb/Nc, length(freq_sample_rads)); % defaults for plotting surface
+
+ % bunch of outputs we log for graphing
+
+ sim_out.errors_log = [];
+ sim_out.Nerrs = [];
+ sim_out.snr_log = [];
+ sim_out.hf_model_pwr = [];
+ sim_out.tx_fdm_log = [];
+ C_log = [];
+
+ for nn = 1: Ntrials
+
+ tx_bits = round( rand( 1, framesize ) );
+
+ % modulate --------------------------------------------
+
+ s = zeros(1, Nsymb);
+ for i=1:Nc:Nsymb
+ for k=1:Nc
+ tx_symb = qpsk_mod(tx_bits(2*(i-1+k-1)+1:2*(i+k-1)));
+ s_qpsk(i+k-1) = tx_symb;
+ tx_symb *= prev_sym_tx(k);
+ prev_sym_tx(k) = tx_symb;
+ s(i+k-1) = symbol_amp(symbol_amp_index)*tx_symb;
+ end
+ end
+ symbol_amp_index++;
+ s_ch = s;
+
+ % Now we start processing frame Nc symbols at a time to model parallel carriers
+
+ tx_fdm_sym_log = [];
+ for i=1:Nc:Nsymb
+
+ % Delay tx symbols to match delay due to filters. qpsk
+ % (rather than dqpsk) symbols used for convenience as
+ % it's easy to shift symbols than pairs of bits
+
+ s_delay_line_filt(:,1:Nfiltsym-1) = s_delay_line_filt(:,2:Nfiltsym);
+ s_delay_line_filt(:,Nfiltsym) = s_qpsk(i:i+Nc-1);
+ s_qpsk(i:i+Nc-1) = s_delay_line_filt(:,1);
+ for k=1:Nc
+ tx_bits(2*(i-1+k-1)+1:2*(i+k-1)) = qpsk_demod(s_qpsk(i+k-1));
+ end
+
+ % tx filter
+
+ tx_baseband = zeros(Nc,M);
+
+ % tx filter each symbol, generate M filtered output samples for each symbol.
+ % Efficient polyphase filter techniques used as tx_filter_memory is sparse
+
+ tx_filter_memory(:,Nfilter) = s(i:i+Nc-1);
+
+ for k=1:M
+ tx_baseband(:,k) = M*tx_filter_memory(:,M:M:Nfilter) * hrn(M-k+1:M:Nfilter)';
+ end
+ tx_filter_memory(:,1:Nfilter-M) = tx_filter_memory(:,M+1:Nfilter);
+ tx_filter_memory(:,Nfilter-M+1:Nfilter) = zeros(Nc,M);
+
+ sim_out.tx_baseband_log = [sim_out.tx_baseband_log tx_baseband];
+
+ % upconvert
+
+ tx_fdm = zeros(1,M);
+
+ for c=1:Nc
+ for k=1:M
+ phase_tx(c) = phase_tx(c) * freq(c);
+ tx_fdm(k) = tx_fdm(k) + tx_baseband(c,k)*phase_tx(c);
+ end
+ end
+
+ sim_out.tx_fdm_log = [sim_out.tx_fdm_log tx_fdm];
+
+ % HF channel
+
+ if hf_sim
+ hf_sim_delay_line(1:Nhfdelay) = hf_sim_delay_line(M+1:M+Nhfdelay);
+ hf_sim_delay_line(Nhfdelay+1:M+Nhfdelay) = tx_fdm;
+
+ tx_fdm = tx_fdm.*spread(sc:sc+M-1) + hf_sim_delay_line(1:M).*spread_2ms(sc:sc+M-1);
+ tx_fdm *= hf_gain;
+
+ % sample HF channel spectrum in middle of this symbol for plotting
+
+ hf_model(hf_n,:) = hf_gain*(spread(sc+M/2) + exp(-j*freq_sample_rads*Nhfdelay)*spread_2ms(sc+M/2));
+
+ sc += M;
+ hf_n++;
+ end
+
+ tx_fdm_sym_log = [tx_fdm_sym_log tx_fdm ];
+
+ % AWGN noise and phase/freq offset channel simulation
+ % 0.5 factor ensures var(noise) == variance , i.e. splits power between Re & Im
+
+ noise = sqrt(variance*0.5)*(randn(1,M) + j*randn(1,M));
+ noise_log = [noise_log noise];
+
+ % apply frequency and phase offset and noise
+
+ for k=1:M
+ rx_fdm(k) = tx_fdm(k)*exp(j*phase_offset) + noise(k);
+ phase_offset += w_offset;
+ end
+
+ % downconvert
+
+ rx_baseband = zeros(Nc,M);
+ for c=1:Nc
+ for k=1:M
+ phase_rx(c) = phase_rx(c) * freq(c);
+ rx_baseband(c,k) = rx_fdm(k)*phase_rx(c)';
+ end
+ end
+
+ % rx filter
+
+ rx_filter_memory(:,Nfilter-M+1:Nfilter) = rx_baseband;
+ rx_filt = rx_filter_memory * hrn';
+ rx_filter_memory(:,1:Nfilter-M) = rx_filter_memory(:,1+M:Nfilter);
+ sim_out.rx_filt_log = [sim_out.rx_filt_log rx_filt];
+
+ s_ch(i:i+Nc-1) = rx_filt;
+ end
+
+ % est HF model power for entire code frame (which could be several symbols)
+
+ if hf_sim
+ frame_hf_model = reshape(hf_model(hf_n-Nsymb/Nc:hf_n-1,:),1,(Nsymb/Nc)*length(freq_sample_hz));
+ sim_out.hf_model_pwr = [sim_out.hf_model_pwr mean(abs(frame_hf_model).^2)];
+ else
+ sim_out.hf_model_pwr = [sim_out.hf_model_pwr 1];
+ end
+
+ % "genie" SNR estimate
+
+ snr = (tx_fdm_sym_log*tx_fdm_sym_log')/(M*variance);
+ sim_out.snr_log = [sim_out.snr_log snr];
+
+ % de-modulate
+
+ rx_bits = zeros(1, framesize);
+ for i=1:Nc:Nsymb
+ for k=1:Nc
+ rx_symb = s_ch(i+k-1);
+ tmp = rx_symb;
+ rx_symb *= conj(prev_sym_rx(k)/abs(prev_sym_rx(k)));
+ prev_sym_rx(k) = tmp;
+ rx_bits((2*(i-1+k-1)+1):(2*(i+k-1))) = qpsk_demod(rx_symb);
+ rx_symb_log = [rx_symb_log rx_symb];
+ end
+ end
+
+ % ignore data until we have enough frames to fill filter memory
+ % then count errors
+
+ if nn > ceil(Nfiltsym/(Nsymb/Nc))
+ error_positions = xor(rx_bits, tx_bits);
+ sim_out.errors_log = [sim_out.errors_log error_positions];
+ Nerrs = sum(error_positions);
+ sim_out.Nerrs = [sim_out.Nerrs Nerrs];
+ Terrs += Nerrs;
+ Tbits += length(tx_bits);
+ end
+
+ end
+
+ TERvec(ne) = Terrs;
+ BERvec(ne) = Terrs/Tbits;
+
+ if verbose
+ printf("EsNo (dB): %f Terrs: %d BER %f ", EsNodB, Terrs, Terrs/Tbits);
+ printf("\n");
+ end
+ if verbose > 1
+ printf("Terrs: %d BER %f C %f N %f Es %f No %f Es/No %f\n\n", Terrs,
+ Terrs/Tbits, var(sim_out.tx_fdm_log), var(noise_log),
+ var(sim_out.tx_fdm_log)/(Nc*Rs), var(noise_log)/Fs, (var(sim_out.tx_fdm_log)/(Nc*Rs))/(var(noise_log)/Fs));
+ end
+ end
+
+ Ebvec = Esvec - 10*log10(bps);
+
+ sim_out.BERvec = BERvec;
+ sim_out.Ebvec = Ebvec;
+ sim_out.TERvec = TERvec;
+
+ if plot_scatter
+ figure(2);
+ clf;
+ scat = rx_symb_log(Nfiltsym*Nc:length(rx_symb_log)) .* exp(j*pi/4);
+ plot(real(scat), imag(scat),'+');
+ title('Scatter plot');
+
+ figure(3);
+ clf;
+ y = 1:Rs*2;
+ EsNodBSurface = 20*log10(abs(hf_model(y,:))) + EsNodB;
+ mesh(1:length(freq_sample_hz),y,EsNodBSurface);
+ grid
+ title('HF Channel Es/No');
+ end
+
+endfunction
+
+% Gray coded QPSK modulation function
+
+function symbol = qpsk_mod(two_bits)
+ two_bits_decimal = sum(two_bits .* [2 1]);
+ switch(two_bits_decimal)
+ case (0) symbol = 1;
+ case (1) symbol = j;
+ case (2) symbol = -j;
+ case (3) symbol = -1;
+ endswitch
+endfunction
+
+% Gray coded QPSK demodulation function
+
+function two_bits = qpsk_demod(symbol)
+ if isscalar(symbol) == 0
+ printf("only works with scalars\n");
+ return;
+ end
+ bit0 = real(symbol*exp(j*pi/4)) < 0;
+ bit1 = imag(symbol*exp(j*pi/4)) < 0;
+ two_bits = [bit1 bit0];
+endfunction
+
+function sim_in = standard_init
+ sim_in.verbose = 1;
+ sim_in.plot_scatter = 0;
+
+ sim_in.Esvec = 5:15;
+ sim_in.Ntrials = 100;
+ sim_in.framesize = 64;
+ sim_in.Rs = 100;
+ sim_in.Nc = 8;
+
+ sim_in.phase_offset = 0;
+ sim_in.w_offset = 0;
+ sim_in.phase_noise_amp = 0;
+
+ sim_in.hf_delay_ms = 2;
+ sim_in.hf_sim = 0;
+ sim_in.hf_phase_only = 0;
+ sim_in.hf_mag_only = 0;
+endfunction
+
+function awgn_hf_ber_curves()
+ sim_in = standard_init();
+
+ Ebvec = sim_in.Esvec - 10*log10(2);
+ BER_theory = 0.5*erfc(sqrt(10.^(Ebvec/10)));
+
+ dpsk_awgn = ber_test(sim_in);
+ sim_in.hf_sim = 1;
+ dpsk_hf = ber_test(sim_in);
+
+ figure(1);
+ clf;
+ semilogy(Ebvec, BER_theory,'r;QPSK theory;')
+ hold on;
+ semilogy(dpsk_awgn.Ebvec, dpsk_awgn.BERvec,'g;DQPSK;')
+ semilogy(dpsk_hf.Ebvec, dpsk_hf.BERvec,'g;DQPSK HF;')
+ hold off;
+ xlabel('Eb/N0')
+ ylabel('BER')
+ grid("minor")
+ axis([min(Ebvec) max(Ebvec) 1E-3 1])
+end
+
+sim_in = standard_init();
+
+% energy file sampled every 10ms
+
+load ../src/ve9qrp.txt
+pdB=10*log10(ve9qrp);
+for i=1:length(pdB)
+ if pdB(i) < 0
+ pdB(i) = 0;
+ end
+end
+
+% Down sample to 40ms rate used for 1300 bit/s codec, every 4th sample is transmitted
+
+pdB = pdB(4:4:length(pdB));
+
+% Use linear mapping function in dB domain to map to symbol power
+
+%power_map_x = [ 0 20 24 40 50 ];
+%power_map_y = [--6 -6 0 6 6];
+power_map_x = [ 0 50 ];
+power_map_y = [ -15 12];
+mapped_pdB = interp1(power_map_x, power_map_y, pdB);
+
+sim_in.symbol_amp = 10 .^ (mapped_pdB/20);
+%sim_in.symbol_amp = ones(1,length(pdB));
+sim_in.plot_scatter = 1;
+sim_in.verbose = 2;
+sim_in.hf_delay_ms = 2;
+sim_in.hf_sim = 1;
+sim_in.Esvec = 10;
+sim_in.Ntrials = 400;
+
+dqpsk_pwr_hf = ber_test(sim_in);
+
+% note: need way to test that power is aligned with speech
+
+figure(4)
+clf;
+plot((1:sim_in.Ntrials)*80*4, pdB(1:sim_in.Ntrials));
+hold on;
+plot((1:sim_in.Ntrials)*80*4, mapped_pdB(1:sim_in.Ntrials),'r');
+hold off;
+
+figure(5)
+clf;
+s = load_raw("../raw/ve9qrp.raw");
+M=320; M_on_2 = M/2; % processing delay between input speech and centre of analysis window
+subplot(211)
+plot(M_on_2:(M_on_2-1+sim_in.Ntrials*M),s(1:sim_in.Ntrials*M))
+hold on;
+plot((1:sim_in.Ntrials)*M, 5000*sim_in.symbol_amp(1:sim_in.Ntrials),'r');
+hold off;
+axis([1 sim_in.Ntrials*M -3E4 3E4]);
+subplot(212)
+plot(real(dqpsk_pwr_hf.tx_fdm_log));
+
+
+figure(6)
+clf;
+plot((1:sim_in.Ntrials)*M, 20*log10(sim_in.symbol_amp(1:sim_in.Ntrials)),'b;Es (dB);');
+hold on;
+plot((1:sim_in.Ntrials)*M, 10*log10(dqpsk_pwr_hf.hf_model_pwr),'g;Fading (dB);');
+plot((1:sim_in.Ntrials)*M, 10*log10(dqpsk_pwr_hf.snr_log),'r;Es/No (dB);');
+
+ber = dqpsk_pwr_hf.Nerrs/sim_in.framesize;
+ber_clip = ber;
+ber_clip(find(ber > 0.2)) = 0.2;
+plot((1:length(ber_clip))*M, -20+100*ber_clip,'k;BER (0-20%);');
+hold off;
+axis([1 sim_in.Ntrials*M -20 20])
+
+fep=fopen("dqpsk_errors_pwr.bin","wb"); fwrite(fep, dqpsk_pwr_hf.errors_log, "short"); fclose(fep);
+fber=fopen("ber.bin","wb"); fwrite(fber, ber, "float"); fclose(fber);
-% test_foff.m\r
-% David Rowe April 2015\r
-%\r
-% Octave script for testing the cohpsk freq offset estimator\r
-\r
-graphics_toolkit ("gnuplot");\r
-more off;\r
-\r
-cohpsk;\r
-fdmdv;\r
-autotest;\r
-\r
-rand('state',1); \r
-randn('state',1);\r
-\r
- \r
-% Core function for testing frequency offset estimator. Performs one test\r
-\r
-function sim_out = freq_off_est_test(sim_in)\r
- global Nfilter;\r
- global M;\r
-\r
- Rs = 100;\r
- Nc = 4;\r
- Nd = 2;\r
- framesize = 32;\r
- Fs = 8000;\r
- Fcentre = 1500;\r
- \r
- Nsw = 3; % numbers of sync window frames we process over. Set based\r
- % on Nsym to flush filter memory by final frame in windw\r
-\r
- afdmdv.Nsym = 5;\r
- afdmdv.Nt = 5;\r
-\r
- afdmdv.Fs = 8000;\r
- afdmdv.Nc = Nd*Nc-1;\r
- afdmdv.Rs = Rs;\r
- M = afdmdv.M = afdmdv.Fs/afdmdv.Rs;\r
- afdmdv.Nfilter = afdmdv.Nsym*M;\r
- afdmdv.tx_filter_memory = zeros(afdmdv.Nc+1, afdmdv.Nfilter);\r
- excess_bw = 0.5;\r
- afdmdv.gt_alpha5_root = gen_rn_coeffs(excess_bw, 1/Fs, Rs, afdmdv.Nsym, afdmdv.M);\r
- afdmdv.Fsep = afdmdv.Rs*(1+excess_bw);\r
- afdmdv.phase_tx = ones(afdmdv.Nc+1,1);\r
- freq_hz = afdmdv.Fsep*( -Nc*Nd/2 - 0.5 + (1:Nc*Nd).^1.1 );\r
- afdmdv.freq_pol = 2*pi*freq_hz/Fs;\r
- afdmdv.freq = exp(j*afdmdv.freq_pol);\r
- afdmdv.Fcentre = 1500;\r
-\r
- afdmdv.fbb_rect = exp(j*2*pi*Fcentre/Fs);\r
- afdmdv.fbb_phase_tx = 1;\r
- afdmdv.fbb_phase_rx = 1;\r
- %afdmdv.phase_rx = ones(afdmdv.Nc+1,1);\r
- afdmdv.phase_rx = 1 - 2*(mod(1:Nc*Nd,2));\r
- nin = M;\r
-\r
- P = afdmdv.P = 4;\r
- afdmdv.Nfilter = afdmdv.Nsym*afdmdv.M;\r
- afdmdv.rx_filter_mem_timing = zeros(afdmdv.Nc+1, afdmdv.Nt*afdmdv.P);\r
- afdmdv.Nfiltertiming = afdmdv.M + afdmdv.Nfilter + afdmdv.M;\r
- afdmdv.rx_filter_memory = zeros(afdmdv.Nc+1, afdmdv.Nfilter);\r
-\r
- acohpsk = standard_init();\r
- acohpsk.framesize = framesize;\r
- acohpsk.ldpc_code = 0;\r
- acohpsk.ldpc_code_rate = 1;\r
- acohpsk.Nc = Nc;\r
- acohpsk.Rs = Rs;\r
- acohpsk.Ns = 4;\r
- acohpsk.Nd = Nd;\r
- acohpsk.modulation = 'qpsk';\r
- acohpsk.do_write_pilot_file = 0;\r
- acohpsk = symbol_rate_init(acohpsk);\r
- acohpsk.Ncm = 10*acohpsk.Nsymbrowpilot*M;\r
- acohpsk.coarse_mem = zeros(1,acohpsk.Ncm);\r
- acohpsk.Ndft = 2^(ceil(log2(acohpsk.Ncm)));\r
- \r
- ch_fdm_frame_buf = zeros(1, Nsw*acohpsk.Nsymbrowpilot*M);\r
-\r
- frames = sim_in.frames;\r
- EsNodB = sim_in.EsNodB;\r
- foff = sim_in.foff;\r
- dfoff = sim_in.dfoff;\r
- fading_en = sim_in.fading_en;\r
-\r
- EsNo = 10^(EsNodB/10);\r
- hf_delay_ms = 2;\r
- phase_ch = 1;\r
-\r
- rand('state',1); \r
- tx_bits_coh = round(rand(1,framesize*10));\r
- ptx_bits_coh = 1;\r
- [spread spread_2ms hf_gain] = init_hf_model(Fs, frames*acohpsk.Nsymbrowpilot*afdmdv.M);\r
-\r
- hf_n = 1;\r
- nhfdelay = floor(hf_delay_ms*Fs/1000);\r
- ch_fdm_delay = zeros(1, acohpsk.Nsymbrowpilot*M + nhfdelay);\r
- \r
- sync = 0; next_sync = 1;\r
- sync_start = 1;\r
- freq_offset_log = [];\r
- sync_time_log = [];\r
- ch_fdm_frame_log = [];\r
- ch_symb_log = [];\r
- tx_fdm_frame_log = [];\r
- ratio_log = [];\r
-\r
- for f=1:frames\r
-\r
- acohpsk.frame = f;\r
-\r
- %\r
- % Mod --------------------------------------------------------------------\r
- %\r
-\r
- tx_bits = tx_bits_coh(ptx_bits_coh:ptx_bits_coh+framesize-1);\r
- ptx_bits_coh += framesize;\r
- if ptx_bits_coh > length(tx_bits_coh)\r
- ptx_bits_coh = 1;\r
- end \r
-\r
- [tx_symb tx_bits] = bits_to_qpsk_symbols(acohpsk, tx_bits, [], []);\r
-\r
- tx_fdm_frame = [];\r
- for r=1:acohpsk.Nsymbrowpilot\r
- tx_onesymb = tx_symb(r,:);\r
- [tx_baseband afdmdv] = tx_filter(afdmdv, tx_onesymb);\r
- [tx_fdm afdmdv] = fdm_upconvert(afdmdv, tx_baseband);\r
- tx_fdm_frame = [tx_fdm_frame tx_fdm];\r
- end\r
- tx_fdm_frame_log = [tx_fdm_frame_log tx_fdm_frame];\r
-\r
- %\r
- % Channel --------------------------------------------------------------------\r
- %\r
-\r
- ch_fdm_frame = zeros(1,acohpsk.Nsymbrowpilot*M);\r
- for i=1:acohpsk.Nsymbrowpilot*M\r
- foff_rect = exp(j*2*pi*foff/Fs);\r
- foff += dfoff;\r
- phase_ch *= foff_rect;\r
- ch_fdm_frame(i) = tx_fdm_frame(i) * phase_ch;\r
- end\r
- phase_ch /= abs(phase_ch);\r
-\r
- if fading_en\r
- ch_fdm_delay(1:nhfdelay) = ch_fdm_delay(acohpsk.Nsymbrowpilot*M+1:nhfdelay+acohpsk.Nsymbrowpilot*M);\r
- ch_fdm_delay(nhfdelay+1:nhfdelay+acohpsk.Nsymbrowpilot*M) = ch_fdm_frame;\r
-\r
- for i=1:acohpsk.Nsymbrowpilot*M\r
- ahf_model = hf_gain*(spread(hf_n)*ch_fdm_frame(i) + spread_2ms(hf_n)*ch_fdm_delay(i));\r
- ch_fdm_frame(i) = ahf_model;\r
- hf_n++;\r
- end\r
- end\r
-\r
- % each carrier has power = 2, total power 2Nc, total symbol rate NcRs, noise BW B=Fs\r
- % Es/No = (C/Rs)/(N/B), N = var = 2NcFs/NcRs(Es/No) = 2Fs/Rs(Es/No)\r
-\r
- variance = 2*Fs/(acohpsk.Rs*EsNo);\r
- uvnoise = sqrt(0.5)*(randn(1,acohpsk.Nsymbrowpilot*M) + j*randn(1,acohpsk.Nsymbrowpilot*M));\r
- noise = sqrt(variance)*uvnoise;\r
-\r
- ch_fdm_frame += noise;\r
- ch_fdm_frame_log = [ch_fdm_frame_log ch_fdm_frame];\r
-\r
- %\r
- % Try to achieve sync --------------------------------------------------------------------\r
- %\r
-\r
- % store Nsw frames so we can rewind if we get a good candidate\r
-\r
- ch_fdm_frame_buf(1:(Nsw-1)*acohpsk.Nsymbrowpilot*M) = ch_fdm_frame_buf(acohpsk.Nsymbrowpilot*M+1:Nsw*acohpsk.Nsymbrowpilot*M);\r
- ch_fdm_frame_buf((Nsw-1)*acohpsk.Nsymbrowpilot*M+1:Nsw*acohpsk.Nsymbrowpilot*M) = ch_fdm_frame;\r
-\r
- next_sync = sync;\r
- sync = 0;\r
-\r
- if sync == 0\r
-\r
- % we can test +/- 20Hz, so we break this up into 3 tests to cover +/- 60Hz\r
-\r
- max_ratio = 0;\r
- for acohpsk.f_est = Fcentre-40:40:Fcentre+40\r
- %for acohpsk.f_est = Fcentre\r
- \r
- printf(" [%d] acohpsk.f_est: %f +/- 20\n", f, acohpsk.f_est);\r
- [ch_symb rx_timing rx_filt rx_baseband afdmdv acohpsk.f_est ] = rate_Fs_rx_processing(afdmdv, ch_fdm_frame_buf, acohpsk.f_est, Nsw*acohpsk.Nsymbrowpilot, nin, 0);\r
-\r
- % coarse timing (frame sync) and initial fine freq est ---------------------------------------------\r
- \r
- for i=1:Nsw-1\r
- acohpsk.ct_symb_buf = update_ct_symb_buf(acohpsk.ct_symb_buf, ch_symb((i-1)*acohpsk.Nsymbrowpilot+1:i*acohpsk.Nsymbrowpilot,:), acohpsk.Nct_sym_buf, acohpsk.Nsymbrowpilot);\r
- end\r
- [anext_sync acohpsk] = frame_sync_fine_freq_est(acohpsk, ch_symb((Nsw-1)*acohpsk.Nsymbrowpilot+1:Nsw*acohpsk.Nsymbrowpilot,:), sync, next_sync);\r
-\r
- if anext_sync == 1\r
- printf(" [%d] acohpsk.ratio: %f\n", f, acohpsk.ratio);\r
- if acohpsk.ratio > max_ratio\r
- max_ratio = acohpsk.ratio;\r
- f_est = acohpsk.f_est - acohpsk.f_fine_est;\r
- next_sync = anext_sync;\r
- end\r
- end\r
- end\r
- end\r
-\r
- % we've found a sync candidate\r
-\r
- if (next_sync == 1)\r
-\r
- % rewind and re-process last few frames with f_est\r
-\r
- acohpsk.f_est = f_est;\r
- printf(" [%d] trying sync and f_est: %f\n", f, acohpsk.f_est);\r
- [ch_symb rx_timing rx_filt rx_baseband afdmdv acohpsk.f_est] = rate_Fs_rx_processing(afdmdv, ch_fdm_frame_buf, acohpsk.f_est, Nsw*acohpsk.Nsymbrowpilot, nin, 0);\r
- ch_symb_log = ch_symb;\r
- for i=1:Nsw-1\r
- acohpsk.ct_symb_buf = update_ct_symb_buf(acohpsk.ct_symb_buf, ch_symb((i-1)*acohpsk.Nsymbrowpilot+1:i*acohpsk.Nsymbrowpilot,:), acohpsk.Nct_sym_buf, acohpsk.Nsymbrowpilot);\r
- end\r
- [next_sync acohpsk] = frame_sync_fine_freq_est(acohpsk, ch_symb((Nsw-1)*acohpsk.Nsymbrowpilot+1:Nsw*acohpsk.Nsymbrowpilot,:), sync, next_sync);\r
- if abs(acohpsk.f_fine_est) > 2\r
- printf(" [%d] Hmm %f is a bit big so back to coarse est ...\n", f, acohpsk.f_fine_est);\r
- next_sync = 0;\r
- end\r
-\r
- % candidate checks out so log stats\r
-\r
- if (next_sync == 1)\r
- printf(" [%d] in sync!\n", f);\r
- freq_offset_log = [freq_offset_log Fcentre+foff-acohpsk.f_est];\r
- sync_time_log = [sync_time_log f-sync_start];\r
- ratio_log = [ratio_log max_ratio];\r
- next_sync = 0; sync_start = f;\r
- end\r
- end\r
-\r
- %printf("f: %d sync: %d next_sync: %d\n", f, sync, next_sync);\r
- [sync acohpsk] = sync_state_machine(acohpsk, sync, next_sync);\r
-\r
- end\r
-\r
- % ftx=fopen("coarse_tx.raw","wb"); fwrite(ftx, 1000*ch_fdm_frame_log, "short"); fclose(ftx);\r
-\r
- sim_out.freq_offset_log = freq_offset_log;\r
- sim_out.sync_time_log = sync_time_log;\r
- sim_out.ch_fdm_frame_log = ch_fdm_frame_log;\r
- sim_out.ch_symb_log = ch_symb_log;\r
- sim_out.tx_fdm_frame_log = tx_fdm_frame_log;\r
- sim_out.ratio_log = ratio_log;\r
-endfunction\r
-\r
-\r
-function freq_off_est_test_single\r
- sim_in.frames = 5;\r
- sim_in.EsNodB = 120;\r
- sim_in.foff = 0;\r
- sim_in.dfoff = 0;\r
- sim_in.fading_en = 0;\r
-\r
- sim_out = freq_off_est_test(sim_in);\r
-\r
- figure(1)\r
- subplot(211)\r
- plot(sim_out.freq_offset_log)\r
- ylabel('f est error')\r
- xlabel('time')\r
-\r
- subplot(212)\r
- if length(sim_out.freq_offset_log) > 0\r
- hist(sim_out.freq_offset_log)\r
- xlabel('f est error')\r
- ylabel('histogram');\r
- end\r
-\r
- figure(2)\r
- subplot(211)\r
- plot(sim_out.sync_time_log)\r
- ylabel('time to sync (frames)')\r
- subplot(212)\r
- if length(sim_out.sync_time_log) > 0\r
- hist(sim_out.sync_time_log)\r
- xlabel('time to sync (frames)')\r
- ylabel('histogram')\r
- end\r
-\r
- figure(3)\r
- subplot(211)\r
- plot(real(sim_out.tx_fdm_frame_log(1:2*960)))\r
- grid;\r
- subplot(212)\r
- plot(real(sim_out.ch_symb_log),'+')\r
- grid;\r
-\r
- figure(4)\r
- clf;\r
- plot(sim_out.ch_symb_log,'+')\r
-\r
- figure(5)\r
- clf;\r
- plot(sim_out.ratio_log)\r
- xlabel('time')\r
- ylabel('ratio for sync')\r
-endfunction\r
-\r
-\r
-function [freq_off_log EsNodBSet] = freq_off_est_test_curves\r
- EsNodBSet = [20 12 8];\r
-\r
- sim_in.frames = 100;\r
- sim_in.foff = -40;\r
- sim_in.dfoff = 0;\r
- sim_in.fading_en = 1;\r
- freq_off_log = 1E6*ones(sim_in.frames, length(EsNodBSet) );\r
- sync_time_log = 1E6*ones(sim_in.frames, length(EsNodBSet) );\r
-\r
- for i=1:length(EsNodBSet)\r
- sim_in.EsNodB = EsNodBSet(i);\r
- printf("%f\n", sim_in.EsNodB);\r
-\r
- sim_out = freq_off_est_test(sim_in);\r
- freq_off_log(1:length(sim_out.freq_offset_log),i) = sim_out.freq_offset_log;\r
- sync_time_log(1:length(sim_out.sync_time_log),i) = sim_out.sync_time_log;\r
- end\r
-\r
- figure(1)\r
- clf\r
- hold on;\r
- for i=1:length(EsNodBSet)\r
- data = freq_off_log(find(freq_off_log(:,i) < 1E6),i);\r
- s = std(data);\r
- m = mean(data);\r
- stdbar = [m-s; m+s];\r
- plot(EsNodBSet(i), data, '+')\r
- plot([EsNodBSet(i) EsNodBSet(i)]+0.5, stdbar,'+-')\r
- end\r
- hold off\r
-\r
- axis([6 22 -25 25])\r
- if sim_in.fading_en\r
- title_str = sprintf('foff = %d Hz Fading', sim_in.foff);\r
- else\r
- title_str = sprintf('foff = %d Hz AWGN', sim_in.foff);\r
- end\r
- title(title_str);\r
- xlabel('Es/No (dB)')\r
- ylabel('freq offset error (Hz)');\r
- \r
- figure(2)\r
- clf\r
- hold on;\r
- for i=1:length(EsNodBSet)\r
- leg = sprintf("%d;%d dB;", i, EsNodBSet(i));\r
- plot(freq_off_log(find(freq_off_log(:,i) < 1E6),i),leg)\r
- end\r
- hold off;\r
- title(title_str);\r
- xlabel('test');\r
- ylabel('freq offset error (Hz)');\r
- legend('boxoff');\r
-\r
- figure(3)\r
- clf\r
- hold on;\r
- for i=1:length(EsNodBSet)\r
- data = sync_time_log(find(sync_time_log(:,i) < 1E6),i);\r
- if length(data) \r
- s = std(data);\r
- m = mean(data);\r
- stdbar = [m-s; m+s];\r
- plot(EsNodBSet(i), data, '+')\r
- plot([EsNodBSet(i) EsNodBSet(i)]+0.5, stdbar,'+-')\r
- end\r
- end \r
- hold off;\r
- axis([6 22 0 10])\r
- ylabel('sync time (frames)')\r
- xlabel('Es/No (dB)');\r
- title(title_str);\r
-\r
- figure(4)\r
- clf\r
- hold on;\r
- for i=1:length(EsNodBSet)\r
- leg = sprintf("%d;%d dB;", i, EsNodBSet(i));\r
- plot(sync_time_log(find(sync_time_log(:,i) < 1E6),i),leg)\r
- end\r
- hold off;\r
- title(title_str);\r
- xlabel('test');\r
- ylabel('sync time (frames)');\r
- legend('boxoff');\r
-\r
-endfunction\r
-\r
-\r
-% select on of these to run:\r
-\r
-freq_off_est_test_single;\r
-%freq_off_est_test_curves;\r
-\r
+% test_foff.m
+% David Rowe April 2015
+%
+% Octave script for testing the cohpsk freq offset estimator
+
+graphics_toolkit ("gnuplot");
+more off;
+
+cohpsk;
+fdmdv;
+autotest;
+
+rand('state',1);
+randn('state',1);
+
+
+% Core function for testing frequency offset estimator. Performs one test
+
+function sim_out = freq_off_est_test(sim_in)
+ global Nfilter;
+ global M;
+
+ Rs = 100;
+ Nc = 4;
+ Nd = 2;
+ framesize = 32;
+ Fs = 8000;
+ Fcentre = 1500;
+
+ Nsw = 3; % numbers of sync window frames we process over. Set based
+ % on Nsym to flush filter memory by final frame in windw
+
+ afdmdv.Nsym = 5;
+ afdmdv.Nt = 5;
+
+ afdmdv.Fs = 8000;
+ afdmdv.Nc = Nd*Nc-1;
+ afdmdv.Rs = Rs;
+ M = afdmdv.M = afdmdv.Fs/afdmdv.Rs;
+ afdmdv.Nfilter = afdmdv.Nsym*M;
+ afdmdv.tx_filter_memory = zeros(afdmdv.Nc+1, afdmdv.Nfilter);
+ excess_bw = 0.5;
+ afdmdv.gt_alpha5_root = gen_rn_coeffs(excess_bw, 1/Fs, Rs, afdmdv.Nsym, afdmdv.M);
+ afdmdv.Fsep = afdmdv.Rs*(1+excess_bw);
+ afdmdv.phase_tx = ones(afdmdv.Nc+1,1);
+ freq_hz = afdmdv.Fsep*( -Nc*Nd/2 - 0.5 + (1:Nc*Nd).^1.1 );
+ afdmdv.freq_pol = 2*pi*freq_hz/Fs;
+ afdmdv.freq = exp(j*afdmdv.freq_pol);
+ afdmdv.Fcentre = 1500;
+
+ afdmdv.fbb_rect = exp(j*2*pi*Fcentre/Fs);
+ afdmdv.fbb_phase_tx = 1;
+ afdmdv.fbb_phase_rx = 1;
+ %afdmdv.phase_rx = ones(afdmdv.Nc+1,1);
+ afdmdv.phase_rx = 1 - 2*(mod(1:Nc*Nd,2));
+ nin = M;
+
+ P = afdmdv.P = 4;
+ afdmdv.Nfilter = afdmdv.Nsym*afdmdv.M;
+ afdmdv.rx_filter_mem_timing = zeros(afdmdv.Nc+1, afdmdv.Nt*afdmdv.P);
+ afdmdv.Nfiltertiming = afdmdv.M + afdmdv.Nfilter + afdmdv.M;
+ afdmdv.rx_filter_memory = zeros(afdmdv.Nc+1, afdmdv.Nfilter);
+
+ acohpsk = standard_init();
+ acohpsk.framesize = framesize;
+ acohpsk.ldpc_code = 0;
+ acohpsk.ldpc_code_rate = 1;
+ acohpsk.Nc = Nc;
+ acohpsk.Rs = Rs;
+ acohpsk.Ns = 4;
+ acohpsk.Nd = Nd;
+ acohpsk.modulation = 'qpsk';
+ acohpsk.do_write_pilot_file = 0;
+ acohpsk = symbol_rate_init(acohpsk);
+ acohpsk.Ncm = 10*acohpsk.Nsymbrowpilot*M;
+ acohpsk.coarse_mem = zeros(1,acohpsk.Ncm);
+ acohpsk.Ndft = 2^(ceil(log2(acohpsk.Ncm)));
+
+ ch_fdm_frame_buf = zeros(1, Nsw*acohpsk.Nsymbrowpilot*M);
+
+ frames = sim_in.frames;
+ EsNodB = sim_in.EsNodB;
+ foff = sim_in.foff;
+ dfoff = sim_in.dfoff;
+ fading_en = sim_in.fading_en;
+
+ EsNo = 10^(EsNodB/10);
+ hf_delay_ms = 2;
+ phase_ch = 1;
+
+ rand('state',1);
+ tx_bits_coh = round(rand(1,framesize*10));
+ ptx_bits_coh = 1;
+ [spread spread_2ms hf_gain] = init_hf_model(Fs, frames*acohpsk.Nsymbrowpilot*afdmdv.M);
+
+ hf_n = 1;
+ nhfdelay = floor(hf_delay_ms*Fs/1000);
+ ch_fdm_delay = zeros(1, acohpsk.Nsymbrowpilot*M + nhfdelay);
+
+ sync = 0; next_sync = 1;
+ sync_start = 1;
+ freq_offset_log = [];
+ sync_time_log = [];
+ ch_fdm_frame_log = [];
+ ch_symb_log = [];
+ tx_fdm_frame_log = [];
+ ratio_log = [];
+
+ for f=1:frames
+
+ acohpsk.frame = f;
+
+ %
+ % Mod --------------------------------------------------------------------
+ %
+
+ tx_bits = tx_bits_coh(ptx_bits_coh:ptx_bits_coh+framesize-1);
+ ptx_bits_coh += framesize;
+ if ptx_bits_coh > length(tx_bits_coh)
+ ptx_bits_coh = 1;
+ end
+
+ [tx_symb tx_bits] = bits_to_qpsk_symbols(acohpsk, tx_bits, [], []);
+
+ tx_fdm_frame = [];
+ for r=1:acohpsk.Nsymbrowpilot
+ tx_onesymb = tx_symb(r,:);
+ [tx_baseband afdmdv] = tx_filter(afdmdv, tx_onesymb);
+ [tx_fdm afdmdv] = fdm_upconvert(afdmdv, tx_baseband);
+ tx_fdm_frame = [tx_fdm_frame tx_fdm];
+ end
+ tx_fdm_frame_log = [tx_fdm_frame_log tx_fdm_frame];
+
+ %
+ % Channel --------------------------------------------------------------------
+ %
+
+ ch_fdm_frame = zeros(1,acohpsk.Nsymbrowpilot*M);
+ for i=1:acohpsk.Nsymbrowpilot*M
+ foff_rect = exp(j*2*pi*foff/Fs);
+ foff += dfoff;
+ phase_ch *= foff_rect;
+ ch_fdm_frame(i) = tx_fdm_frame(i) * phase_ch;
+ end
+ phase_ch /= abs(phase_ch);
+
+ if fading_en
+ ch_fdm_delay(1:nhfdelay) = ch_fdm_delay(acohpsk.Nsymbrowpilot*M+1:nhfdelay+acohpsk.Nsymbrowpilot*M);
+ ch_fdm_delay(nhfdelay+1:nhfdelay+acohpsk.Nsymbrowpilot*M) = ch_fdm_frame;
+
+ for i=1:acohpsk.Nsymbrowpilot*M
+ ahf_model = hf_gain*(spread(hf_n)*ch_fdm_frame(i) + spread_2ms(hf_n)*ch_fdm_delay(i));
+ ch_fdm_frame(i) = ahf_model;
+ hf_n++;
+ end
+ end
+
+ % each carrier has power = 2, total power 2Nc, total symbol rate NcRs, noise BW B=Fs
+ % Es/No = (C/Rs)/(N/B), N = var = 2NcFs/NcRs(Es/No) = 2Fs/Rs(Es/No)
+
+ variance = 2*Fs/(acohpsk.Rs*EsNo);
+ uvnoise = sqrt(0.5)*(randn(1,acohpsk.Nsymbrowpilot*M) + j*randn(1,acohpsk.Nsymbrowpilot*M));
+ noise = sqrt(variance)*uvnoise;
+
+ ch_fdm_frame += noise;
+ ch_fdm_frame_log = [ch_fdm_frame_log ch_fdm_frame];
+
+ %
+ % Try to achieve sync --------------------------------------------------------------------
+ %
+
+ % store Nsw frames so we can rewind if we get a good candidate
+
+ ch_fdm_frame_buf(1:(Nsw-1)*acohpsk.Nsymbrowpilot*M) = ch_fdm_frame_buf(acohpsk.Nsymbrowpilot*M+1:Nsw*acohpsk.Nsymbrowpilot*M);
+ ch_fdm_frame_buf((Nsw-1)*acohpsk.Nsymbrowpilot*M+1:Nsw*acohpsk.Nsymbrowpilot*M) = ch_fdm_frame;
+
+ next_sync = sync;
+ sync = 0;
+
+ if sync == 0
+
+ % we can test +/- 20Hz, so we break this up into 3 tests to cover +/- 60Hz
+
+ max_ratio = 0;
+ for acohpsk.f_est = Fcentre-40:40:Fcentre+40
+ %for acohpsk.f_est = Fcentre
+
+ printf(" [%d] acohpsk.f_est: %f +/- 20\n", f, acohpsk.f_est);
+ [ch_symb rx_timing rx_filt rx_baseband afdmdv acohpsk.f_est ] = rate_Fs_rx_processing(afdmdv, ch_fdm_frame_buf, acohpsk.f_est, Nsw*acohpsk.Nsymbrowpilot, nin, 0);
+
+ % coarse timing (frame sync) and initial fine freq est ---------------------------------------------
+
+ for i=1:Nsw-1
+ acohpsk.ct_symb_buf = update_ct_symb_buf(acohpsk.ct_symb_buf, ch_symb((i-1)*acohpsk.Nsymbrowpilot+1:i*acohpsk.Nsymbrowpilot,:), acohpsk.Nct_sym_buf, acohpsk.Nsymbrowpilot);
+ end
+ [anext_sync acohpsk] = frame_sync_fine_freq_est(acohpsk, ch_symb((Nsw-1)*acohpsk.Nsymbrowpilot+1:Nsw*acohpsk.Nsymbrowpilot,:), sync, next_sync);
+
+ if anext_sync == 1
+ printf(" [%d] acohpsk.ratio: %f\n", f, acohpsk.ratio);
+ if acohpsk.ratio > max_ratio
+ max_ratio = acohpsk.ratio;
+ f_est = acohpsk.f_est - acohpsk.f_fine_est;
+ next_sync = anext_sync;
+ end
+ end
+ end
+ end
+
+ % we've found a sync candidate
+
+ if (next_sync == 1)
+
+ % rewind and re-process last few frames with f_est
+
+ acohpsk.f_est = f_est;
+ printf(" [%d] trying sync and f_est: %f\n", f, acohpsk.f_est);
+ [ch_symb rx_timing rx_filt rx_baseband afdmdv acohpsk.f_est] = rate_Fs_rx_processing(afdmdv, ch_fdm_frame_buf, acohpsk.f_est, Nsw*acohpsk.Nsymbrowpilot, nin, 0);
+ ch_symb_log = ch_symb;
+ for i=1:Nsw-1
+ acohpsk.ct_symb_buf = update_ct_symb_buf(acohpsk.ct_symb_buf, ch_symb((i-1)*acohpsk.Nsymbrowpilot+1:i*acohpsk.Nsymbrowpilot,:), acohpsk.Nct_sym_buf, acohpsk.Nsymbrowpilot);
+ end
+ [next_sync acohpsk] = frame_sync_fine_freq_est(acohpsk, ch_symb((Nsw-1)*acohpsk.Nsymbrowpilot+1:Nsw*acohpsk.Nsymbrowpilot,:), sync, next_sync);
+ if abs(acohpsk.f_fine_est) > 2
+ printf(" [%d] Hmm %f is a bit big so back to coarse est ...\n", f, acohpsk.f_fine_est);
+ next_sync = 0;
+ end
+
+ % candidate checks out so log stats
+
+ if (next_sync == 1)
+ printf(" [%d] in sync!\n", f);
+ freq_offset_log = [freq_offset_log Fcentre+foff-acohpsk.f_est];
+ sync_time_log = [sync_time_log f-sync_start];
+ ratio_log = [ratio_log max_ratio];
+ next_sync = 0; sync_start = f;
+ end
+ end
+
+ %printf("f: %d sync: %d next_sync: %d\n", f, sync, next_sync);
+ [sync acohpsk] = sync_state_machine(acohpsk, sync, next_sync);
+
+ end
+
+ % ftx=fopen("coarse_tx.raw","wb"); fwrite(ftx, 1000*ch_fdm_frame_log, "short"); fclose(ftx);
+
+ sim_out.freq_offset_log = freq_offset_log;
+ sim_out.sync_time_log = sync_time_log;
+ sim_out.ch_fdm_frame_log = ch_fdm_frame_log;
+ sim_out.ch_symb_log = ch_symb_log;
+ sim_out.tx_fdm_frame_log = tx_fdm_frame_log;
+ sim_out.ratio_log = ratio_log;
+endfunction
+
+
+function freq_off_est_test_single
+ sim_in.frames = 5;
+ sim_in.EsNodB = 120;
+ sim_in.foff = 0;
+ sim_in.dfoff = 0;
+ sim_in.fading_en = 0;
+
+ sim_out = freq_off_est_test(sim_in);
+
+ figure(1)
+ subplot(211)
+ plot(sim_out.freq_offset_log)
+ ylabel('f est error')
+ xlabel('time')
+
+ subplot(212)
+ if length(sim_out.freq_offset_log) > 0
+ hist(sim_out.freq_offset_log)
+ xlabel('f est error')
+ ylabel('histogram');
+ end
+
+ figure(2)
+ subplot(211)
+ plot(sim_out.sync_time_log)
+ ylabel('time to sync (frames)')
+ subplot(212)
+ if length(sim_out.sync_time_log) > 0
+ hist(sim_out.sync_time_log)
+ xlabel('time to sync (frames)')
+ ylabel('histogram')
+ end
+
+ figure(3)
+ subplot(211)
+ plot(real(sim_out.tx_fdm_frame_log(1:2*960)))
+ grid;
+ subplot(212)
+ plot(real(sim_out.ch_symb_log),'+')
+ grid;
+
+ figure(4)
+ clf;
+ plot(sim_out.ch_symb_log,'+')
+
+ figure(5)
+ clf;
+ plot(sim_out.ratio_log)
+ xlabel('time')
+ ylabel('ratio for sync')
+endfunction
+
+
+function [freq_off_log EsNodBSet] = freq_off_est_test_curves
+ EsNodBSet = [20 12 8];
+
+ sim_in.frames = 100;
+ sim_in.foff = -40;
+ sim_in.dfoff = 0;
+ sim_in.fading_en = 1;
+ freq_off_log = 1E6*ones(sim_in.frames, length(EsNodBSet) );
+ sync_time_log = 1E6*ones(sim_in.frames, length(EsNodBSet) );
+
+ for i=1:length(EsNodBSet)
+ sim_in.EsNodB = EsNodBSet(i);
+ printf("%f\n", sim_in.EsNodB);
+
+ sim_out = freq_off_est_test(sim_in);
+ freq_off_log(1:length(sim_out.freq_offset_log),i) = sim_out.freq_offset_log;
+ sync_time_log(1:length(sim_out.sync_time_log),i) = sim_out.sync_time_log;
+ end
+
+ figure(1)
+ clf
+ hold on;
+ for i=1:length(EsNodBSet)
+ data = freq_off_log(find(freq_off_log(:,i) < 1E6),i);
+ s = std(data);
+ m = mean(data);
+ stdbar = [m-s; m+s];
+ plot(EsNodBSet(i), data, '+')
+ plot([EsNodBSet(i) EsNodBSet(i)]+0.5, stdbar,'+-')
+ end
+ hold off
+
+ axis([6 22 -25 25])
+ if sim_in.fading_en
+ title_str = sprintf('foff = %d Hz Fading', sim_in.foff);
+ else
+ title_str = sprintf('foff = %d Hz AWGN', sim_in.foff);
+ end
+ title(title_str);
+ xlabel('Es/No (dB)')
+ ylabel('freq offset error (Hz)');
+
+ figure(2)
+ clf
+ hold on;
+ for i=1:length(EsNodBSet)
+ leg = sprintf("%d;%d dB;", i, EsNodBSet(i));
+ plot(freq_off_log(find(freq_off_log(:,i) < 1E6),i),leg)
+ end
+ hold off;
+ title(title_str);
+ xlabel('test');
+ ylabel('freq offset error (Hz)');
+ legend('boxoff');
+
+ figure(3)
+ clf
+ hold on;
+ for i=1:length(EsNodBSet)
+ data = sync_time_log(find(sync_time_log(:,i) < 1E6),i);
+ if length(data)
+ s = std(data);
+ m = mean(data);
+ stdbar = [m-s; m+s];
+ plot(EsNodBSet(i), data, '+')
+ plot([EsNodBSet(i) EsNodBSet(i)]+0.5, stdbar,'+-')
+ end
+ end
+ hold off;
+ axis([6 22 0 10])
+ ylabel('sync time (frames)')
+ xlabel('Es/No (dB)');
+ title(title_str);
+
+ figure(4)
+ clf
+ hold on;
+ for i=1:length(EsNodBSet)
+ leg = sprintf("%d;%d dB;", i, EsNodBSet(i));
+ plot(sync_time_log(find(sync_time_log(:,i) < 1E6),i),leg)
+ end
+ hold off;
+ title(title_str);
+ xlabel('test');
+ ylabel('sync time (frames)');
+ legend('boxoff');
+
+endfunction
+
+
+% select on of these to run:
+
+freq_off_est_test_single;
+%freq_off_est_test_curves;
+
-% test_qpsk.m\r
-% David Rowe Feb 2014\r
-%\r
-% QPSK modem simulation, initially based on code by Bill Cowley\r
-% Generates curves BER versus E/No curves for different modems.\r
-% Design to test coherent demodulation ideas on HF channels without\r
-% building a full blown modem. Uses 'genie provided' estimates for\r
-% timing estimation, frame sync.\r
-%\r
-\r
-1;\r
-\r
-% main test function \r
-\r
-function sim_out = ber_test(sim_in, modulation)\r
- Fs = 8000;\r
-\r
- verbose = sim_in.verbose;\r
- framesize = sim_in.framesize;\r
- Ntrials = sim_in.Ntrials;\r
- Esvec = sim_in.Esvec;\r
- phase_offset = sim_in.phase_offset;\r
- phase_est = sim_in.phase_est;\r
- w_offset = sim_in.w_offset;\r
- plot_scatter = sim_in.plot_scatter;\r
- Rs = sim_in.Rs;\r
- hf_sim = sim_in.hf_sim;\r
- Nhfdelay = floor(sim_in.hf_delay_ms*1000/Fs);\r
- hf_phase_only = sim_in.hf_phase_only;\r
- hf_mag_only = sim_in.hf_mag_only;\r
-\r
- bps = 2;\r
- Nsymb = framesize/bps;\r
- prev_sym_tx = qpsk_mod([0 0]);\r
- prev_sym_rx = qpsk_mod([0 0]);\r
- rx_symb_log = [];\r
-\r
- Np = sim_in.Np; % number of pilot symbols to use in phase est\r
- Ns = sim_in.Ns; % spacing of pilot symbols, so (Nps-1) data symbols between every pilot\r
- Nps = Np*Ns;\r
- r_delay_line = zeros(1,Nps+1);\r
- s_delay_line = zeros(1,Nps+1);\r
- spread_main_phi = 0;\r
- spread_delay_phi = 0;\r
- spread_main_phi_log = [];\r
-\r
- ldpc_code = sim_in.ldpc_code;\r
-\r
- if ldpc_code\r
- % Start CML library\r
-\r
- currentdir = pwd;\r
- addpath '/home/david/tmp/cml/mat' % assume the source files stored here\r
- cd /home/david/tmp/cml\r
- CmlStartup % note that this is not in the cml path!\r
- cd(currentdir)\r
- \r
- % Our LDPC library\r
-\r
- ldpc;\r
-\r
- rate = 3/4; \r
- mod_order = 4; \r
- modulation = 'QPSK';\r
- mapping = 'gray';\r
-\r
- demod_type = 0;\r
- decoder_type = 0;\r
- max_iterations = 100;\r
-\r
- code_param = ldpc_init(rate, framesize, modulation, mod_order, mapping);\r
- code_param.code_bits_per_frame = framesize;\r
- code_param.symbols_per_frame = framesize/bps;\r
- else\r
- rate = 1;\r
- end\r
-\r
- % convert "spreading" samples from 1kHz carrier at Fs to complex\r
- % baseband, generated by passing a 1kHz sine wave through PathSim\r
- % with the ccir-poor model, enabling one path at a time.\r
- \r
- Fc = 1000;\r
- fspread = fopen("../raw/sine1k_2Hz_spread.raw","rb");\r
- spread1k = fread(fspread, "int16")/10000;\r
- fclose(fspread);\r
- fspread = fopen("../raw/sine1k_2ms_delay_2Hz_spread.raw","rb");\r
- spread1k_2ms = fread(fspread, "int16")/10000;\r
- fclose(fspread);\r
-\r
- % down convert to complex baseband\r
- spreadbb = spread1k.*exp(-j*(2*pi*Fc/Fs)*(1:length(spread1k))');\r
- spreadbb_2ms = spread1k_2ms.*exp(-j*(2*pi*Fc/Fs)*(1:length(spread1k_2ms))');\r
-\r
- % remove -2000 Hz image\r
- b = fir1(50, 5/Fs);\r
- spread = filter(b,1,spreadbb);\r
- spread_2ms = filter(b,1,spreadbb_2ms);\r
-\r
- % discard first 1000 samples as these were near 0, probably as\r
- % PathSim states were ramping up\r
-\r
- spread = spread(1000:length(spread));\r
- spread_2ms = spread_2ms(1000:length(spread_2ms));\r
-\r
- % Determine "gain" of HF channel model, so we can normalise\r
- % carrier power during HF channel sim to calibrate SNR. I imagine\r
- % different implementations of ccir-poor would do this in\r
- % different ways, leading to different BER results. Oh Well!\r
-\r
- hf_gain = 1.0/sqrt(var(spread)+var(spread_2ms));\r
-\r
- % design root nyquist (root raised cosine) filter and init tx and rx filter states\r
-\r
- alpha = 0.5; T=1/Fs; Nfiltsym=7; M=Fs/Rs;\r
- if floor(Fs/Rs) != Fs/Rs\r
- printf("oversampling ratio must be an integer\n");\r
- return;\r
- end\r
- hrn = gen_rn_coeffs(alpha, T, Rs, Nfiltsym, M);\r
- Nfilter = length(hrn);\r
- tx_filter_memory = zeros(1, Nfilter);\r
- rx_filter_memory = zeros(1, Nfilter);\r
- s_delay_line_filt = zeros(1,Nfiltsym);\r
- tx_bits_delay_line_filt = zeros(1,Nfiltsym*bps);\r
- hf_sim_delay_line = zeros(1,M+Nhfdelay);\r
-\r
- for ne = 1:length(Esvec)\r
- Es = Esvec(ne);\r
- EsNo = 10^(Es/10);\r
- \r
- % Given Es/No, determine the variance of a normal noise source:\r
- %\r
- % Es = C/Rs where C is carrier power (energy per unit time) and Rs is the symbole rate\r
- % N = NoB where N is the total noise power, No is the Noise spectral density is W/Hz\r
- % and B is the bandwidth of the noise which is Fs\r
- % No = N/Fs\r
- %\r
- % equating Es/No we get:\r
- %\r
- % Es/No = (C/Rs)/(No/Fs)\r
- % No = CFs/(Rs(Es/No))\r
-\r
- variance = Fs/(Rs*EsNo);\r
- Terrs = 0; Tbits = 0; Terrsldpc = 0; Tbitsldpc = 0; Ferrsldpc = 0;\r
- if verbose > 1\r
- printf("EsNo (dB): %f EsNo: %f variance: %f\n", Es, EsNo, variance);\r
- end\r
- \r
- % init HF channel\r
- sc = 1;\r
-\r
- tx_filt_log = [];\r
- rx_filt_log = [];\r
- rx_baseband_log = [];\r
- tx_baseband_log = [];\r
- noise_log = [];\r
- hf_angle_log = [];\r
- tx_phase = rx_phase = 0;\r
- tx_data_buffer = zeros(1,2*framesize);\r
- s_data_buffer = zeros(1,2*Nsymb);\r
- C_log = [];\r
-\r
- for nn = 1: Ntrials\r
- \r
- tx_bits = round( rand( 1, framesize*rate ) );\r
- %tx_bits = [1 0 zeros(1,framesize*rate-2)];\r
-\r
- % modulate\r
-\r
- if ldpc_code\r
- [tx_bits, s] = ldpc_enc(tx_bits, code_param);\r
- t2 = tx_bits;\r
- s2 = s;\r
- else\r
- s = zeros(1, Nsymb);\r
- for i=1:Nsymb\r
- tx_symb = qpsk_mod(tx_bits(2*(i-1)+1:2*i));\r
- %printf("shift: %f prev_sym: %f ", tx_symb, prev_sym_tx);\r
- if strcmp(modulation,'dqpsk')\r
- tx_symb *= prev_sym_tx;\r
- %printf("tx_symb: %f\n", tx_symb);\r
- prev_sym_tx = tx_symb;\r
- end \r
- s(i) = tx_symb;\r
- end\r
- end\r
- s_ch = s;\r
-\r
- % root nyquist filter symbols\r
-\r
- for k=1:Nsymb\r
-\r
- % tx filter symbols\r
-\r
- tx_filt = zeros(1,M);\r
-\r
- % tx filter each symbol, generate M filtered output samples for each symbol.\r
- % Efficient polyphase filter techniques used as tx_filter_memory is sparse\r
-\r
- tx_filter_memory(Nfilter) = s_ch(k);\r
-\r
- for i=1:M\r
- tx_filt(i) = M*tx_filter_memory(M:M:Nfilter) * hrn(M-i+1:M:Nfilter)';\r
- end\r
- tx_filter_memory(1:Nfilter-M) = tx_filter_memory(M+1:Nfilter);\r
- tx_filter_memory(Nfilter-M+1:Nfilter) = zeros(1,M);\r
- \r
- % HF channel simulation\r
-\r
- if hf_sim\r
-\r
- hf_sim_delay_line(1:Nhfdelay) = hf_sim_delay_line(M+1:M+Nhfdelay);\r
- hf_sim_delay_line(Nhfdelay+1:M+Nhfdelay) = tx_filt;\r
-\r
- % disable as a wrap around will cause a nasty phase jump. Best to generate\r
- % longer files\r
- %if ((sc+M) > length(spread)) || ((sc+M) > length(spread_2ms))\r
- % sc =1 ;\r
- %end\r
- comb = conj(spread(sc:sc+M-1))' + conj(spread_2ms(sc:sc+M-1))';\r
- if hf_phase_only\r
- tx_filt = tx_filt.*exp(j*angle(comb));\r
- else\r
- if hf_mag_only\r
- comb = conj(spread(sc:sc+M-1))' + conj(spread_2ms(sc:sc+M-1))';\r
- tx_filt = tx_filt.*abs(comb); \r
- else\r
- % regular HF channel sim\r
- tx_filt = tx_filt.*conj(spread(sc:sc+M-1))' + hf_sim_delay_line(1:M).*conj(spread_2ms(sc:sc+M-1))';\r
- end\r
- end\r
- sc += M;\r
- \r
- % normalise so average HF power C=1\r
-\r
- if hf_phase_only == 0 % C already 1 if we are just tweaking phase\r
- tx_filt *= hf_gain;\r
- end\r
- C_log = [C_log abs(comb)*hf_gain];\r
- end\r
- tx_filt_log = [tx_filt_log tx_filt];\r
- hf_angle_log = [hf_angle_log angle(comb)];\r
-\r
- % AWGN noise and phase/freq offset channel simulation\r
- % 0.5 factor ensures var(noise) == variance , i.e. splits power between Re & Im\r
-\r
- noise = sqrt(variance*0.5)*( randn(1,M) + j*randn(1,M) );\r
- noise_log = [noise_log noise];\r
- rx_baseband = tx_filt.*exp(j*phase_offset) + noise;\r
- phase_offset += w_offset;\r
- \r
- % rx filter symbol\r
-\r
- rx_filter_memory(Nfilter-M+1:Nfilter) = rx_baseband;\r
- rx_filt = rx_filter_memory * hrn';\r
- rx_filter_memory(1:Nfilter-M) = rx_filter_memory(1+M:Nfilter);\r
- rx_filt_log = [rx_filt_log rx_filt];\r
-\r
- % delay in tx symbols to compensate for filtering\r
- % delay, as tx symbols are used as pilot symbols input\r
- % to phase est\r
-\r
- s_delay_line_filt(1:Nfiltsym-1) = s_delay_line_filt(2:Nfiltsym);\r
- s_delay_line_filt(Nfiltsym) = s(k);\r
- s(k) = s_delay_line_filt(1); \r
-\r
- % delay in tx bits to compensate for filtering delay\r
-\r
- tx_bits_delay_line_filt(1:(Nfiltsym-1)*bps) = tx_bits_delay_line_filt(bps+1:Nfiltsym*bps);\r
- tx_bits_delay_line_filt((Nfiltsym-1)*bps+1:Nfiltsym*bps) = tx_bits((k-1)*bps+1:k*bps);\r
- tx_bits((k-1)*bps+1:k*bps) = tx_bits_delay_line_filt(1:bps);\r
-\r
- s_ch(k) = rx_filt; \r
- end\r
-\r
- % coherent demod phase estimation and correction using pilot symbols\r
- % cheating a bit here, we use fact that all tx-ed symbols are known\r
-\r
- if phase_est\r
- for i=1:Nsymb\r
-\r
- % delay line for phase est window\r
-\r
- r_delay_line(1:Nps-1) = r_delay_line(2:Nps);\r
- r_delay_line(Nps) = s_ch(i);\r
-\r
- % delay in tx data to compensate data for phase est window\r
-\r
- s_delay_line(1:Nps-1) = s_delay_line(2:Nps);\r
- s_delay_line(Nps) = s(i);\r
- tx_bits(2*(i-1)+1:2*i) = qpsk_demod(s_delay_line(floor(Nps/2)+1));\r
-\r
- % estimate phase from surrounding known pilot symbols and correct\r
-\r
- corr = 0; centre = floor(Nps/2)+1;\r
- for k=1:Ns:(Nps+1)\r
- if (k != centre)\r
- corr += s_delay_line(k) * r_delay_line(k)';\r
- end\r
- end\r
- s_ch(i) = r_delay_line(centre).*exp(j*angle(corr));\r
- end \r
- %printf("corr: %f angle: %f\n", corr, angle(corr));\r
- end\r
-\r
- % de-modulate\r
-\r
- rx_bits = zeros(1, framesize);\r
- for i=1:Nsymb\r
- rx_symb = s_ch(i);\r
- if strcmp(modulation,'dqpsk')\r
- tmp = rx_symb;\r
- rx_symb *= conj(prev_sym_rx/abs(prev_sym_rx));\r
- prev_sym_rx = tmp;\r
- end\r
- rx_bits((2*(i-1)+1):(2*i)) = qpsk_demod(rx_symb);\r
- rx_symb_log = [rx_symb_log rx_symb];\r
- end\r
-\r
- % Measure BER\r
-\r
- % discard bits from first 2*Nfiltsym+Nps+1 symbols as tx\r
- % and rx filter and phase est memories not full\r
-\r
- skip = bps*(2*Nfiltsym+1+Nps+1);\r
- if nn == 1\r
- tx_bits_tmp = tx_bits(skip:length(tx_bits));\r
- rx_bits_tmp = rx_bits(skip:length(rx_bits));\r
- else\r
- tx_bits_tmp = tx_bits;\r
- rx_bits_tmp = rx_bits;\r
- end\r
-\r
- error_positions = xor( rx_bits_tmp, tx_bits_tmp );\r
- Nerrs = sum(error_positions);\r
- Terrs += Nerrs;\r
- Tbits += length(tx_bits_tmp);\r
-\r
- % Optionally LDPC decode\r
- \r
- if ldpc_code\r
- % filter memories etc screw up frame alignment so we need to buffer a frame\r
-\r
- tx_data_buffer(1:framesize) = tx_data_buffer(framesize+1:2*framesize);\r
- s_data_buffer(1:Nsymb) = s_data_buffer(Nsymb+1:2*Nsymb);\r
- tx_data_buffer(framesize+1:2*framesize) = tx_bits;\r
- s_data_buffer(Nsymb+1:2*Nsymb) = s_ch;\r
-\r
- offset = Nfiltsym-1;\r
- if (phase_est)\r
- offset += floor(Nps/2);\r
- end\r
- st_tx = offset*bps+1;\r
- st_s = offset;\r
-\r
- detected_data = ldpc_dec(code_param, max_iterations, demod_type, decoder_type, ...\r
- s_data_buffer(st_s+1:st_s+Nsymb), min(100,EsNo));\r
-\r
- % ignore first frame as filter, phase est memories filling up\r
- if nn != 1\r
- error_positions = xor( detected_data(1:framesize*rate), ...\r
- tx_data_buffer(st_tx:st_tx+framesize*rate-1) );\r
- Nerrs = sum(error_positions);\r
- if Nerrs\r
- Ferrsldpc++;\r
- end\r
- Terrsldpc += Nerrs;\r
- Tbitsldpc += framesize*rate;\r
- end\r
- end\r
-\r
- end\r
- \r
- TERvec(ne) = Terrs;\r
- BERvec(ne) = Terrs/Tbits;\r
- if ldpc_code\r
- TERldpcvec(ne) = Terrsldpc;\r
- FERldpcvec(ne) = Ferrsldpc;\r
- BERldpcvec(ne) = Terrsldpc/Tbitsldpc;\r
- end\r
-\r
- if verbose \r
- printf("EsNo (dB): %f Terrs: %d BER %f BER theory %f", Es, Terrs,\r
- Terrs/Tbits, 0.5*erfc(sqrt(EsNo/2)));\r
- if ldpc_code\r
- printf(" LDPC: Terrs: %d BER: %f Ferrs: %d FER: %f", \r
- Terrsldpc, Terrsldpc/Tbitsldpc, Ferrsldpc, Ferrsldpc/(Ntrials-1));\r
- end\r
- printf("\n");\r
- end\r
- if verbose > 1\r
- printf("Terrs: %d BER %f BER theory %f C %f N %f Es %f No %f Es/No %f\n\n", Terrs,\r
- Terrs/Tbits, 0.5*erfc(sqrt(EsNo/2)), var(tx_filt_log), var(noise_log),\r
- var(tx_filt_log)/Rs, var(noise_log)/Fs, (var(tx_filt_log)/Rs)/(var(noise_log)/Fs));\r
- end\r
- end\r
- \r
- Ebvec = Esvec - 10*log10(bps);\r
- sim_out.BERvec = BERvec;\r
- sim_out.Ebvec = Ebvec;\r
- sim_out.TERvec = TERvec;\r
- if ldpc_code\r
- sim_out.BERldpcvec = BERldpcvec;\r
- sim_out.TERldpcvec = TERldpcvec;\r
- sim_out.FERldpcvec = FERldpcvec;\r
- end\r
-\r
- if plot_scatter\r
- figure(2);\r
- clf;\r
- scat = rx_symb_log(2*Nfiltsym:length(rx_symb_log)) .* exp(j*pi/4);\r
- plot(real(scat), imag(scat),'+');\r
-\r
- figure(3);\r
- clf;\r
-\r
- subplot(211)\r
- plot(C_log);\r
- subplot(212)\r
- plot(hf_angle_log);\r
- axis([1 10000 min(hf_angle_log) max(hf_angle_log)])\r
- end\r
-endfunction\r
-\r
-% Gray coded QPSK modulation function\r
-\r
-function symbol = qpsk_mod(two_bits)\r
- two_bits_decimal = sum(two_bits .* [2 1]); \r
- switch(two_bits_decimal)\r
- case (0) symbol = 1;\r
- case (1) symbol = j;\r
- case (2) symbol = -j;\r
- case (3) symbol = -1;\r
- endswitch\r
-endfunction\r
-\r
-% Gray coded QPSK demodulation function\r
-\r
-function two_bits = qpsk_demod(symbol)\r
- if isscalar(symbol) == 0\r
- printf("only works with scalars\n");\r
- return;\r
- end\r
- bit0 = real(symbol*exp(j*pi/4)) < 0;\r
- bit1 = imag(symbol*exp(j*pi/4)) < 0;\r
- two_bits = [bit1 bit0];\r
-endfunction\r
-\r
-% Start simulations ---------------------------------------\r
-\r
-more off;\r
-sim_in.verbose = 2;\r
-\r
-sim_in.Esvec = 5; \r
-sim_in.Ntrials = 100;\r
-sim_in.framesize = 100;\r
-sim_in.Rs = 400;\r
-sim_in.phase_offset = 0;\r
-sim_in.phase_est = 0;\r
-sim_in.w_offset = 0;\r
-sim_in.plot_scatter = 1;\r
-sim_in.hf_delay_ms = 2;\r
-sim_in.hf_sim = 1;\r
-sim_in.Np = 6;\r
-sim_in.Ns = 5;\r
-sim_in.hf_phase_only = 0;\r
-sim_in.hf_mag_only = 1;\r
-sim_in.ldpc_code = 0;\r
-\r
-Ebvec = sim_in.Esvec - 10*log10(2);\r
-BER_theory = 0.5*erfc(sqrt(10.^(Ebvec/10)));\r
-\r
-sim_qpsk = ber_test(sim_in, 'qpsk');\r
-\r
-figure(1); \r
-clf;\r
-semilogy(Ebvec, BER_theory,'r;QPSK theory;')\r
-hold on;\r
-semilogy(sim_qpsk.Ebvec, sim_qpsk.BERvec,'g;QPSK;')\r
-hold off;\r
-xlabel('Eb/N0')\r
-ylabel('BER')\r
-grid("minor")\r
-\r
-\r
-if 0\r
-sim_in.hf_mag_only = 1;\r
-sim_qpsk_mag = ber_test(sim_in, 'qpsk');\r
-\r
-sim_in.hf_mag_only = 0;\r
-sim_in.hf_phase_only = 1;\r
-sim_in.phase_est = 1;\r
-sim_qpsk_phase = ber_test(sim_in, 'qpsk');\r
-\r
-sim_in.hf_phase_only = 0;\r
-sim_qpsk_coh_6_5 = ber_test(sim_in, 'qpsk');\r
-\r
-sim_in.phase_est = 0;\r
-sim_dqpsk = ber_test(sim_in, 'dqpsk');\r
-\r
-figure(1); \r
-clf;\r
-semilogy(Ebvec, BER_theory,'r;QPSK theory;')\r
-hold on;\r
-semilogy(sim_qpsk_mag.Ebvec, sim_qpsk_mag.BERvec,'g;QPSK CCIR poor mag;')\r
-semilogy(sim_qpsk_phase.Ebvec, sim_qpsk_phase.BERvec,'k;QPSK CCIR poor phase;')\r
-semilogy(sim_qpsk_coh_6_5.Ebvec, sim_qpsk_coh_6_5.BERvec,'c;QPSK CCIR poor Np=6 Ns=5;')\r
-semilogy(sim_dqpsk.Ebvec, sim_dqpsk.BERvec,'b;DQPSK CCIR poor;')\r
-%semilogy(sim_qpsk_coh_5_24.Ebvec, sim_qpsk_coh_5_24.BERvec,'k;QPSK Ns=5 Np=24;')\r
-%semilogy(sim_qpsk_coh_2_12.Ebvec, sim_qpsk_coh_2_12.BERvec,'c;QPSK Ns=2 Np=12;')\r
-hold off;\r
-xlabel('Eb/N0')\r
-ylabel('BER')\r
-grid("minor")\r
-axis([min(Ebvec)-1 max(Ebvec)+1 1E-2 1])\r
-end\r
+% test_qpsk.m
+% David Rowe Feb 2014
+%
+% QPSK modem simulation, initially based on code by Bill Cowley
+% Generates curves BER versus E/No curves for different modems.
+% Design to test coherent demodulation ideas on HF channels without
+% building a full blown modem. Uses 'genie provided' estimates for
+% timing estimation, frame sync.
+%
+
+1;
+
+% main test function
+
+function sim_out = ber_test(sim_in, modulation)
+ Fs = 8000;
+
+ verbose = sim_in.verbose;
+ framesize = sim_in.framesize;
+ Ntrials = sim_in.Ntrials;
+ Esvec = sim_in.Esvec;
+ phase_offset = sim_in.phase_offset;
+ phase_est = sim_in.phase_est;
+ w_offset = sim_in.w_offset;
+ plot_scatter = sim_in.plot_scatter;
+ Rs = sim_in.Rs;
+ hf_sim = sim_in.hf_sim;
+ Nhfdelay = floor(sim_in.hf_delay_ms*1000/Fs);
+ hf_phase_only = sim_in.hf_phase_only;
+ hf_mag_only = sim_in.hf_mag_only;
+
+ bps = 2;
+ Nsymb = framesize/bps;
+ prev_sym_tx = qpsk_mod([0 0]);
+ prev_sym_rx = qpsk_mod([0 0]);
+ rx_symb_log = [];
+
+ Np = sim_in.Np; % number of pilot symbols to use in phase est
+ Ns = sim_in.Ns; % spacing of pilot symbols, so (Nps-1) data symbols between every pilot
+ Nps = Np*Ns;
+ r_delay_line = zeros(1,Nps+1);
+ s_delay_line = zeros(1,Nps+1);
+ spread_main_phi = 0;
+ spread_delay_phi = 0;
+ spread_main_phi_log = [];
+
+ ldpc_code = sim_in.ldpc_code;
+
+ if ldpc_code
+ % Start CML library
+
+ currentdir = pwd;
+ addpath '/home/david/tmp/cml/mat' % assume the source files stored here
+ cd /home/david/tmp/cml
+ CmlStartup % note that this is not in the cml path!
+ cd(currentdir)
+
+ % Our LDPC library
+
+ ldpc;
+
+ rate = 3/4;
+ mod_order = 4;
+ modulation = 'QPSK';
+ mapping = 'gray';
+
+ demod_type = 0;
+ decoder_type = 0;
+ max_iterations = 100;
+
+ code_param = ldpc_init(rate, framesize, modulation, mod_order, mapping);
+ code_param.code_bits_per_frame = framesize;
+ code_param.symbols_per_frame = framesize/bps;
+ else
+ rate = 1;
+ end
+
+ % convert "spreading" samples from 1kHz carrier at Fs to complex
+ % baseband, generated by passing a 1kHz sine wave through PathSim
+ % with the ccir-poor model, enabling one path at a time.
+
+ Fc = 1000;
+ fspread = fopen("../raw/sine1k_2Hz_spread.raw","rb");
+ spread1k = fread(fspread, "int16")/10000;
+ fclose(fspread);
+ fspread = fopen("../raw/sine1k_2ms_delay_2Hz_spread.raw","rb");
+ spread1k_2ms = fread(fspread, "int16")/10000;
+ fclose(fspread);
+
+ % down convert to complex baseband
+ spreadbb = spread1k.*exp(-j*(2*pi*Fc/Fs)*(1:length(spread1k))');
+ spreadbb_2ms = spread1k_2ms.*exp(-j*(2*pi*Fc/Fs)*(1:length(spread1k_2ms))');
+
+ % remove -2000 Hz image
+ b = fir1(50, 5/Fs);
+ spread = filter(b,1,spreadbb);
+ spread_2ms = filter(b,1,spreadbb_2ms);
+
+ % discard first 1000 samples as these were near 0, probably as
+ % PathSim states were ramping up
+
+ spread = spread(1000:length(spread));
+ spread_2ms = spread_2ms(1000:length(spread_2ms));
+
+ % Determine "gain" of HF channel model, so we can normalise
+ % carrier power during HF channel sim to calibrate SNR. I imagine
+ % different implementations of ccir-poor would do this in
+ % different ways, leading to different BER results. Oh Well!
+
+ hf_gain = 1.0/sqrt(var(spread)+var(spread_2ms));
+
+ % design root nyquist (root raised cosine) filter and init tx and rx filter states
+
+ alpha = 0.5; T=1/Fs; Nfiltsym=7; M=Fs/Rs;
+ if floor(Fs/Rs) != Fs/Rs
+ printf("oversampling ratio must be an integer\n");
+ return;
+ end
+ hrn = gen_rn_coeffs(alpha, T, Rs, Nfiltsym, M);
+ Nfilter = length(hrn);
+ tx_filter_memory = zeros(1, Nfilter);
+ rx_filter_memory = zeros(1, Nfilter);
+ s_delay_line_filt = zeros(1,Nfiltsym);
+ tx_bits_delay_line_filt = zeros(1,Nfiltsym*bps);
+ hf_sim_delay_line = zeros(1,M+Nhfdelay);
+
+ for ne = 1:length(Esvec)
+ Es = Esvec(ne);
+ EsNo = 10^(Es/10);
+
+ % Given Es/No, determine the variance of a normal noise source:
+ %
+ % Es = C/Rs where C is carrier power (energy per unit time) and Rs is the symbole rate
+ % N = NoB where N is the total noise power, No is the Noise spectral density is W/Hz
+ % and B is the bandwidth of the noise which is Fs
+ % No = N/Fs
+ %
+ % equating Es/No we get:
+ %
+ % Es/No = (C/Rs)/(No/Fs)
+ % No = CFs/(Rs(Es/No))
+
+ variance = Fs/(Rs*EsNo);
+ Terrs = 0; Tbits = 0; Terrsldpc = 0; Tbitsldpc = 0; Ferrsldpc = 0;
+ if verbose > 1
+ printf("EsNo (dB): %f EsNo: %f variance: %f\n", Es, EsNo, variance);
+ end
+
+ % init HF channel
+ sc = 1;
+
+ tx_filt_log = [];
+ rx_filt_log = [];
+ rx_baseband_log = [];
+ tx_baseband_log = [];
+ noise_log = [];
+ hf_angle_log = [];
+ tx_phase = rx_phase = 0;
+ tx_data_buffer = zeros(1,2*framesize);
+ s_data_buffer = zeros(1,2*Nsymb);
+ C_log = [];
+
+ for nn = 1: Ntrials
+
+ tx_bits = round( rand( 1, framesize*rate ) );
+ %tx_bits = [1 0 zeros(1,framesize*rate-2)];
+
+ % modulate
+
+ if ldpc_code
+ [tx_bits, s] = ldpc_enc(tx_bits, code_param);
+ t2 = tx_bits;
+ s2 = s;
+ else
+ s = zeros(1, Nsymb);
+ for i=1:Nsymb
+ tx_symb = qpsk_mod(tx_bits(2*(i-1)+1:2*i));
+ %printf("shift: %f prev_sym: %f ", tx_symb, prev_sym_tx);
+ if strcmp(modulation,'dqpsk')
+ tx_symb *= prev_sym_tx;
+ %printf("tx_symb: %f\n", tx_symb);
+ prev_sym_tx = tx_symb;
+ end
+ s(i) = tx_symb;
+ end
+ end
+ s_ch = s;
+
+ % root nyquist filter symbols
+
+ for k=1:Nsymb
+
+ % tx filter symbols
+
+ tx_filt = zeros(1,M);
+
+ % tx filter each symbol, generate M filtered output samples for each symbol.
+ % Efficient polyphase filter techniques used as tx_filter_memory is sparse
+
+ tx_filter_memory(Nfilter) = s_ch(k);
+
+ for i=1:M
+ tx_filt(i) = M*tx_filter_memory(M:M:Nfilter) * hrn(M-i+1:M:Nfilter)';
+ end
+ tx_filter_memory(1:Nfilter-M) = tx_filter_memory(M+1:Nfilter);
+ tx_filter_memory(Nfilter-M+1:Nfilter) = zeros(1,M);
+
+ % HF channel simulation
+
+ if hf_sim
+
+ hf_sim_delay_line(1:Nhfdelay) = hf_sim_delay_line(M+1:M+Nhfdelay);
+ hf_sim_delay_line(Nhfdelay+1:M+Nhfdelay) = tx_filt;
+
+ % disable as a wrap around will cause a nasty phase jump. Best to generate
+ % longer files
+ %if ((sc+M) > length(spread)) || ((sc+M) > length(spread_2ms))
+ % sc =1 ;
+ %end
+ comb = conj(spread(sc:sc+M-1))' + conj(spread_2ms(sc:sc+M-1))';
+ if hf_phase_only
+ tx_filt = tx_filt.*exp(j*angle(comb));
+ else
+ if hf_mag_only
+ comb = conj(spread(sc:sc+M-1))' + conj(spread_2ms(sc:sc+M-1))';
+ tx_filt = tx_filt.*abs(comb);
+ else
+ % regular HF channel sim
+ tx_filt = tx_filt.*conj(spread(sc:sc+M-1))' + hf_sim_delay_line(1:M).*conj(spread_2ms(sc:sc+M-1))';
+ end
+ end
+ sc += M;
+
+ % normalise so average HF power C=1
+
+ if hf_phase_only == 0 % C already 1 if we are just tweaking phase
+ tx_filt *= hf_gain;
+ end
+ C_log = [C_log abs(comb)*hf_gain];
+ end
+ tx_filt_log = [tx_filt_log tx_filt];
+ hf_angle_log = [hf_angle_log angle(comb)];
+
+ % AWGN noise and phase/freq offset channel simulation
+ % 0.5 factor ensures var(noise) == variance , i.e. splits power between Re & Im
+
+ noise = sqrt(variance*0.5)*( randn(1,M) + j*randn(1,M) );
+ noise_log = [noise_log noise];
+ rx_baseband = tx_filt.*exp(j*phase_offset) + noise;
+ phase_offset += w_offset;
+
+ % rx filter symbol
+
+ rx_filter_memory(Nfilter-M+1:Nfilter) = rx_baseband;
+ rx_filt = rx_filter_memory * hrn';
+ rx_filter_memory(1:Nfilter-M) = rx_filter_memory(1+M:Nfilter);
+ rx_filt_log = [rx_filt_log rx_filt];
+
+ % delay in tx symbols to compensate for filtering
+ % delay, as tx symbols are used as pilot symbols input
+ % to phase est
+
+ s_delay_line_filt(1:Nfiltsym-1) = s_delay_line_filt(2:Nfiltsym);
+ s_delay_line_filt(Nfiltsym) = s(k);
+ s(k) = s_delay_line_filt(1);
+
+ % delay in tx bits to compensate for filtering delay
+
+ tx_bits_delay_line_filt(1:(Nfiltsym-1)*bps) = tx_bits_delay_line_filt(bps+1:Nfiltsym*bps);
+ tx_bits_delay_line_filt((Nfiltsym-1)*bps+1:Nfiltsym*bps) = tx_bits((k-1)*bps+1:k*bps);
+ tx_bits((k-1)*bps+1:k*bps) = tx_bits_delay_line_filt(1:bps);
+
+ s_ch(k) = rx_filt;
+ end
+
+ % coherent demod phase estimation and correction using pilot symbols
+ % cheating a bit here, we use fact that all tx-ed symbols are known
+
+ if phase_est
+ for i=1:Nsymb
+
+ % delay line for phase est window
+
+ r_delay_line(1:Nps-1) = r_delay_line(2:Nps);
+ r_delay_line(Nps) = s_ch(i);
+
+ % delay in tx data to compensate data for phase est window
+
+ s_delay_line(1:Nps-1) = s_delay_line(2:Nps);
+ s_delay_line(Nps) = s(i);
+ tx_bits(2*(i-1)+1:2*i) = qpsk_demod(s_delay_line(floor(Nps/2)+1));
+
+ % estimate phase from surrounding known pilot symbols and correct
+
+ corr = 0; centre = floor(Nps/2)+1;
+ for k=1:Ns:(Nps+1)
+ if (k != centre)
+ corr += s_delay_line(k) * r_delay_line(k)';
+ end
+ end
+ s_ch(i) = r_delay_line(centre).*exp(j*angle(corr));
+ end
+ %printf("corr: %f angle: %f\n", corr, angle(corr));
+ end
+
+ % de-modulate
+
+ rx_bits = zeros(1, framesize);
+ for i=1:Nsymb
+ rx_symb = s_ch(i);
+ if strcmp(modulation,'dqpsk')
+ tmp = rx_symb;
+ rx_symb *= conj(prev_sym_rx/abs(prev_sym_rx));
+ prev_sym_rx = tmp;
+ end
+ rx_bits((2*(i-1)+1):(2*i)) = qpsk_demod(rx_symb);
+ rx_symb_log = [rx_symb_log rx_symb];
+ end
+
+ % Measure BER
+
+ % discard bits from first 2*Nfiltsym+Nps+1 symbols as tx
+ % and rx filter and phase est memories not full
+
+ skip = bps*(2*Nfiltsym+1+Nps+1);
+ if nn == 1
+ tx_bits_tmp = tx_bits(skip:length(tx_bits));
+ rx_bits_tmp = rx_bits(skip:length(rx_bits));
+ else
+ tx_bits_tmp = tx_bits;
+ rx_bits_tmp = rx_bits;
+ end
+
+ error_positions = xor( rx_bits_tmp, tx_bits_tmp );
+ Nerrs = sum(error_positions);
+ Terrs += Nerrs;
+ Tbits += length(tx_bits_tmp);
+
+ % Optionally LDPC decode
+
+ if ldpc_code
+ % filter memories etc screw up frame alignment so we need to buffer a frame
+
+ tx_data_buffer(1:framesize) = tx_data_buffer(framesize+1:2*framesize);
+ s_data_buffer(1:Nsymb) = s_data_buffer(Nsymb+1:2*Nsymb);
+ tx_data_buffer(framesize+1:2*framesize) = tx_bits;
+ s_data_buffer(Nsymb+1:2*Nsymb) = s_ch;
+
+ offset = Nfiltsym-1;
+ if (phase_est)
+ offset += floor(Nps/2);
+ end
+ st_tx = offset*bps+1;
+ st_s = offset;
+
+ detected_data = ldpc_dec(code_param, max_iterations, demod_type, decoder_type, ...
+ s_data_buffer(st_s+1:st_s+Nsymb), min(100,EsNo));
+
+ % ignore first frame as filter, phase est memories filling up
+ if nn != 1
+ error_positions = xor( detected_data(1:framesize*rate), ...
+ tx_data_buffer(st_tx:st_tx+framesize*rate-1) );
+ Nerrs = sum(error_positions);
+ if Nerrs
+ Ferrsldpc++;
+ end
+ Terrsldpc += Nerrs;
+ Tbitsldpc += framesize*rate;
+ end
+ end
+
+ end
+
+ TERvec(ne) = Terrs;
+ BERvec(ne) = Terrs/Tbits;
+ if ldpc_code
+ TERldpcvec(ne) = Terrsldpc;
+ FERldpcvec(ne) = Ferrsldpc;
+ BERldpcvec(ne) = Terrsldpc/Tbitsldpc;
+ end
+
+ if verbose
+ printf("EsNo (dB): %f Terrs: %d BER %f BER theory %f", Es, Terrs,
+ Terrs/Tbits, 0.5*erfc(sqrt(EsNo/2)));
+ if ldpc_code
+ printf(" LDPC: Terrs: %d BER: %f Ferrs: %d FER: %f",
+ Terrsldpc, Terrsldpc/Tbitsldpc, Ferrsldpc, Ferrsldpc/(Ntrials-1));
+ end
+ printf("\n");
+ end
+ if verbose > 1
+ printf("Terrs: %d BER %f BER theory %f C %f N %f Es %f No %f Es/No %f\n\n", Terrs,
+ Terrs/Tbits, 0.5*erfc(sqrt(EsNo/2)), var(tx_filt_log), var(noise_log),
+ var(tx_filt_log)/Rs, var(noise_log)/Fs, (var(tx_filt_log)/Rs)/(var(noise_log)/Fs));
+ end
+ end
+
+ Ebvec = Esvec - 10*log10(bps);
+ sim_out.BERvec = BERvec;
+ sim_out.Ebvec = Ebvec;
+ sim_out.TERvec = TERvec;
+ if ldpc_code
+ sim_out.BERldpcvec = BERldpcvec;
+ sim_out.TERldpcvec = TERldpcvec;
+ sim_out.FERldpcvec = FERldpcvec;
+ end
+
+ if plot_scatter
+ figure(2);
+ clf;
+ scat = rx_symb_log(2*Nfiltsym:length(rx_symb_log)) .* exp(j*pi/4);
+ plot(real(scat), imag(scat),'+');
+
+ figure(3);
+ clf;
+
+ subplot(211)
+ plot(C_log);
+ subplot(212)
+ plot(hf_angle_log);
+ axis([1 10000 min(hf_angle_log) max(hf_angle_log)])
+ end
+endfunction
+
+% Gray coded QPSK modulation function
+
+function symbol = qpsk_mod(two_bits)
+ two_bits_decimal = sum(two_bits .* [2 1]);
+ switch(two_bits_decimal)
+ case (0) symbol = 1;
+ case (1) symbol = j;
+ case (2) symbol = -j;
+ case (3) symbol = -1;
+ endswitch
+endfunction
+
+% Gray coded QPSK demodulation function
+
+function two_bits = qpsk_demod(symbol)
+ if isscalar(symbol) == 0
+ printf("only works with scalars\n");
+ return;
+ end
+ bit0 = real(symbol*exp(j*pi/4)) < 0;
+ bit1 = imag(symbol*exp(j*pi/4)) < 0;
+ two_bits = [bit1 bit0];
+endfunction
+
+% Start simulations ---------------------------------------
+
+more off;
+sim_in.verbose = 2;
+
+sim_in.Esvec = 5;
+sim_in.Ntrials = 100;
+sim_in.framesize = 100;
+sim_in.Rs = 400;
+sim_in.phase_offset = 0;
+sim_in.phase_est = 0;
+sim_in.w_offset = 0;
+sim_in.plot_scatter = 1;
+sim_in.hf_delay_ms = 2;
+sim_in.hf_sim = 1;
+sim_in.Np = 6;
+sim_in.Ns = 5;
+sim_in.hf_phase_only = 0;
+sim_in.hf_mag_only = 1;
+sim_in.ldpc_code = 0;
+
+Ebvec = sim_in.Esvec - 10*log10(2);
+BER_theory = 0.5*erfc(sqrt(10.^(Ebvec/10)));
+
+sim_qpsk = ber_test(sim_in, 'qpsk');
+
+figure(1);
+clf;
+semilogy(Ebvec, BER_theory,'r;QPSK theory;')
+hold on;
+semilogy(sim_qpsk.Ebvec, sim_qpsk.BERvec,'g;QPSK;')
+hold off;
+xlabel('Eb/N0')
+ylabel('BER')
+grid("minor")
+
+
+if 0
+sim_in.hf_mag_only = 1;
+sim_qpsk_mag = ber_test(sim_in, 'qpsk');
+
+sim_in.hf_mag_only = 0;
+sim_in.hf_phase_only = 1;
+sim_in.phase_est = 1;
+sim_qpsk_phase = ber_test(sim_in, 'qpsk');
+
+sim_in.hf_phase_only = 0;
+sim_qpsk_coh_6_5 = ber_test(sim_in, 'qpsk');
+
+sim_in.phase_est = 0;
+sim_dqpsk = ber_test(sim_in, 'dqpsk');
+
+figure(1);
+clf;
+semilogy(Ebvec, BER_theory,'r;QPSK theory;')
+hold on;
+semilogy(sim_qpsk_mag.Ebvec, sim_qpsk_mag.BERvec,'g;QPSK CCIR poor mag;')
+semilogy(sim_qpsk_phase.Ebvec, sim_qpsk_phase.BERvec,'k;QPSK CCIR poor phase;')
+semilogy(sim_qpsk_coh_6_5.Ebvec, sim_qpsk_coh_6_5.BERvec,'c;QPSK CCIR poor Np=6 Ns=5;')
+semilogy(sim_dqpsk.Ebvec, sim_dqpsk.BERvec,'b;DQPSK CCIR poor;')
+%semilogy(sim_qpsk_coh_5_24.Ebvec, sim_qpsk_coh_5_24.BERvec,'k;QPSK Ns=5 Np=24;')
+%semilogy(sim_qpsk_coh_2_12.Ebvec, sim_qpsk_coh_2_12.BERvec,'c;QPSK Ns=2 Np=12;')
+hold off;
+xlabel('Eb/N0')
+ylabel('BER')
+grid("minor")
+axis([min(Ebvec)-1 max(Ebvec)+1 1E-2 1])
+end
-% test_qps2k.m\r
-% David Rowe Feb 2014\r
-%\r
-% QPSK modem simulation, version 2. Simplifed version of\r
-% test_qpsk. initially based on code by Bill Cowley Generates curves\r
-% BER versus E/No curves for different modems. Design to test\r
-% coherent demodulation ideas on HF channels without building a full\r
-% blown modem. Uses 'genie provided' estimates for timing estimation,\r
-% frame sync.\r
-\r
-1;\r
-\r
-% main test function \r
-\r
-function sim_out = ber_test(sim_in, modulation)\r
- Fs = 8000;\r
-\r
- verbose = sim_in.verbose;\r
- framesize = sim_in.framesize;\r
- Ntrials = sim_in.Ntrials;\r
- Esvec = sim_in.Esvec;\r
- phase_offset = sim_in.phase_offset;\r
- phase_est = sim_in.phase_est;\r
- w_offset = sim_in.w_offset;\r
- plot_scatter = sim_in.plot_scatter;\r
- Rs = sim_in.Rs;\r
- hf_sim = sim_in.hf_sim;\r
- nhfdelay = sim_in.hf_delay_ms*Rs/1000;\r
- hf_phase_only = sim_in.hf_phase_only;\r
- hf_mag_only = sim_in.hf_mag_only;\r
- Nc = sim_in.Nc;\r
-\r
- bps = 2;\r
- Nsymb = framesize/bps;\r
- prev_sym_tx = qpsk_mod([0 0]);\r
- prev_sym_rx = qpsk_mod([0 0]);\r
-\r
- phase_est_method = sim_in.phase_est_method;\r
- if phase_est_method == 1\r
- Nps = sim_in.Np; \r
- else\r
- Np = sim_in.Np;\r
- Ns = sim_in.Ns;\r
- if Np/2 == floor(Np/2)\r
- printf("Np must be odd\n");\r
- return;\r
- end\r
- Nps = (Np-1)*Ns+1; \r
- end\r
- r_delay_line = zeros(Nc, Nps);\r
- s_delay_line = zeros(Nc, Nps);\r
- ph_est_log = [];\r
-\r
- phase_noise_amp = sim_in.phase_noise_amp;\r
-\r
- ldpc_code = sim_in.ldpc_code;\r
-\r
- tx_bits_buf = zeros(1,2*framesize);\r
- rx_bits_buf = zeros(1,2*framesize);\r
- rx_symb_buf = zeros(1,2*Nsymb);\r
-\r
- % Init LDPC --------------------------------------------------------------------\r
-\r
- if ldpc_code\r
- % Start CML library\r
-\r
- currentdir = pwd;\r
- addpath '/home/david/tmp/cml/mat' % assume the source files stored here\r
- cd /home/david/tmp/cml\r
- CmlStartup % note that this is not in the cml path!\r
- cd(currentdir)\r
- \r
- % Our LDPC library\r
-\r
- ldpc;\r
-\r
- rate = sim_in.ldpc_code_rate; \r
- mod_order = 4; \r
- modulation = 'QPSK';\r
- mapping = 'gray';\r
-\r
- demod_type = 0;\r
- decoder_type = 0;\r
- max_iterations = 100;\r
-\r
- code_param = ldpc_init(rate, framesize, modulation, mod_order, mapping);\r
- code_param.code_bits_per_frame = framesize;\r
- code_param.symbols_per_frame = framesize/bps;\r
- else\r
- rate = 1;\r
- end\r
-\r
- % Init HF channel model from stored sample files of spreading signal ----------------------------------\r
-\r
- % convert "spreading" samples from 1kHz carrier at Fs to complex\r
- % baseband, generated by passing a 1kHz sine wave through PathSim\r
- % with the ccir-poor model, enabling one path at a time.\r
- \r
- Fc = 1000; M = Fs/Rs;\r
- fspread = fopen("../raw/sine1k_2Hz_spread.raw","rb");\r
- spread1k = fread(fspread, "int16")/10000;\r
- fclose(fspread);\r
- fspread = fopen("../raw/sine1k_2ms_delay_2Hz_spread.raw","rb");\r
- spread1k_2ms = fread(fspread, "int16")/10000;\r
- fclose(fspread);\r
-\r
- % down convert to complex baseband\r
- spreadbb = spread1k.*exp(-j*(2*pi*Fc/Fs)*(1:length(spread1k))');\r
- spreadbb_2ms = spread1k_2ms.*exp(-j*(2*pi*Fc/Fs)*(1:length(spread1k_2ms))');\r
-\r
- % remove -2000 Hz image\r
- b = fir1(50, 5/Fs);\r
- spread = filter(b,1,spreadbb);\r
- spread_2ms = filter(b,1,spreadbb_2ms);\r
-\r
- % discard first 1000 samples as these were near 0, probably as\r
- % PathSim states were ramping up\r
-\r
- spread = spread(1000:length(spread));\r
- spread_2ms = spread_2ms(1000:length(spread_2ms));\r
-\r
- % decimate down to Rs\r
-\r
- spread = spread(1:M:length(spread));\r
- spread_2ms = spread_2ms(1:M:length(spread_2ms));\r
-\r
- % Determine "gain" of HF channel model, so we can normalise\r
- % carrier power during HF channel sim to calibrate SNR. I imagine\r
- % different implementations of ccir-poor would do this in\r
- % different ways, leading to different BER results. Oh Well!\r
-\r
- hf_gain = 1.0/sqrt(var(spread)+var(spread_2ms));\r
-\r
- % Start Simulation ----------------------------------------------------------------\r
-\r
- for ne = 1:length(Esvec)\r
- EsNodB = Esvec(ne);\r
- EsNo = 10^(EsNodB/10);\r
- \r
- variance = 1/EsNo;\r
- if verbose > 1\r
- printf("EsNo (dB): %f EsNo: %f variance: %f\n", EsNodB, EsNo, variance);\r
- end\r
- \r
- Terrs = 0; Tbits = 0; Terrsldpc = 0; Tbitsldpc = 0; Ferrsldpc = 0;\r
-\r
- tx_symb_log = [];\r
- rx_symb_log = [];\r
- noise_log = [];\r
- mod_strip_log = [];\r
-\r
- % init HF channel\r
-\r
- hf_n = 1;\r
- hf_angle_log = [];\r
- hf_fading = ones(1,Nsymb); % default input for ldpc dec\r
- hf_model = ones(Ntrials*Nsymb/Nc, Nc); % defaults for plotting surface\r
-\r
- for nn = 1: Ntrials\r
- \r
- tx_bits = round( rand( 1, framesize*rate ) );\r
- \r
- % modulate --------------------------------------------\r
-\r
- if ldpc_code\r
- [tx_bits, s] = ldpc_enc(tx_bits, code_param);\r
- else\r
- s = zeros(1, Nsymb);\r
- for i=1:Nsymb\r
- tx_symb = qpsk_mod(tx_bits(2*(i-1)+1:2*i));\r
- if strcmp(modulation,'dqpsk')\r
- tx_symb *= prev_sym_tx;\r
- prev_sym_tx = tx_symb;\r
- end \r
- s(i) = tx_symb;\r
- end\r
- end\r
- tx_bits_buf(1:framesize) = tx_bits_buf(framesize+1:2*framesize);\r
- tx_bits_buf(framesize+1:2*framesize) = tx_bits;\r
- s_ch = s;\r
-\r
- % HF channel simulation ------------------------------------\r
- \r
- if hf_sim\r
-\r
- % separation between carriers. Note this is\r
- % effectively under samples at Rs, I dont think this\r
- % matters. Equivalent to doing freq shift at Fs, then\r
- % decimating to Rs.\r
-\r
- wsep = 2*pi*(1+0.5); % e.g. 75Hz spacing at Rs=50Hz, alpha=0.5 filters\r
-\r
- if Nsymb/Nc != floor(Nsymb/Nc)\r
- printf("Error: Nsymb/Nc must be an integrer\n")\r
- return;\r
- end\r
-\r
- % arrange symbols in Nsymb/Nc by Nc matrix\r
-\r
- for i=1:Nc:Nsymb\r
-\r
- % Determine HF channel at each carrier for this symbol\r
-\r
- for k=1:Nc\r
- hf_model(hf_n, k) = hf_gain*(spread(hf_n) + exp(-j*k*wsep*nhfdelay)*spread_2ms(hf_n));\r
- hf_fading(i+k-1) = abs(hf_model(hf_n, k));\r
- if hf_mag_only\r
- s_ch(i+k-1) *= abs(hf_model(hf_n, k));\r
- else\r
- s_ch(i+k-1) *= hf_model(hf_n, k);\r
- end\r
- end\r
- hf_n++;\r
- end\r
- end\r
- \r
- tx_symb_log = [tx_symb_log s_ch];\r
-\r
- % AWGN noise and phase/freq offset channel simulation\r
- % 0.5 factor ensures var(noise) == variance , i.e. splits power between Re & Im\r
-\r
- noise = sqrt(variance*0.5)*(randn(1,Nsymb) + j*randn(1,Nsymb));\r
- noise_log = [noise_log noise];\r
- phase_noise = phase_noise_amp*(2.0*rand(1,Nsymb)-1.0);\r
- \r
- % organise into carriers to apply frequency and phase offset\r
-\r
- for i=1:Nc:Nsymb\r
- for k=1:Nc\r
- s_ch(i+k-1) = s_ch(i+k-1)*exp(j*(phase_offset+phase_noise(i+k-1))) + noise(i+k-1);\r
- end \r
- phase_offset += w_offset;\r
- end\r
- \r
- % phase estimation\r
- \r
- ph_est = zeros(Nc,1);\r
-\r
- if phase_est\r
-\r
- % organise into carriers\r
-\r
- for i=1:Nc:Nsymb\r
-\r
- for k=1:Nc\r
- centre = floor(Nps/2)+1;\r
-\r
- % delay line for phase est window\r
-\r
- r_delay_line(k,1:Nps-1) = r_delay_line(k,2:Nps);\r
- r_delay_line(k,Nps) = s_ch(i+k-1);\r
-\r
- % delay in tx data to compensate data for phase est window\r
-\r
- s_delay_line(k,1:Nps-1) = s_delay_line(k,2:Nps);\r
- s_delay_line(k,Nps) = s(i+k-1);\r
- %tx_bits(2*(i+k-1-1)+1:2*(i+k-1)) = qpsk_demod(s_delay_line(k,centre));\r
- \r
- if phase_est_method == 1\r
- % QPSK modulation strip and phase est\r
-\r
- mod_strip_pol = angle(r_delay_line(k,:)) * 4;\r
- mod_strip_rect = exp(j*mod_strip_pol);\r
-\r
- ph_est_pol = atan2(sum(imag(mod_strip_rect)),sum(real(mod_strip_rect)))/4;\r
- ph_est(k) = exp(j*ph_est_pol);\r
-\r
- s_ch(i+k-1) = r_delay_line(k,centre).*exp(-j*ph_est_pol);\r
- else\r
-\r
- % estimate phase from surrounding known pilot symbols and correct\r
-\r
- corr = 0;\r
- for m=1:Ns:Nps\r
- if (m != centre)\r
- corr += s_delay_line(k,m) * r_delay_line(k,m)';\r
- end\r
- end\r
- ph_est(k) = conj(corr/(1E-6+abs(corr)));\r
- s_ch(i+k-1) = r_delay_line(k,centre).*exp(j*angle(corr));\r
- end\r
-\r
- end\r
- \r
- ph_est_log = [ph_est_log ph_est];\r
- end \r
- %printf("corr: %f angle: %f\n", corr, angle(corr));\r
- end\r
-\r
- % de-modulate\r
-\r
- rx_bits = zeros(1, framesize);\r
- for i=1:Nsymb\r
- rx_symb = s_ch(i);\r
- if strcmp(modulation,'dqpsk')\r
- tmp = rx_symb;\r
- rx_symb *= conj(prev_sym_rx/abs(prev_sym_rx));\r
- prev_sym_rx = tmp;\r
- end\r
- rx_bits((2*(i-1)+1):(2*i)) = qpsk_demod(rx_symb);\r
- rx_symb_log = [rx_symb_log rx_symb];\r
- end\r
-\r
- rx_bits_buf(1:framesize) = rx_bits_buf(framesize+1:2*framesize);\r
- rx_bits_buf(framesize+1:2*framesize) = rx_bits;\r
- rx_symb_buf(1:Nsymb) = rx_symb_buf(Nsymb+1:2*Nsymb);\r
- rx_symb_buf(Nsymb+1:2*Nsymb) = s_ch;\r
-\r
- % determine location of start and end of frame depending on processing delays\r
-\r
- if phase_est\r
- st_rx_bits = 1+(floor(Nps/2)+1-1)*Nc*2;\r
- st_rx_symb = 1+(floor(Nps/2)+1-1)*Nc;\r
- else\r
- st_rx_bits = 1;\r
- st_rx_symb = 1;\r
- end\r
- en_rx_bits = st_rx_bits+framesize-1;\r
- en_rx_symb = st_rx_symb+Nsymb-1;\r
-\r
- if nn > 1\r
- % Measure BER\r
-\r
- %printf("nn: %d centre: %d\n", nn, floor(Nps/2)+1);\r
- %tx_bits_buf(1:20)\r
- %rx_bits_buf(st_rx_bits:st_rx_bits+20-1)\r
- error_positions = xor(rx_bits_buf(st_rx_bits:en_rx_bits), tx_bits_buf(1:framesize));\r
- Nerrs = sum(error_positions);\r
- Terrs += Nerrs;\r
- Tbits += length(tx_bits);\r
-\r
- % Optionally LDPC decode\r
- \r
- if ldpc_code\r
- detected_data = ldpc_dec(code_param, max_iterations, demod_type, decoder_type, rx_symb_buf(st_rx_symb:en_rx_symb), min(100,EsNo), hf_fading);\r
- %for m=1:20\r
- % printf("%f ", qpsk_demod(rx_symb_buf(m)));\r
- %end\r
- %detected_data(1:19)\r
- error_positions = xor( detected_data(1:framesize*rate), tx_bits_buf(1:framesize*rate) );\r
- Nerrs = sum(error_positions);\r
- if Nerrs\r
- Ferrsldpc++;\r
- end\r
- Terrsldpc += Nerrs;\r
- Tbitsldpc += framesize*rate;\r
- end\r
- end\r
- end\r
- \r
- TERvec(ne) = Terrs;\r
- BERvec(ne) = Terrs/Tbits;\r
- if ldpc_code\r
- TERldpcvec(ne) = Terrsldpc;\r
- FERldpcvec(ne) = Ferrsldpc;\r
- BERldpcvec(ne) = Terrsldpc/Tbitsldpc;\r
- end\r
-\r
- if verbose \r
- printf("EsNo (dB): %f Terrs: %d BER %f BER theory %f", EsNodB, Terrs,\r
- Terrs/Tbits, 0.5*erfc(sqrt(EsNo/2)));\r
- if ldpc_code\r
- printf(" LDPC: Terrs: %d BER: %f Ferrs: %d FER: %f", \r
- Terrsldpc, Terrsldpc/Tbitsldpc, Ferrsldpc, Ferrsldpc/(Ntrials-1));\r
- end\r
- printf("\n");\r
- end\r
- if verbose > 1\r
- printf("Terrs: %d BER %f BER theory %f C %f N %f Es %f No %f Es/No %f\n\n", Terrs,\r
- Terrs/Tbits, 0.5*erfc(sqrt(EsNo/2)), var(tx_symb_log), var(noise_log),\r
- var(tx_symb_log), var(noise_log), var(tx_symb_log)/var(noise_log));\r
- end\r
- end\r
- \r
- Ebvec = Esvec - 10*log10(bps);\r
- sim_out.BERvec = BERvec;\r
- sim_out.Ebvec = Ebvec;\r
- sim_out.TERvec = TERvec;\r
- if ldpc_code\r
- sim_out.BERldpcvec = BERldpcvec;\r
- sim_out.TERldpcvec = TERldpcvec;\r
- sim_out.FERldpcvec = FERldpcvec;\r
- end\r
-\r
- if plot_scatter\r
- figure(2);\r
- clf;\r
- scat = rx_symb_log .* exp(j*pi/4);\r
- plot(real(scat(Nps*Nc:length(scat))), imag(scat(Nps*Nc:length(scat))),'+');\r
- title('Scatter plot');\r
-\r
- figure(3);\r
- clf;\r
- \r
- y = 1:Rs*2;\r
- x = 1:Nc;\r
- EsNodBSurface = 20*log10(abs(hf_model(y,:))) - 10*log10(variance);\r
- mesh(x,y,EsNodBSurface);\r
- grid\r
- %axis([1 Nc 1 Rs*2 -10 10])\r
- title('HF Channel Es/No');\r
-\r
- figure(4);\r
- clf;\r
- %mesh(x,y,unwrap(angle(hf_model(y,:))));\r
- subplot(211)\r
- plot(y,abs(hf_model(y,1)))\r
- title('HF Channel Carrier 1 Mag');\r
- subplot(212)\r
- plot(y,angle(hf_model(y,1)))\r
- title('HF Channel Carrier 1 Phase');\r
-\r
- if phase_est\r
- scat = ph_est_log(1,floor(Nps/2):Rs*2+floor(Nps/2)-1);\r
- hold on;\r
- plot(angle(scat),'r');\r
- hold off;\r
-\r
- figure(5)\r
- clf;\r
- scat = ph_est_log(1,y);\r
- plot(real(scat), imag(scat),'+');\r
- title('Carrier 1 Phase Est');\r
- axis([-1 1 -1 1])\r
- end\r
-if 0 \r
- figure(5);\r
- clf;\r
- subplot(211)\r
- plot(real(spread));\r
- hold on;\r
- plot(imag(spread),'g'); \r
- hold off; \r
- subplot(212)\r
- plot(real(spread_2ms));\r
- hold on;\r
- plot(imag(spread_2ms),'g'); \r
- hold off; \r
-\r
- figure(6)\r
- tmp = [];\r
- for i = 1:hf_n-1\r
- tmp = [tmp abs(hf_model(i,:))];\r
- end\r
- hist(tmp);\r
-end\r
- end\r
-\r
-endfunction\r
-\r
-% Gray coded QPSK modulation function\r
-\r
-function symbol = qpsk_mod(two_bits)\r
- two_bits_decimal = sum(two_bits .* [2 1]); \r
- switch(two_bits_decimal)\r
- case (0) symbol = 1;\r
- case (1) symbol = j;\r
- case (2) symbol = -j;\r
- case (3) symbol = -1;\r
- endswitch\r
-endfunction\r
-\r
-% Gray coded QPSK demodulation function\r
-\r
-function two_bits = qpsk_demod(symbol)\r
- if isscalar(symbol) == 0\r
- printf("only works with scalars\n");\r
- return;\r
- end\r
- bit0 = real(symbol*exp(j*pi/4)) < 0;\r
- bit1 = imag(symbol*exp(j*pi/4)) < 0;\r
- two_bits = [bit1 bit0];\r
-endfunction\r
-\r
-function sim_in = standard_init\r
- sim_in.verbose = 1;\r
- sim_in.plot_scatter = 0;\r
-\r
- sim_in.Esvec = 5; \r
- sim_in.Ntrials = 30;\r
- sim_in.framesize = 576;\r
- sim_in.Rs = 100;\r
- sim_in.Nc = 8;\r
-\r
- sim_in.phase_offset = 0;\r
- sim_in.w_offset = 0;\r
- sim_in.phase_noise_amp = 0;\r
-\r
- sim_in.hf_delay_ms = 2;\r
- sim_in.hf_sim = 0;\r
- sim_in.hf_phase_only = 0;\r
- sim_in.hf_mag_only = 1;\r
-\r
- sim_in.phase_est = 0;\r
- sim_in.phase_est_method = 1;\r
- sim_in.Np = 5;\r
- sim_in.Ns = 5;\r
-\r
- sim_in.ldpc_code_rate = 1/2;\r
- sim_in.ldpc_code = 1;\r
-endfunction\r
-\r
-function ideal\r
-\r
- sim_in = standard_init();\r
-\r
- sim_in.verbose = 1;\r
- sim_in.plot_scatter = 1;\r
-\r
- sim_in.Esvec = 5; \r
- sim_in.hf_sim = 1;\r
- sim_in.Ntrials = 30;\r
-\r
- sim_qpsk_hf = ber_test(sim_in, 'qpsk');\r
-\r
- sim_in.hf_sim = 0;\r
- sim_in.plot_scatter = 0;\r
- sim_in.Esvec = 2:10; \r
- sim_in.ldpc_code = 0;\r
- Ebvec = sim_in.Esvec - 10*log10(2);\r
- BER_theory = 0.5*erfc(sqrt(10.^(Ebvec/10)));\r
- sim_qpsk = ber_test(sim_in, 'qpsk');\r
- sim_dqpsk = ber_test(sim_in, 'dqpsk');\r
-\r
- sim_in.hf_sim = 1;\r
- sim_qpsk_hf = ber_test(sim_in, 'qpsk');\r
- sim_dqpsk_hf = ber_test(sim_in, 'dqpsk');\r
- sim_in.ldpc_code_rate = 1/2;\r
- sim_in.ldpc_code = 1;\r
-\r
- sim_in.hf_sim = 0;\r
- sim_qpsk_ldpc = ber_test(sim_in, 'qpsk');\r
-\r
- sim_in.hf_sim = 1;\r
- sim_qpsk_hf_ldpc = ber_test(sim_in, 'qpsk');\r
- sim_in.hf_mag_only = 0;\r
- sim_dqpsk_hf_ldpc = ber_test(sim_in, 'dqpsk');\r
-\r
- figure(1); \r
- clf;\r
- semilogy(Ebvec, BER_theory,'r;QPSK theory;')\r
- hold on;\r
- semilogy(sim_qpsk.Ebvec, sim_qpsk.BERvec,'g;QPSK AWGN;')\r
- semilogy(sim_qpsk_hf.Ebvec, sim_qpsk_hf.BERvec,'r;QPSK HF;')\r
- semilogy(sim_qpsk_ldpc.Ebvec, sim_qpsk_ldpc.BERldpcvec,'bk;QPSK HF;')\r
- semilogy(sim_dqpsk.Ebvec, sim_dqpsk.BERvec,'g;DQPSK AWGN;')\r
- semilogy(sim_dqpsk_hf.Ebvec, sim_dqpsk_hf.BERvec,'r;DQPSK HF;')\r
- semilogy(sim_qpsk_hf_ldpc.Ebvec, sim_qpsk_hf_ldpc.BERldpcvec,'b;QPSK HF LDPC 1/2;')\r
- semilogy(sim_dqpsk_hf_ldpc.Ebvec, sim_dqpsk_hf_ldpc.BERldpcvec,'b;DQPSK HF LDPC 1/2;')\r
-\r
- hold off;\r
- xlabel('Eb/N0')\r
- ylabel('BER')\r
- grid("minor")\r
- axis([min(Ebvec) max(Ebvec) 1E-3 1])\r
-endfunction\r
-\r
-function phase_noise\r
- sim_in = standard_init();\r
-\r
- sim_in.verbose = 1;\r
- sim_in.plot_scatter = 1;\r
-\r
- sim_in.Esvec = 100; \r
- sim_in.Ntrials = 30;\r
-\r
- sim_in.ldpc_code_rate = 1/2;\r
- sim_in.ldpc_code = 1;\r
-\r
- sim_in.phase_noise_amp = pi/16;\r
- tmp = ber_test(sim_in, 'qpsk');\r
-\r
- sim_in.plot_scatter = 0;\r
- sim_in.Esvec = 2:8; \r
- sim_qpsk_hf = ber_test(sim_in, 'qpsk');\r
-\r
- Ebvec = sim_in.Esvec - 10*log10(2);\r
- BER_theory = 0.5*erfc(sqrt(10.^(Ebvec/10)));\r
-\r
- sim_in.phase_noise_amp = 0;\r
- sim_qpsk = ber_test(sim_in, 'qpsk');\r
- sim_in.phase_noise_amp = pi/8;\r
- sim_qpsk_pn8 = ber_test(sim_in, 'qpsk');\r
- sim_in.phase_noise_amp = pi/16;\r
- sim_qpsk_pn16 = ber_test(sim_in, 'qpsk');\r
- sim_in.phase_noise_amp = pi/32;\r
- sim_qpsk_pn32 = ber_test(sim_in, 'qpsk');\r
-\r
- figure(1); \r
- clf;\r
- semilogy(sim_qpsk.Ebvec, sim_qpsk.BERvec,'g;QPSK phase noise 0;')\r
- hold on;\r
- semilogy(sim_qpsk_pn8.Ebvec, sim_qpsk_pn8.BERvec,'c;QPSK phase noise +/- pi/8;')\r
- semilogy(sim_qpsk_pn16.Ebvec, sim_qpsk_pn16.BERvec,'b;QPSK phase noise +/- pi/16;')\r
- semilogy(sim_qpsk_pn32.Ebvec, sim_qpsk_pn32.BERvec,'k;QPSK phase noise +/- pi/32;')\r
-\r
- semilogy(sim_qpsk.Ebvec, sim_qpsk.BERldpcvec,'g;QPSK phase noise 0 ldpc;')\r
- semilogy(sim_qpsk_pn8.Ebvec, sim_qpsk_pn8.BERldpcvec,'c;QPSK phase noise +/- pi/8 ldpc;')\r
- semilogy(sim_qpsk_pn16.Ebvec, sim_qpsk_pn16.BERldpcvec,'b;QPSK phase noise +/- pi/16 ldpc;')\r
- semilogy(sim_qpsk_pn32.Ebvec, sim_qpsk_pn32.BERldpcvec,'k;QPSK phase noise +/- pi/32 ldpc;')\r
-\r
- hold off;\r
- xlabel('Eb/N0')\r
- ylabel('BER')\r
- grid("minor")\r
- axis([min(Ebvec) max(Ebvec) 1E-2 1])\r
-endfunction\r
-\r
-function test_phase_est\r
- sim_in = standard_init();\r
-\r
- sim_in.Rs = 100;\r
- sim_in.Nc = 8;\r
-\r
- sim_in.verbose = 1;\r
- sim_in.plot_scatter = 1;\r
-\r
- sim_in.Esvec = 5; \r
- sim_in.Ntrials = 30;\r
-\r
- sim_in.ldpc_code_rate = 1/2;\r
- sim_in.ldpc_code = 1;\r
-\r
- sim_in.phase_est = 1;\r
- sim_in.phase_est_method = 2;\r
- sim_in.Np = 3;\r
- sim_in.phase_offset = 0;\r
- sim_in.w_offset = 0;\r
-\r
- sim_in.hf_sim = 1;\r
- sim_in.hf_mag_only = 0;\r
-\r
- tmp = ber_test(sim_in, 'qpsk');\r
-\r
-endfunction\r
-\r
-% Start simulations ---------------------------------------\r
-\r
-more off;\r
-\r
-ideal();\r
+% test_qps2k.m
+% David Rowe Feb 2014
+%
+% QPSK modem simulation, version 2. Simplifed version of
+% test_qpsk. initially based on code by Bill Cowley Generates curves
+% BER versus E/No curves for different modems. Design to test
+% coherent demodulation ideas on HF channels without building a full
+% blown modem. Uses 'genie provided' estimates for timing estimation,
+% frame sync.
+
+1;
+
+% main test function
+
+function sim_out = ber_test(sim_in, modulation)
+ Fs = 8000;
+
+ verbose = sim_in.verbose;
+ framesize = sim_in.framesize;
+ Ntrials = sim_in.Ntrials;
+ Esvec = sim_in.Esvec;
+ phase_offset = sim_in.phase_offset;
+ phase_est = sim_in.phase_est;
+ w_offset = sim_in.w_offset;
+ plot_scatter = sim_in.plot_scatter;
+ Rs = sim_in.Rs;
+ hf_sim = sim_in.hf_sim;
+ nhfdelay = sim_in.hf_delay_ms*Rs/1000;
+ hf_phase_only = sim_in.hf_phase_only;
+ hf_mag_only = sim_in.hf_mag_only;
+ Nc = sim_in.Nc;
+
+ bps = 2;
+ Nsymb = framesize/bps;
+ prev_sym_tx = qpsk_mod([0 0]);
+ prev_sym_rx = qpsk_mod([0 0]);
+
+ phase_est_method = sim_in.phase_est_method;
+ if phase_est_method == 1
+ Nps = sim_in.Np;
+ else
+ Np = sim_in.Np;
+ Ns = sim_in.Ns;
+ if Np/2 == floor(Np/2)
+ printf("Np must be odd\n");
+ return;
+ end
+ Nps = (Np-1)*Ns+1;
+ end
+ r_delay_line = zeros(Nc, Nps);
+ s_delay_line = zeros(Nc, Nps);
+ ph_est_log = [];
+
+ phase_noise_amp = sim_in.phase_noise_amp;
+
+ ldpc_code = sim_in.ldpc_code;
+
+ tx_bits_buf = zeros(1,2*framesize);
+ rx_bits_buf = zeros(1,2*framesize);
+ rx_symb_buf = zeros(1,2*Nsymb);
+
+ % Init LDPC --------------------------------------------------------------------
+
+ if ldpc_code
+ % Start CML library
+
+ currentdir = pwd;
+ addpath '/home/david/tmp/cml/mat' % assume the source files stored here
+ cd /home/david/tmp/cml
+ CmlStartup % note that this is not in the cml path!
+ cd(currentdir)
+
+ % Our LDPC library
+
+ ldpc;
+
+ rate = sim_in.ldpc_code_rate;
+ mod_order = 4;
+ modulation = 'QPSK';
+ mapping = 'gray';
+
+ demod_type = 0;
+ decoder_type = 0;
+ max_iterations = 100;
+
+ code_param = ldpc_init(rate, framesize, modulation, mod_order, mapping);
+ code_param.code_bits_per_frame = framesize;
+ code_param.symbols_per_frame = framesize/bps;
+ else
+ rate = 1;
+ end
+
+ % Init HF channel model from stored sample files of spreading signal ----------------------------------
+
+ % convert "spreading" samples from 1kHz carrier at Fs to complex
+ % baseband, generated by passing a 1kHz sine wave through PathSim
+ % with the ccir-poor model, enabling one path at a time.
+
+ Fc = 1000; M = Fs/Rs;
+ fspread = fopen("../raw/sine1k_2Hz_spread.raw","rb");
+ spread1k = fread(fspread, "int16")/10000;
+ fclose(fspread);
+ fspread = fopen("../raw/sine1k_2ms_delay_2Hz_spread.raw","rb");
+ spread1k_2ms = fread(fspread, "int16")/10000;
+ fclose(fspread);
+
+ % down convert to complex baseband
+ spreadbb = spread1k.*exp(-j*(2*pi*Fc/Fs)*(1:length(spread1k))');
+ spreadbb_2ms = spread1k_2ms.*exp(-j*(2*pi*Fc/Fs)*(1:length(spread1k_2ms))');
+
+ % remove -2000 Hz image
+ b = fir1(50, 5/Fs);
+ spread = filter(b,1,spreadbb);
+ spread_2ms = filter(b,1,spreadbb_2ms);
+
+ % discard first 1000 samples as these were near 0, probably as
+ % PathSim states were ramping up
+
+ spread = spread(1000:length(spread));
+ spread_2ms = spread_2ms(1000:length(spread_2ms));
+
+ % decimate down to Rs
+
+ spread = spread(1:M:length(spread));
+ spread_2ms = spread_2ms(1:M:length(spread_2ms));
+
+ % Determine "gain" of HF channel model, so we can normalise
+ % carrier power during HF channel sim to calibrate SNR. I imagine
+ % different implementations of ccir-poor would do this in
+ % different ways, leading to different BER results. Oh Well!
+
+ hf_gain = 1.0/sqrt(var(spread)+var(spread_2ms));
+
+ % Start Simulation ----------------------------------------------------------------
+
+ for ne = 1:length(Esvec)
+ EsNodB = Esvec(ne);
+ EsNo = 10^(EsNodB/10);
+
+ variance = 1/EsNo;
+ if verbose > 1
+ printf("EsNo (dB): %f EsNo: %f variance: %f\n", EsNodB, EsNo, variance);
+ end
+
+ Terrs = 0; Tbits = 0; Terrsldpc = 0; Tbitsldpc = 0; Ferrsldpc = 0;
+
+ tx_symb_log = [];
+ rx_symb_log = [];
+ noise_log = [];
+ mod_strip_log = [];
+
+ % init HF channel
+
+ hf_n = 1;
+ hf_angle_log = [];
+ hf_fading = ones(1,Nsymb); % default input for ldpc dec
+ hf_model = ones(Ntrials*Nsymb/Nc, Nc); % defaults for plotting surface
+
+ for nn = 1: Ntrials
+
+ tx_bits = round( rand( 1, framesize*rate ) );
+
+ % modulate --------------------------------------------
+
+ if ldpc_code
+ [tx_bits, s] = ldpc_enc(tx_bits, code_param);
+ else
+ s = zeros(1, Nsymb);
+ for i=1:Nsymb
+ tx_symb = qpsk_mod(tx_bits(2*(i-1)+1:2*i));
+ if strcmp(modulation,'dqpsk')
+ tx_symb *= prev_sym_tx;
+ prev_sym_tx = tx_symb;
+ end
+ s(i) = tx_symb;
+ end
+ end
+ tx_bits_buf(1:framesize) = tx_bits_buf(framesize+1:2*framesize);
+ tx_bits_buf(framesize+1:2*framesize) = tx_bits;
+ s_ch = s;
+
+ % HF channel simulation ------------------------------------
+
+ if hf_sim
+
+ % separation between carriers. Note this is
+ % effectively under samples at Rs, I dont think this
+ % matters. Equivalent to doing freq shift at Fs, then
+ % decimating to Rs.
+
+ wsep = 2*pi*(1+0.5); % e.g. 75Hz spacing at Rs=50Hz, alpha=0.5 filters
+
+ if Nsymb/Nc != floor(Nsymb/Nc)
+ printf("Error: Nsymb/Nc must be an integrer\n")
+ return;
+ end
+
+ % arrange symbols in Nsymb/Nc by Nc matrix
+
+ for i=1:Nc:Nsymb
+
+ % Determine HF channel at each carrier for this symbol
+
+ for k=1:Nc
+ hf_model(hf_n, k) = hf_gain*(spread(hf_n) + exp(-j*k*wsep*nhfdelay)*spread_2ms(hf_n));
+ hf_fading(i+k-1) = abs(hf_model(hf_n, k));
+ if hf_mag_only
+ s_ch(i+k-1) *= abs(hf_model(hf_n, k));
+ else
+ s_ch(i+k-1) *= hf_model(hf_n, k);
+ end
+ end
+ hf_n++;
+ end
+ end
+
+ tx_symb_log = [tx_symb_log s_ch];
+
+ % AWGN noise and phase/freq offset channel simulation
+ % 0.5 factor ensures var(noise) == variance , i.e. splits power between Re & Im
+
+ noise = sqrt(variance*0.5)*(randn(1,Nsymb) + j*randn(1,Nsymb));
+ noise_log = [noise_log noise];
+ phase_noise = phase_noise_amp*(2.0*rand(1,Nsymb)-1.0);
+
+ % organise into carriers to apply frequency and phase offset
+
+ for i=1:Nc:Nsymb
+ for k=1:Nc
+ s_ch(i+k-1) = s_ch(i+k-1)*exp(j*(phase_offset+phase_noise(i+k-1))) + noise(i+k-1);
+ end
+ phase_offset += w_offset;
+ end
+
+ % phase estimation
+
+ ph_est = zeros(Nc,1);
+
+ if phase_est
+
+ % organise into carriers
+
+ for i=1:Nc:Nsymb
+
+ for k=1:Nc
+ centre = floor(Nps/2)+1;
+
+ % delay line for phase est window
+
+ r_delay_line(k,1:Nps-1) = r_delay_line(k,2:Nps);
+ r_delay_line(k,Nps) = s_ch(i+k-1);
+
+ % delay in tx data to compensate data for phase est window
+
+ s_delay_line(k,1:Nps-1) = s_delay_line(k,2:Nps);
+ s_delay_line(k,Nps) = s(i+k-1);
+ %tx_bits(2*(i+k-1-1)+1:2*(i+k-1)) = qpsk_demod(s_delay_line(k,centre));
+
+ if phase_est_method == 1
+ % QPSK modulation strip and phase est
+
+ mod_strip_pol = angle(r_delay_line(k,:)) * 4;
+ mod_strip_rect = exp(j*mod_strip_pol);
+
+ ph_est_pol = atan2(sum(imag(mod_strip_rect)),sum(real(mod_strip_rect)))/4;
+ ph_est(k) = exp(j*ph_est_pol);
+
+ s_ch(i+k-1) = r_delay_line(k,centre).*exp(-j*ph_est_pol);
+ else
+
+ % estimate phase from surrounding known pilot symbols and correct
+
+ corr = 0;
+ for m=1:Ns:Nps
+ if (m != centre)
+ corr += s_delay_line(k,m) * r_delay_line(k,m)';
+ end
+ end
+ ph_est(k) = conj(corr/(1E-6+abs(corr)));
+ s_ch(i+k-1) = r_delay_line(k,centre).*exp(j*angle(corr));
+ end
+
+ end
+
+ ph_est_log = [ph_est_log ph_est];
+ end
+ %printf("corr: %f angle: %f\n", corr, angle(corr));
+ end
+
+ % de-modulate
+
+ rx_bits = zeros(1, framesize);
+ for i=1:Nsymb
+ rx_symb = s_ch(i);
+ if strcmp(modulation,'dqpsk')
+ tmp = rx_symb;
+ rx_symb *= conj(prev_sym_rx/abs(prev_sym_rx));
+ prev_sym_rx = tmp;
+ end
+ rx_bits((2*(i-1)+1):(2*i)) = qpsk_demod(rx_symb);
+ rx_symb_log = [rx_symb_log rx_symb];
+ end
+
+ rx_bits_buf(1:framesize) = rx_bits_buf(framesize+1:2*framesize);
+ rx_bits_buf(framesize+1:2*framesize) = rx_bits;
+ rx_symb_buf(1:Nsymb) = rx_symb_buf(Nsymb+1:2*Nsymb);
+ rx_symb_buf(Nsymb+1:2*Nsymb) = s_ch;
+
+ % determine location of start and end of frame depending on processing delays
+
+ if phase_est
+ st_rx_bits = 1+(floor(Nps/2)+1-1)*Nc*2;
+ st_rx_symb = 1+(floor(Nps/2)+1-1)*Nc;
+ else
+ st_rx_bits = 1;
+ st_rx_symb = 1;
+ end
+ en_rx_bits = st_rx_bits+framesize-1;
+ en_rx_symb = st_rx_symb+Nsymb-1;
+
+ if nn > 1
+ % Measure BER
+
+ %printf("nn: %d centre: %d\n", nn, floor(Nps/2)+1);
+ %tx_bits_buf(1:20)
+ %rx_bits_buf(st_rx_bits:st_rx_bits+20-1)
+ error_positions = xor(rx_bits_buf(st_rx_bits:en_rx_bits), tx_bits_buf(1:framesize));
+ Nerrs = sum(error_positions);
+ Terrs += Nerrs;
+ Tbits += length(tx_bits);
+
+ % Optionally LDPC decode
+
+ if ldpc_code
+ detected_data = ldpc_dec(code_param, max_iterations, demod_type, decoder_type, rx_symb_buf(st_rx_symb:en_rx_symb), min(100,EsNo), hf_fading);
+ %for m=1:20
+ % printf("%f ", qpsk_demod(rx_symb_buf(m)));
+ %end
+ %detected_data(1:19)
+ error_positions = xor( detected_data(1:framesize*rate), tx_bits_buf(1:framesize*rate) );
+ Nerrs = sum(error_positions);
+ if Nerrs
+ Ferrsldpc++;
+ end
+ Terrsldpc += Nerrs;
+ Tbitsldpc += framesize*rate;
+ end
+ end
+ end
+
+ TERvec(ne) = Terrs;
+ BERvec(ne) = Terrs/Tbits;
+ if ldpc_code
+ TERldpcvec(ne) = Terrsldpc;
+ FERldpcvec(ne) = Ferrsldpc;
+ BERldpcvec(ne) = Terrsldpc/Tbitsldpc;
+ end
+
+ if verbose
+ printf("EsNo (dB): %f Terrs: %d BER %f BER theory %f", EsNodB, Terrs,
+ Terrs/Tbits, 0.5*erfc(sqrt(EsNo/2)));
+ if ldpc_code
+ printf(" LDPC: Terrs: %d BER: %f Ferrs: %d FER: %f",
+ Terrsldpc, Terrsldpc/Tbitsldpc, Ferrsldpc, Ferrsldpc/(Ntrials-1));
+ end
+ printf("\n");
+ end
+ if verbose > 1
+ printf("Terrs: %d BER %f BER theory %f C %f N %f Es %f No %f Es/No %f\n\n", Terrs,
+ Terrs/Tbits, 0.5*erfc(sqrt(EsNo/2)), var(tx_symb_log), var(noise_log),
+ var(tx_symb_log), var(noise_log), var(tx_symb_log)/var(noise_log));
+ end
+ end
+
+ Ebvec = Esvec - 10*log10(bps);
+ sim_out.BERvec = BERvec;
+ sim_out.Ebvec = Ebvec;
+ sim_out.TERvec = TERvec;
+ if ldpc_code
+ sim_out.BERldpcvec = BERldpcvec;
+ sim_out.TERldpcvec = TERldpcvec;
+ sim_out.FERldpcvec = FERldpcvec;
+ end
+
+ if plot_scatter
+ figure(2);
+ clf;
+ scat = rx_symb_log .* exp(j*pi/4);
+ plot(real(scat(Nps*Nc:length(scat))), imag(scat(Nps*Nc:length(scat))),'+');
+ title('Scatter plot');
+
+ figure(3);
+ clf;
+
+ y = 1:Rs*2;
+ x = 1:Nc;
+ EsNodBSurface = 20*log10(abs(hf_model(y,:))) - 10*log10(variance);
+ mesh(x,y,EsNodBSurface);
+ grid
+ %axis([1 Nc 1 Rs*2 -10 10])
+ title('HF Channel Es/No');
+
+ figure(4);
+ clf;
+ %mesh(x,y,unwrap(angle(hf_model(y,:))));
+ subplot(211)
+ plot(y,abs(hf_model(y,1)))
+ title('HF Channel Carrier 1 Mag');
+ subplot(212)
+ plot(y,angle(hf_model(y,1)))
+ title('HF Channel Carrier 1 Phase');
+
+ if phase_est
+ scat = ph_est_log(1,floor(Nps/2):Rs*2+floor(Nps/2)-1);
+ hold on;
+ plot(angle(scat),'r');
+ hold off;
+
+ figure(5)
+ clf;
+ scat = ph_est_log(1,y);
+ plot(real(scat), imag(scat),'+');
+ title('Carrier 1 Phase Est');
+ axis([-1 1 -1 1])
+ end
+if 0
+ figure(5);
+ clf;
+ subplot(211)
+ plot(real(spread));
+ hold on;
+ plot(imag(spread),'g');
+ hold off;
+ subplot(212)
+ plot(real(spread_2ms));
+ hold on;
+ plot(imag(spread_2ms),'g');
+ hold off;
+
+ figure(6)
+ tmp = [];
+ for i = 1:hf_n-1
+ tmp = [tmp abs(hf_model(i,:))];
+ end
+ hist(tmp);
+end
+ end
+
+endfunction
+
+% Gray coded QPSK modulation function
+
+function symbol = qpsk_mod(two_bits)
+ two_bits_decimal = sum(two_bits .* [2 1]);
+ switch(two_bits_decimal)
+ case (0) symbol = 1;
+ case (1) symbol = j;
+ case (2) symbol = -j;
+ case (3) symbol = -1;
+ endswitch
+endfunction
+
+% Gray coded QPSK demodulation function
+
+function two_bits = qpsk_demod(symbol)
+ if isscalar(symbol) == 0
+ printf("only works with scalars\n");
+ return;
+ end
+ bit0 = real(symbol*exp(j*pi/4)) < 0;
+ bit1 = imag(symbol*exp(j*pi/4)) < 0;
+ two_bits = [bit1 bit0];
+endfunction
+
+function sim_in = standard_init
+ sim_in.verbose = 1;
+ sim_in.plot_scatter = 0;
+
+ sim_in.Esvec = 5;
+ sim_in.Ntrials = 30;
+ sim_in.framesize = 576;
+ sim_in.Rs = 100;
+ sim_in.Nc = 8;
+
+ sim_in.phase_offset = 0;
+ sim_in.w_offset = 0;
+ sim_in.phase_noise_amp = 0;
+
+ sim_in.hf_delay_ms = 2;
+ sim_in.hf_sim = 0;
+ sim_in.hf_phase_only = 0;
+ sim_in.hf_mag_only = 1;
+
+ sim_in.phase_est = 0;
+ sim_in.phase_est_method = 1;
+ sim_in.Np = 5;
+ sim_in.Ns = 5;
+
+ sim_in.ldpc_code_rate = 1/2;
+ sim_in.ldpc_code = 1;
+endfunction
+
+function ideal
+
+ sim_in = standard_init();
+
+ sim_in.verbose = 1;
+ sim_in.plot_scatter = 1;
+
+ sim_in.Esvec = 5;
+ sim_in.hf_sim = 1;
+ sim_in.Ntrials = 30;
+
+ sim_qpsk_hf = ber_test(sim_in, 'qpsk');
+
+ sim_in.hf_sim = 0;
+ sim_in.plot_scatter = 0;
+ sim_in.Esvec = 2:10;
+ sim_in.ldpc_code = 0;
+ Ebvec = sim_in.Esvec - 10*log10(2);
+ BER_theory = 0.5*erfc(sqrt(10.^(Ebvec/10)));
+ sim_qpsk = ber_test(sim_in, 'qpsk');
+ sim_dqpsk = ber_test(sim_in, 'dqpsk');
+
+ sim_in.hf_sim = 1;
+ sim_qpsk_hf = ber_test(sim_in, 'qpsk');
+ sim_dqpsk_hf = ber_test(sim_in, 'dqpsk');
+ sim_in.ldpc_code_rate = 1/2;
+ sim_in.ldpc_code = 1;
+
+ sim_in.hf_sim = 0;
+ sim_qpsk_ldpc = ber_test(sim_in, 'qpsk');
+
+ sim_in.hf_sim = 1;
+ sim_qpsk_hf_ldpc = ber_test(sim_in, 'qpsk');
+ sim_in.hf_mag_only = 0;
+ sim_dqpsk_hf_ldpc = ber_test(sim_in, 'dqpsk');
+
+ figure(1);
+ clf;
+ semilogy(Ebvec, BER_theory,'r;QPSK theory;')
+ hold on;
+ semilogy(sim_qpsk.Ebvec, sim_qpsk.BERvec,'g;QPSK AWGN;')
+ semilogy(sim_qpsk_hf.Ebvec, sim_qpsk_hf.BERvec,'r;QPSK HF;')
+ semilogy(sim_qpsk_ldpc.Ebvec, sim_qpsk_ldpc.BERldpcvec,'bk;QPSK HF;')
+ semilogy(sim_dqpsk.Ebvec, sim_dqpsk.BERvec,'g;DQPSK AWGN;')
+ semilogy(sim_dqpsk_hf.Ebvec, sim_dqpsk_hf.BERvec,'r;DQPSK HF;')
+ semilogy(sim_qpsk_hf_ldpc.Ebvec, sim_qpsk_hf_ldpc.BERldpcvec,'b;QPSK HF LDPC 1/2;')
+ semilogy(sim_dqpsk_hf_ldpc.Ebvec, sim_dqpsk_hf_ldpc.BERldpcvec,'b;DQPSK HF LDPC 1/2;')
+
+ hold off;
+ xlabel('Eb/N0')
+ ylabel('BER')
+ grid("minor")
+ axis([min(Ebvec) max(Ebvec) 1E-3 1])
+endfunction
+
+function phase_noise
+ sim_in = standard_init();
+
+ sim_in.verbose = 1;
+ sim_in.plot_scatter = 1;
+
+ sim_in.Esvec = 100;
+ sim_in.Ntrials = 30;
+
+ sim_in.ldpc_code_rate = 1/2;
+ sim_in.ldpc_code = 1;
+
+ sim_in.phase_noise_amp = pi/16;
+ tmp = ber_test(sim_in, 'qpsk');
+
+ sim_in.plot_scatter = 0;
+ sim_in.Esvec = 2:8;
+ sim_qpsk_hf = ber_test(sim_in, 'qpsk');
+
+ Ebvec = sim_in.Esvec - 10*log10(2);
+ BER_theory = 0.5*erfc(sqrt(10.^(Ebvec/10)));
+
+ sim_in.phase_noise_amp = 0;
+ sim_qpsk = ber_test(sim_in, 'qpsk');
+ sim_in.phase_noise_amp = pi/8;
+ sim_qpsk_pn8 = ber_test(sim_in, 'qpsk');
+ sim_in.phase_noise_amp = pi/16;
+ sim_qpsk_pn16 = ber_test(sim_in, 'qpsk');
+ sim_in.phase_noise_amp = pi/32;
+ sim_qpsk_pn32 = ber_test(sim_in, 'qpsk');
+
+ figure(1);
+ clf;
+ semilogy(sim_qpsk.Ebvec, sim_qpsk.BERvec,'g;QPSK phase noise 0;')
+ hold on;
+ semilogy(sim_qpsk_pn8.Ebvec, sim_qpsk_pn8.BERvec,'c;QPSK phase noise +/- pi/8;')
+ semilogy(sim_qpsk_pn16.Ebvec, sim_qpsk_pn16.BERvec,'b;QPSK phase noise +/- pi/16;')
+ semilogy(sim_qpsk_pn32.Ebvec, sim_qpsk_pn32.BERvec,'k;QPSK phase noise +/- pi/32;')
+
+ semilogy(sim_qpsk.Ebvec, sim_qpsk.BERldpcvec,'g;QPSK phase noise 0 ldpc;')
+ semilogy(sim_qpsk_pn8.Ebvec, sim_qpsk_pn8.BERldpcvec,'c;QPSK phase noise +/- pi/8 ldpc;')
+ semilogy(sim_qpsk_pn16.Ebvec, sim_qpsk_pn16.BERldpcvec,'b;QPSK phase noise +/- pi/16 ldpc;')
+ semilogy(sim_qpsk_pn32.Ebvec, sim_qpsk_pn32.BERldpcvec,'k;QPSK phase noise +/- pi/32 ldpc;')
+
+ hold off;
+ xlabel('Eb/N0')
+ ylabel('BER')
+ grid("minor")
+ axis([min(Ebvec) max(Ebvec) 1E-2 1])
+endfunction
+
+function test_phase_est
+ sim_in = standard_init();
+
+ sim_in.Rs = 100;
+ sim_in.Nc = 8;
+
+ sim_in.verbose = 1;
+ sim_in.plot_scatter = 1;
+
+ sim_in.Esvec = 5;
+ sim_in.Ntrials = 30;
+
+ sim_in.ldpc_code_rate = 1/2;
+ sim_in.ldpc_code = 1;
+
+ sim_in.phase_est = 1;
+ sim_in.phase_est_method = 2;
+ sim_in.Np = 3;
+ sim_in.phase_offset = 0;
+ sim_in.w_offset = 0;
+
+ sim_in.hf_sim = 1;
+ sim_in.hf_mag_only = 0;
+
+ tmp = ber_test(sim_in, 'qpsk');
+
+endfunction
+
+% Start simulations ---------------------------------------
+
+more off;
+
+ideal();
-% test_qps3k.m\r
-% David Rowe March 2014\r
-%\r
-% QPSK modem simulation, version 2. Simplifed version of\r
-% test_qpsk. Initially based on code by Bill Cowley Generates curves\r
-% BER versus E/No curves for different modems. Design to test\r
-% coherent demodulation ideas on HF channels without building a full\r
-% blown modem. Uses 'genie provided' estimates for timing estimation,\r
-% frame sync.\r
-%\r
-% Compared to test_qsk2.m this version supports phase estimation\r
-% (coherent demod)\r
-\r
-1;\r
-\r
-% main test function \r
-\r
-function sim_out = ber_test(sim_in, modulation)\r
- Fs = 8000;\r
-\r
- newldpc = sim_in.newldpc;\r
- verbose = sim_in.verbose;\r
- framesize = sim_in.framesize;\r
- Ntrials = sim_in.Ntrials;\r
- Esvec = sim_in.Esvec;\r
- phase_offset = sim_in.phase_offset;\r
- phase_est = sim_in.phase_est;\r
- w_offset = sim_in.w_offset;\r
- plot_scatter = sim_in.plot_scatter;\r
- Rs = sim_in.Rs;\r
- hf_sim = sim_in.hf_sim;\r
- nhfdelay = sim_in.hf_delay_ms*Rs/1000;\r
- hf_phase_only = sim_in.hf_phase_only;\r
- hf_mag_only = sim_in.hf_mag_only;\r
- Nc = sim_in.Nc;\r
- sim_coh_dpsk = sim_in.sim_coh_dpsk;\r
-\r
- bps = 2;\r
- Nsymb = framesize/bps;\r
- for k=1:Nc\r
- prev_sym_tx(k) = qpsk_mod([0 0]);\r
- prev_sym_rx(k) = qpsk_mod([0 0]);\r
- end\r
-\r
- phase_est_method = sim_in.phase_est_method;\r
- if phase_est_method == 2\r
- Np = sim_in.Np;\r
- Ns = sim_in.Ns;\r
- if Np/2 == floor(Np/2)\r
- printf("Np must be odd\n");\r
- return;\r
- end\r
- Nps = (Np-1)*Ns+1; \r
- else\r
- Nps = sim_in.Np; \r
- end\r
- r_delay_line = zeros(Nc, Nps);\r
- s_delay_line = zeros(Nc, Nps);\r
- ph_est_log = [];\r
-\r
- phase_noise_amp = sim_in.phase_noise_amp;\r
-\r
- ldpc_code = sim_in.ldpc_code;\r
-\r
- tx_bits_buf = zeros(1,2*framesize);\r
- rx_bits_buf = zeros(1,2*framesize);\r
- rx_symb_buf = zeros(1,2*Nsymb);\r
- hf_fading_buf = zeros(1,2*Nsymb);\r
-\r
- % Init LDPC --------------------------------------------------------------------\r
-\r
- if ldpc_code\r
- % Start CML library\r
-\r
- currentdir = pwd;\r
- addpath '/home/david/tmp/cml/mat' % assume the source files stored here\r
- cd /home/david/tmp/cml\r
- CmlStartup % note that this is not in the cml path!\r
- cd(currentdir)\r
- \r
- % Our LDPC library\r
-\r
- ldpc;\r
-\r
- rate = sim_in.ldpc_code_rate; \r
- mod_order = 4; \r
- modulation2 = 'QPSK';\r
- mapping = 'gray';\r
-\r
- demod_type = 0;\r
- decoder_type = 0;\r
- max_iterations = 100;\r
-\r
- code_param = ldpc_init(rate, framesize, modulation2, mod_order, mapping);\r
- code_param.code_bits_per_frame = framesize;\r
- code_param.symbols_per_frame = framesize/bps;\r
- else\r
- rate = 1;\r
- end\r
-\r
- % Init HF channel model from stored sample files of spreading signal ----------------------------------\r
-\r
- % convert "spreading" samples from 1kHz carrier at Fs to complex\r
- % baseband, generated by passing a 1kHz sine wave through PathSim\r
- % with the ccir-poor model, enabling one path at a time.\r
- \r
- Fc = 1000; M = Fs/Rs;\r
- fspread = fopen("../raw/sine1k_2Hz_spread.raw","rb");\r
- spread1k = fread(fspread, "int16")/10000;\r
- fclose(fspread);\r
- fspread = fopen("../raw/sine1k_2ms_delay_2Hz_spread.raw","rb");\r
- spread1k_2ms = fread(fspread, "int16")/10000;\r
- fclose(fspread);\r
-\r
- % down convert to complex baseband\r
- spreadbb = spread1k.*exp(-j*(2*pi*Fc/Fs)*(1:length(spread1k))');\r
- spreadbb_2ms = spread1k_2ms.*exp(-j*(2*pi*Fc/Fs)*(1:length(spread1k_2ms))');\r
-\r
- % remove -2000 Hz image\r
- b = fir1(50, 5/Fs);\r
- spread = filter(b,1,spreadbb);\r
- spread_2ms = filter(b,1,spreadbb_2ms);\r
-\r
- % discard first 1000 samples as these were near 0, probably as\r
- % PathSim states were ramping up\r
-\r
- spread = spread(1000:length(spread));\r
- spread_2ms = spread_2ms(1000:length(spread_2ms));\r
-\r
- % decimate down to Rs\r
-\r
- spread = spread(1:M:length(spread));\r
- spread_2ms = spread_2ms(1:M:length(spread_2ms));\r
-\r
- % Determine "gain" of HF channel model, so we can normalise\r
- % carrier power during HF channel sim to calibrate SNR. I imagine\r
- % different implementations of ccir-poor would do this in\r
- % different ways, leading to different BER results. Oh Well!\r
-\r
- hf_gain = 1.0/sqrt(var(spread)+var(spread_2ms));\r
-\r
- % Start Simulation ----------------------------------------------------------------\r
-\r
- for ne = 1:length(Esvec)\r
- EsNodB = Esvec(ne);\r
- EsNo = 10^(EsNodB/10);\r
- \r
- variance = 1/EsNo;\r
- if verbose > 1\r
- printf("EsNo (dB): %f EsNo: %f variance: %f\n", EsNodB, EsNo, variance);\r
- end\r
- \r
- Terrs = 0; Tbits = 0; Terrsldpc = 0; Tbitsldpc = 0; Ferrsldpc = 0;\r
-\r
- tx_symb_log = [];\r
- rx_symb_log = [];\r
- noise_log = [];\r
- mod_strip_log = [];\r
- \r
- % init HF channel\r
-\r
- hf_n = 1;\r
- hf_angle_log = [];\r
- hf_fading = ones(1,Nsymb); % default input for ldpc dec\r
- hf_model = ones(Ntrials*Nsymb/Nc, Nc); % defaults for plotting surface\r
-\r
- sim_out.errors_log = [];\r
- sim_out.ldpc_errors_log = [];\r
-\r
- for nn = 1: Ntrials\r
- \r
- tx_bits = round( rand( 1, framesize*rate ) );\r
- \r
- % modulate --------------------------------------------\r
-\r
- if ldpc_code\r
- [tx_bits, s] = ldpc_enc(tx_bits, code_param);\r
- end\r
- s = zeros(1, Nsymb);\r
- for i=1:Nc:Nsymb\r
- for k=1:Nc\r
- tx_symb = qpsk_mod(tx_bits(2*(i-1+k-1)+1:2*(i+k-1)));\r
- if strcmp(modulation,'dqpsk')\r
- tx_symb *= prev_sym_tx(k);\r
- prev_sym_tx(k) = tx_symb;\r
- end \r
- s(i+k-1) = tx_symb;\r
- end\r
- end\r
- tx_bits_buf(1:framesize) = tx_bits_buf(framesize+1:2*framesize);\r
- tx_bits_buf(framesize+1:2*framesize) = tx_bits;\r
- s_ch = s;\r
-\r
- % HF channel simulation ------------------------------------\r
- \r
- if hf_sim\r
-\r
- % separation between carriers. Note this is\r
- % effectively under samples at Rs, I dont think this\r
- % matters. Equivalent to doing freq shift at Fs, then\r
- % decimating to Rs.\r
-\r
- wsep = 2*pi*(1+0.5); % e.g. 75Hz spacing at Rs=50Hz, alpha=0.5 filters\r
-\r
- if Nsymb/Nc != floor(Nsymb/Nc)\r
- printf("Error: Nsymb/Nc must be an integrer\n")\r
- return;\r
- end\r
-\r
- % arrange symbols in Nsymb/Nc by Nc matrix\r
-\r
- for i=1:Nc:Nsymb\r
-\r
- % Determine HF channel at each carrier for this symbol\r
-\r
- for k=1:Nc\r
- hf_model(hf_n, k) = hf_gain*(spread(hf_n) + exp(-j*k*wsep*nhfdelay)*spread_2ms(hf_n));\r
- hf_fading(i+k-1) = abs(hf_model(hf_n, k));\r
- if hf_mag_only\r
- s_ch(i+k-1) *= abs(hf_model(hf_n, k));\r
- else\r
- s_ch(i+k-1) *= hf_model(hf_n, k);\r
- end\r
- end\r
- hf_n++;\r
- end\r
- end\r
- \r
- tx_symb_log = [tx_symb_log s_ch];\r
-\r
- % AWGN noise and phase/freq offset channel simulation\r
- % 0.5 factor ensures var(noise) == variance , i.e. splits power between Re & Im\r
-\r
- noise = sqrt(variance*0.5)*(randn(1,Nsymb) + j*randn(1,Nsymb));\r
- noise_log = [noise_log noise];\r
- phase_noise = phase_noise_amp*(2.0*rand(1,Nsymb)-1.0);\r
- \r
- % organise into carriers to apply frequency and phase offset\r
-\r
- for i=1:Nc:Nsymb\r
- for k=1:Nc\r
- s_ch(i+k-1) = s_ch(i+k-1)*exp(j*(phase_offset+phase_noise(i+k-1))) + noise(i+k-1);\r
- end \r
- phase_offset += w_offset;\r
- end\r
- \r
- % phase estimation\r
- \r
- ph_est = zeros(Nc,1);\r
-\r
- if phase_est\r
-\r
- % organise into carriers\r
-\r
- for i=1:Nc:Nsymb\r
-\r
- for k=1:Nc\r
- centre = floor(Nps/2)+1;\r
-\r
- % delay line for phase est window\r
-\r
- r_delay_line(k,1:Nps-1) = r_delay_line(k,2:Nps);\r
- r_delay_line(k,Nps) = s_ch(i+k-1);\r
-\r
- % delay in tx data to compensate data for phase est window\r
-\r
- s_delay_line(k,1:Nps-1) = s_delay_line(k,2:Nps);\r
- s_delay_line(k,Nps) = s(i+k-1);\r
- \r
- if phase_est_method == 1\r
- % QPSK modulation strip and phase est\r
-\r
- mod_strip_pol = angle(r_delay_line(k,:)) * 4;\r
- mod_strip_rect = exp(j*mod_strip_pol);\r
-\r
- ph_est_pol = atan2(sum(imag(mod_strip_rect)),sum(real(mod_strip_rect)))/4;\r
- ph_est(k) = exp(j*ph_est_pol);\r
-\r
- s_ch(i+k-1) = r_delay_line(k,centre).*exp(-j*ph_est_pol);\r
- % s_ch(i+k-1) = r_delay_line(k,centre);\r
- end\r
-\r
- if phase_est_method == 3\r
- % QPSK modulation strip and phase est with original symbol mags\r
-\r
- mod_strip_pol = angle(r_delay_line(k,:)) * 4;\r
- mod_strip_rect = abs(r_delay_line(k,:)) .* exp(j*mod_strip_pol);\r
-\r
- ph_est_pol = atan2(sum(imag(mod_strip_rect)),sum(real(mod_strip_rect)))/4;\r
- ph_est(k) = exp(j*ph_est_pol);\r
-\r
- s_ch(i+k-1) = r_delay_line(k,centre).*exp(-j*ph_est_pol);\r
- % s_ch(i+k-1) = r_delay_line(k,centre);\r
- end\r
-\r
- if phase_est_method == 2\r
-\r
- % estimate phase from surrounding known pilot symbols and correct\r
-\r
- corr = 0;\r
- for m=1:Ns:Nps\r
- if (m != centre)\r
- corr += s_delay_line(k,m) * r_delay_line(k,m)';\r
- end\r
- end\r
- ph_est(k) = conj(corr/(1E-6+abs(corr)));\r
- s_ch(i+k-1) = r_delay_line(k,centre).*exp(j*angle(corr));\r
- %s_ch(i+k-1) = r_delay_line(k,centre);\r
- end\r
-\r
- end\r
- \r
- ph_est_log = [ph_est_log ph_est];\r
- end \r
- %printf("corr: %f angle: %f\n", corr, angle(corr));\r
- end\r
-\r
- % de-modulate\r
-\r
- rx_bits = zeros(1, framesize);\r
- for i=1:Nc:Nsymb\r
- for k=1:Nc\r
- rx_symb = s_ch(i+k-1);\r
- if strcmp(modulation,'dqpsk')\r
- tmp = rx_symb;\r
- rx_symb *= conj(prev_sym_rx(k)/abs(prev_sym_rx(k)));\r
- if sim_coh_dpsk\r
- prev_sym_rx(k) = qpsk_mod(qpsk_demod(tmp));\r
- else\r
- prev_sym_rx(k) = tmp;\r
- end\r
- s_ch(i+k-1) = rx_symb;\r
- end\r
- rx_bits((2*(i-1+k-1)+1):(2*(i+k-1))) = qpsk_demod(rx_symb);\r
- rx_symb_log = [rx_symb_log rx_symb];\r
- end\r
- end\r
-\r
-if newldpc\r
- rx_bits_buf(1:framesize) = rx_bits_buf(framesize+1:2*framesize);\r
- rx_bits_buf(framesize+1:2*framesize) = rx_bits;\r
- rx_symb_buf(1:Nsymb) = rx_symb_buf(Nsymb+1:2*Nsymb);\r
- rx_symb_buf(Nsymb+1:2*Nsymb) = s_ch;\r
- hf_fading_buf(1:Nsymb) = hf_fading_buf(Nsymb+1:2*Nsymb);\r
- hf_fading_buf(Nsymb+1:2*Nsymb) = hf_fading;\r
-\r
- % determine location of start and end of frame depending on processing delays\r
-\r
- if phase_est\r
- st_rx_bits = 1+(floor(Nps/2)+1-1)*Nc*2;\r
- st_rx_symb = 1+(floor(Nps/2)+1-1)*Nc;\r
- else\r
- st_rx_bits = 1;\r
- st_rx_symb = 1;\r
- end\r
- en_rx_bits = st_rx_bits+framesize-1;\r
- en_rx_symb = st_rx_symb+Nsymb-1;\r
-\r
- if nn > 1\r
- % Measure BER\r
-\r
- %printf("nn: %d centre: %d\n", nn, floor(Nps/2)+1);\r
- %tx_bits_buf(1:20)\r
- %rx_bits_buf(st_rx_bits:st_rx_bits+20-1)\r
- error_positions = xor(rx_bits_buf(st_rx_bits:en_rx_bits), tx_bits_buf(1:framesize));\r
- Nerrs = sum(error_positions);\r
- sim_out.errors_log = [sim_out.errors_log error_positions];\r
- Terrs += Nerrs;\r
- Tbits += length(tx_bits);\r
-\r
- % Optionally LDPC decode\r
- \r
- if ldpc_code\r
- detected_data = ldpc_dec(code_param, max_iterations, demod_type, decoder_type, ...\r
- rx_symb_buf(st_rx_symb:en_rx_symb), min(100,EsNo), hf_fading_buf(1:Nsymb));\r
- error_positions = xor( detected_data(1:framesize*rate), tx_bits_buf(1:framesize*rate) );\r
- %detected_data = ldpc_dec(code_param, max_iterations, demod_type, decoder_type, s_ch, min(100,EsNo), hf_fading);\r
- %error_positions = xor( detected_data(1:framesize*rate), tx_bits(1:framesize*rate) );\r
- Nerrs = sum(error_positions);\r
- sim_out.ldpc_errors_log = [sim_out.ldpc_errors_log error_positions];\r
- if Nerrs\r
- Ferrsldpc++;\r
- end\r
- Terrsldpc += Nerrs;\r
- Tbitsldpc += framesize*rate;\r
- end\r
- end\r
-\r
-else \r
- error_positions = xor(rx_bits, tx_bits);\r
- Nerrs = sum(error_positions);\r
- Terrs += Nerrs;\r
- Tbits += length(tx_bits);\r
-\r
- % Optionally LDPC decode\r
- \r
- if ldpc_code\r
- detected_data = ldpc_dec(code_param, max_iterations, demod_type, decoder_type, s_ch, min(100,EsNo), hf_fading);\r
- error_positions = xor( detected_data(1:framesize*rate), tx_bits(1:framesize*rate) );\r
- Nerrs = sum(error_positions);\r
- if Nerrs\r
- Ferrsldpc++;\r
- end\r
- Terrsldpc += Nerrs;\r
- Tbitsldpc += framesize*rate;\r
-\r
- end\r
- end\r
-end\r
-\r
- TERvec(ne) = Terrs;\r
- BERvec(ne) = Terrs/Tbits;\r
- if ldpc_code\r
- TERldpcvec(ne) = Terrsldpc;\r
- FERldpcvec(ne) = Ferrsldpc;\r
- BERldpcvec(ne) = Terrsldpc/Tbitsldpc;\r
- end\r
-\r
- if verbose \r
- printf("EsNo (dB): %f Terrs: %d BER %f BER theory %f", EsNodB, Terrs,\r
- Terrs/Tbits, 0.5*erfc(sqrt(EsNo/2)));\r
- if ldpc_code\r
- printf(" LDPC: Terrs: %d BER: %f Ferrs: %d FER: %f", \r
- Terrsldpc, Terrsldpc/Tbitsldpc, Ferrsldpc, Ferrsldpc/(Ntrials-1));\r
- end\r
- printf("\n");\r
- end\r
- if verbose > 1\r
- printf("Terrs: %d BER %f BER theory %f C %f N %f Es %f No %f Es/No %f\n\n", Terrs,\r
- Terrs/Tbits, 0.5*erfc(sqrt(EsNo/2)), var(tx_symb_log), var(noise_log),\r
- var(tx_symb_log), var(noise_log), var(tx_symb_log)/var(noise_log));\r
- end\r
- end\r
- \r
- Ebvec = Esvec - 10*log10(bps);\r
-\r
- % account for extra power rqd for pilot symbols\r
-\r
- if (phase_est_method == 2) && (phase_est)\r
- Ebvec += 10*log10(Ns/(Ns-1));\r
- end\r
-\r
- sim_out.BERvec = BERvec;\r
- sim_out.Ebvec = Ebvec;\r
- sim_out.TERvec = TERvec;\r
- if ldpc_code\r
- sim_out.BERldpcvec = BERldpcvec;\r
- sim_out.TERldpcvec = TERldpcvec;\r
- sim_out.FERldpcvec = FERldpcvec;\r
- end\r
-\r
- if plot_scatter\r
- figure(2);\r
- clf;\r
- scat = rx_symb_log .* exp(j*pi/4);\r
- plot(real(scat(Nps*Nc:length(scat))), imag(scat(Nps*Nc:length(scat))),'+');\r
- title('Scatter plot');\r
-\r
- figure(3);\r
- clf;\r
- \r
- y = 1:Rs*2;\r
- x = 1:Nc;\r
- EsNodBSurface = 20*log10(abs(hf_model(y,:))) - 10*log10(variance);\r
- mesh(x,y,EsNodBSurface);\r
- grid\r
- %axis([1 Nc 1 Rs*2 -10 10])\r
- title('HF Channel Es/No');\r
-\r
- figure(4);\r
- clf;\r
- %mesh(x,y,unwrap(angle(hf_model(y,:))));\r
- subplot(211)\r
- plot(y,abs(hf_model(y,1)))\r
- title('HF Channel Carrier 1 Mag');\r
- subplot(212)\r
- plot(y,angle(hf_model(y,1)))\r
- title('HF Channel Carrier 1 Phase');\r
-\r
- if phase_est\r
- scat = ph_est_log(1,floor(Nps/2):Rs*2+floor(Nps/2)-1);\r
- hold on;\r
- plot(angle(scat),'r');\r
- hold off;\r
-\r
- figure(5)\r
- clf;\r
- scat = ph_est_log(1,y);\r
- plot(real(scat), imag(scat),'+');\r
- title('Carrier 1 Phase Est');\r
- axis([-1 1 -1 1])\r
- end\r
-if 0 \r
- figure(5);\r
- clf;\r
- subplot(211)\r
- plot(real(spread));\r
- hold on;\r
- plot(imag(spread),'g'); \r
- hold off; \r
- subplot(212)\r
- plot(real(spread_2ms));\r
- hold on;\r
- plot(imag(spread_2ms),'g'); \r
- hold off; \r
-\r
- figure(6)\r
- tmp = [];\r
- for i = 1:hf_n-1\r
- tmp = [tmp abs(hf_model(i,:))];\r
- end\r
- hist(tmp);\r
-end\r
- end\r
-\r
-size(sim_out.errors_log)\r
-\r
-endfunction\r
-\r
-% Gray coded QPSK modulation function\r
-\r
-function symbol = qpsk_mod(two_bits)\r
- two_bits_decimal = sum(two_bits .* [2 1]); \r
- switch(two_bits_decimal)\r
- case (0) symbol = 1;\r
- case (1) symbol = j;\r
- case (2) symbol = -j;\r
- case (3) symbol = -1;\r
- endswitch\r
-endfunction\r
-\r
-% Gray coded QPSK demodulation function\r
-\r
-function two_bits = qpsk_demod(symbol)\r
- if isscalar(symbol) == 0\r
- printf("only works with scalars\n");\r
- return;\r
- end\r
- bit0 = real(symbol*exp(j*pi/4)) < 0;\r
- bit1 = imag(symbol*exp(j*pi/4)) < 0;\r
- two_bits = [bit1 bit0];\r
-endfunction\r
-\r
-function sim_in = standard_init\r
- sim_in.verbose = 1;\r
- sim_in.plot_scatter = 0;\r
-\r
- sim_in.Esvec = 5; \r
- sim_in.Ntrials = 30;\r
- sim_in.framesize = 576;\r
- sim_in.Rs = 100;\r
- sim_in.Nc = 8;\r
-\r
- sim_in.phase_offset = 0;\r
- sim_in.w_offset = 0;\r
- sim_in.phase_noise_amp = 0;\r
-\r
- sim_in.hf_delay_ms = 2;\r
- sim_in.hf_sim = 0;\r
- sim_in.hf_phase_only = 0;\r
- sim_in.hf_mag_only = 1;\r
-\r
- sim_in.phase_est = 0;\r
- sim_in.phase_est_method = 1;\r
- sim_in.Np = 5;\r
- sim_in.Ns = 5;\r
-\r
- sim_in.ldpc_code_rate = 1/2;\r
- sim_in.ldpc_code = 1;\r
-endfunction\r
-\r
-function ideal\r
-\r
- sim_in = standard_init();\r
-\r
- sim_in.sim_coh_dpsk = 0;\r
- sim_in.newldpc = 1;\r
- sim_in.verbose = 2;\r
- sim_in.plot_scatter = 1;\r
-\r
- sim_in.Esvec = 5; \r
- sim_in.hf_sim = 1;\r
- sim_in.Ntrials = 30;\r
-\r
- sim_qpsk_hf = ber_test(sim_in, 'qpsk');\r
-\r
- sim_in.hf_sim = 0;\r
- sim_in.plot_scatter = 0;\r
- sim_in.Esvec = 2:15; \r
- sim_in.ldpc_code = 0;\r
- Ebvec = sim_in.Esvec - 10*log10(2);\r
- BER_theory = 0.5*erfc(sqrt(10.^(Ebvec/10)));\r
- sim_qpsk = ber_test(sim_in, 'qpsk');\r
- sim_dqpsk = ber_test(sim_in, 'dqpsk');\r
-\r
- sim_in.hf_sim = 1;\r
- sim_in.Esvec = 2:15; \r
- sim_qpsk_hf = ber_test(sim_in, 'qpsk');\r
- sim_dqpsk_hf = ber_test(sim_in, 'dqpsk');\r
- sim_in.ldpc_code = 1;\r
- sim_in.ldpc_code_rate = 3/4;\r
- sim_qpsk_hf_ldpc1 = ber_test(sim_in, 'qpsk');\r
- sim_in.ldpc_code_rate = 1/2;\r
- sim_qpsk_hf_ldpc2 = ber_test(sim_in, 'qpsk');\r
- sim_in.ldpc_code_rate = 3/4;\r
- sim_in.hf_sim = 0;\r
- sim_qpsk_awgn_ldpc = ber_test(sim_in, 'qpsk');\r
-\r
- figure(1); \r
- clf;\r
- semilogy(Ebvec, BER_theory,'r;QPSK theory;')\r
- hold on;\r
- semilogy(sim_qpsk.Ebvec, sim_qpsk.BERvec,'g;QPSK AWGN;')\r
- semilogy(sim_qpsk_hf.Ebvec, sim_qpsk_hf.BERvec,'r;QPSK HF;')\r
- semilogy(sim_dqpsk.Ebvec, sim_dqpsk.BERvec,'c;DQPSK AWGN;')\r
- semilogy(sim_dqpsk_hf.Ebvec, sim_dqpsk_hf.BERvec,'m;DQPSK HF;')\r
- semilogy(sim_qpsk_hf_ldpc1.Ebvec, sim_qpsk_hf_ldpc1.BERldpcvec,'k;QPSK HF LDPC 3/4;')\r
- semilogy(sim_qpsk_hf_ldpc2.Ebvec, sim_qpsk_hf_ldpc2.BERldpcvec,'b;QPSK HF LDPC 1/2;')\r
- semilogy(sim_qpsk_awgn_ldpc.Ebvec, sim_qpsk_awgn_ldpc.BERldpcvec,'k;QPSK AWGN LDPC 3/4;')\r
-\r
- hold off;\r
- xlabel('Eb/N0')\r
- ylabel('BER')\r
- grid("minor")\r
- axis([min(Ebvec) max(Ebvec) 1E-3 1])\r
-endfunction\r
-\r
-function phase_noise\r
- sim_in = standard_init();\r
-\r
- sim_in.verbose = 1;\r
- sim_in.plot_scatter = 1;\r
-\r
- sim_in.Esvec = 100; \r
- sim_in.Ntrials = 100;\r
-\r
- sim_in.ldpc_code_rate = 1/2;\r
- sim_in.ldpc_code = 1;\r
-\r
- sim_in.phase_noise_amp = pi/16;\r
- tmp = ber_test(sim_in, 'qpsk');\r
-\r
- sim_in.plot_scatter = 0;\r
- sim_in.Esvec = 2:8; \r
- sim_qpsk_hf = ber_test(sim_in, 'qpsk');\r
-\r
- Ebvec = sim_in.Esvec - 10*log10(2);\r
- BER_theory = 0.5*erfc(sqrt(10.^(Ebvec/10)));\r
-\r
- sim_in.phase_noise_amp = 0;\r
- sim_qpsk = ber_test(sim_in, 'qpsk');\r
- sim_in.phase_noise_amp = pi/8;\r
- sim_qpsk_pn8 = ber_test(sim_in, 'qpsk');\r
- sim_in.phase_noise_amp = pi/16;\r
- sim_qpsk_pn16 = ber_test(sim_in, 'qpsk');\r
- sim_in.phase_noise_amp = pi/32;\r
- sim_qpsk_pn32 = ber_test(sim_in, 'qpsk');\r
-\r
- figure(1); \r
- clf;\r
- semilogy(sim_qpsk.Ebvec, sim_qpsk.BERvec,'g;QPSK phase noise 0;')\r
- hold on;\r
- semilogy(sim_qpsk_pn8.Ebvec, sim_qpsk_pn8.BERvec,'c;QPSK phase noise +/- pi/8;')\r
- semilogy(sim_qpsk_pn16.Ebvec, sim_qpsk_pn16.BERvec,'b;QPSK phase noise +/- pi/16;')\r
- semilogy(sim_qpsk_pn32.Ebvec, sim_qpsk_pn32.BERvec,'k;QPSK phase noise +/- pi/32;')\r
-\r
- semilogy(sim_qpsk.Ebvec, sim_qpsk.BERldpcvec,'g;QPSK phase noise 0 ldpc;')\r
- semilogy(sim_qpsk_pn8.Ebvec, sim_qpsk_pn8.BERldpcvec,'c;QPSK phase noise +/- pi/8 ldpc;')\r
- semilogy(sim_qpsk_pn16.Ebvec, sim_qpsk_pn16.BERldpcvec,'b;QPSK phase noise +/- pi/16 ldpc;')\r
- semilogy(sim_qpsk_pn32.Ebvec, sim_qpsk_pn32.BERldpcvec,'k;QPSK phase noise +/- pi/32 ldpc;')\r
-\r
- hold off;\r
- xlabel('Eb/N0')\r
- ylabel('BER')\r
- grid("minor")\r
- axis([min(Ebvec) max(Ebvec) 1E-2 1])\r
-endfunction\r
-\r
-function phase_est_hf\r
- sim_in = standard_init();\r
-\r
- sim_in.Rs = 100;\r
- sim_in.Nc = 8;\r
-\r
- sim_in.verbose = 1;\r
- sim_in.plot_scatter = 0;\r
-\r
- sim_in.Esvec = 5:15; \r
- sim_in.Ntrials = 100;\r
-\r
- sim_in.newldpc = 1;\r
- sim_in.ldpc_code_rate = 1/2;\r
- sim_in.ldpc_code = 1;\r
-\r
- sim_in.phase_est = 0;\r
- sim_in.sim_coh_dpsk = 0;\r
- sim_in.phase_est_method = 2;\r
- sim_in.Np = 3;\r
- sim_in.phase_offset = 0;\r
- sim_in.w_offset = 0;\r
-\r
- sim_in.hf_sim = 1;\r
- sim_in.hf_mag_only = 1;\r
-\r
- Ebvec = sim_in.Esvec - 10*log10(2);\r
-\r
- baseline = ber_test(sim_in, 'qpsk');\r
-\r
- sim_in.hf_mag_only = 0;\r
- sim_in.phase_est_method = 2;\r
- sim_in.phase_est = 1;\r
- sim_in.Np = 3;\r
- pilot_3 = ber_test(sim_in, 'qpsk');\r
- sim_in.Np = 5;\r
- pilot_5 = ber_test(sim_in, 'qpsk');\r
- sim_in.Np = 7;\r
- pilot_7 = ber_test(sim_in, 'qpsk');\r
-\r
-if 1\r
- sim_in.phase_est = 0;\r
- dqpsk = ber_test(sim_in, 'dqpsk');\r
-\r
- figure(1); \r
- clf;\r
- semilogy(baseline.Ebvec, baseline.BERvec,'r;QPSK CCIR poor;')\r
- hold on;\r
- semilogy(baseline.Ebvec, baseline.BERldpcvec,'r;QPSK CCIR poor ldpc;')\r
- semilogy(pilot_3.Ebvec, pilot_3.BERvec,'b;QPSK CCIR poor ldpc pilot 3;')\r
- semilogy(pilot_3.Ebvec, pilot_3.BERldpcvec,'b;QPSK CCIR poor ldpc pilot 3;')\r
- semilogy(pilot_5.Ebvec, pilot_5.BERvec,'g;QPSK CCIR poor ldpc pilot 5;')\r
- semilogy(pilot_5.Ebvec, pilot_5.BERldpcvec,'g;QPSK CCIR poor ldpc pilot 5;')\r
- semilogy(pilot_7.Ebvec, pilot_7.BERvec,'m;QPSK CCIR poor ldpc pilot 7;')\r
- semilogy(pilot_7.Ebvec, pilot_7.BERldpcvec,'m;QPSK CCIR poor ldpc pilot 7;')\r
- semilogy(dqpsk.Ebvec, dqpsk.BERvec,'k;DQPSK CCIR poor ldpc;')\r
- semilogy(dqpsk.Ebvec, dqpsk.BERldpcvec,'k;DQPSK CCIR poor ldpc;')\r
-\r
- hold off;\r
- xlabel('Eb/N0')\r
- ylabel('BER')\r
- grid("minor")\r
- axis([min(Ebvec) max(Ebvec) 1E-2 1])\r
-end\r
-endfunction\r
-\r
-function phase_est_awgn\r
- sim_in = standard_init();\r
-\r
- sim_in.Rs = 100;\r
- sim_in.Nc = 8;\r
-\r
- sim_in.verbose = 1;\r
- sim_in.plot_scatter = 0;\r
-\r
- sim_in.Esvec = 0:0.5:3; \r
- sim_in.Ntrials = 30;\r
-\r
- sim_in.newldpc = 1;\r
- sim_in.ldpc_code_rate = 1/2;\r
- sim_in.ldpc_code = 1;\r
-\r
- sim_in.phase_est = 0;\r
- sim_in.phase_est_method = 1;\r
- sim_in.Np = 3;\r
- sim_in.phase_offset = 0;\r
- sim_in.w_offset = 0;\r
-\r
- sim_in.hf_sim = 0;\r
- sim_in.hf_mag_only = 1;\r
-\r
- ideal = ber_test(sim_in, 'qpsk');\r
-\r
- sim_in.phase_est = 1;\r
- sim_in.Np = 21;\r
- sim_in.phase_est_method = 3;\r
- strip_21_mag = ber_test(sim_in, 'qpsk');\r
-\r
- sim_in.Np = 41;\r
- strip_41_mag = ber_test(sim_in, 'qpsk');\r
-\r
- sim_in.phase_est_method = 1;\r
- sim_in.Np = 21;\r
- strip_21 = ber_test(sim_in, 'qpsk');\r
-\r
- sim_in.Np = 41;\r
- strip_41 = ber_test(sim_in, 'qpsk');\r
-\r
- sim_in.Np = 7;\r
- sim_in.phase_est_method = 2;\r
- pilot_7 = ber_test(sim_in, 'qpsk');\r
-\r
- Ebvec = sim_in.Esvec - 10*log10(2);\r
-\r
- figure(1); \r
- clf;\r
- semilogy(ideal.Ebvec, ideal.BERvec,'r;QPSK;')\r
- hold on;\r
- semilogy(ideal.Ebvec, ideal.BERldpcvec,'r;QPSK LDPC;')\r
- semilogy(strip_21.Ebvec, strip_21.BERvec,'g;QPSK strip 21;')\r
- semilogy(strip_21.Ebvec, strip_21.BERldpcvec,'g;QPSK LDPC strip 21;')\r
- semilogy(strip_41.Ebvec, strip_41.BERvec,'b;QPSK strip 41;')\r
- semilogy(strip_41.Ebvec, strip_41.BERldpcvec,'b;QPSK LDPC strip 41;')\r
- semilogy(strip_21_mag.Ebvec, strip_21_mag.BERvec,'m;QPSK strip 21 mag;')\r
- semilogy(strip_21_mag.Ebvec, strip_21_mag.BERldpcvec,'m;QPSK LDPC strip 21 mag;')\r
- semilogy(strip_41_mag.Ebvec, strip_41_mag.BERvec,'c;QPSK strip 41 mag;')\r
- semilogy(strip_41_mag.Ebvec, strip_41_mag.BERldpcvec,'c;QPSK LDPC strip 41 mag;')\r
- semilogy(pilot_7.Ebvec, pilot_7.BERvec,'k;QPSK pilot 7;')\r
- semilogy(pilot_7.Ebvec, pilot_7.BERldpcvec,'k;QPSK LDPC pilot 7;')\r
-\r
- hold off;\r
- xlabel('Eb/N0')\r
- ylabel('BER')\r
- grid("minor")\r
- axis([min(Ebvec) max(Ebvec) 1E-2 1])\r
-endfunction\r
-\r
-function test_dpsk\r
- sim_in = standard_init();\r
-\r
- sim_in.Rs = 100;\r
- sim_in.Nc = 8;\r
-\r
- sim_in.verbose = 1;\r
- sim_in.plot_scatter = 0;\r
-\r
- sim_in.Esvec = 5; \r
- sim_in.Ntrials = 30;\r
-\r
- sim_in.newldpc = 1;\r
- sim_in.ldpc_code_rate = 1/2;\r
- sim_in.ldpc_code = 1;\r
-\r
- sim_in.phase_est = 0;\r
- sim_in.phase_est_method = 3;\r
- sim_in.Np = 41;\r
- sim_in.phase_offset = 0;\r
- sim_in.w_offset = 0;\r
- sim_in.sim_coh_dpsk = 0;\r
-\r
- sim_in.hf_sim = 0;\r
- sim_in.hf_mag_only = 1;\r
-\r
- Ebvec = sim_in.Esvec - 10*log10(2);\r
-\r
- baseline = ber_test(sim_in, 'qpsk');\r
- sim_in.phase_est = 0;\r
- dqpsk = ber_test(sim_in, 'dqpsk');\r
-\r
- sim_in.phase_est = 1;\r
- sim_in.phase_est_method = 3;\r
- sim_in.sim_coh_dpsk = 1;\r
- sim_in.Np = 41;\r
- dqpsk_strip_41 = ber_test(sim_in, 'dqpsk');\r
- \r
- figure(1); \r
- clf;\r
- semilogy(baseline.Ebvec, baseline.BERvec,'r;QPSK CCIR poor;')\r
- hold on;\r
- semilogy(baseline.Ebvec, baseline.BERldpcvec,'r;QPSK CCIR poor ldpc;')\r
- semilogy(dqpsk.Ebvec, dqpsk.BERvec,'c;DQPSK CCIR poor ldpc;')\r
- semilogy(dqpsk.Ebvec, dqpsk.BERldpcvec,'c;DQPSK CCIR poor ldpc;')\r
- semilogy(dqpsk_strip_41.Ebvec, dqpsk_strip_41.BERvec,'m;DQPSK CCIR poor ldpc strip 41;')\r
- semilogy(dqpsk_strip_41.Ebvec, dqpsk_strip_41.BERldpcvec,'m;DQPSK CCIR poor ldpc strip 41;')\r
-\r
- hold off;\r
- xlabel('Eb/N0')\r
- ylabel('BER')\r
- grid("minor")\r
- axis([min(Ebvec) max(Ebvec) 1E-2 1])\r
-\r
-endfunction\r
-\r
-function gen_error_pattern_qpsk()\r
- sim_in = standard_init();\r
-\r
- % model codec and uncoded streams as 1000 bit/s each\r
-\r
- sim_in.Rs = 100;\r
- sim_in.Nc = 4;\r
-\r
- sim_in.verbose = 1;\r
- sim_in.plot_scatter = 0;\r
-\r
- sim_in.Esvec = 10; % Eb/No=2dB\r
- sim_in.Ntrials = 30;\r
-\r
- sim_in.newldpc = 1;\r
- sim_in.ldpc_code_rate = 1/2;\r
- sim_in.ldpc_code = 1;\r
-\r
- sim_in.phase_est = 1;\r
- sim_in.phase_est_method = 2;\r
- sim_in.Np = 5;\r
- sim_in.phase_offset = 0;\r
- sim_in.w_offset = 0;\r
- sim_in.sim_coh_dpsk = 0;\r
-\r
- sim_in.hf_sim = 1;\r
- sim_in.hf_mag_only = 0;\r
-\r
- qpsk = ber_test(sim_in, 'qpsk');\r
- \r
- length(qpsk.errors_log) \r
- length(qpsk.ldpc_errors_log)\r
- % multiplex errors into prot and unprot halves of 52 bit codec frames\r
-\r
- error_pattern = [];\r
- for i=1:26:length(qpsk.ldpc_errors_log)-52\r
- error_pattern = [error_pattern qpsk.ldpc_errors_log(i:i+25) qpsk.errors_log(i:i+25) zeros(1,4)];\r
- %error_pattern = [error_pattern qpsk.ldpc_errors_log(i:i+25) zeros(1,26) zeros(1,4)];\r
- %error_pattern = [error_pattern zeros(1,26) qpsk.errors_log(i:i+25) zeros(1,4)];\r
- end\r
-\r
- fep=fopen("qpsk_errors_2dB.bin","wb"); fwrite(fep, error_pattern, "short"); fclose(fep);\r
-\r
-endfunction\r
-\r
-function gen_error_pattern_dpsk()\r
- sim_in = standard_init();\r
-\r
- sim_in.Rs = 50;\r
- sim_in.Nc = 16;\r
-\r
- sim_in.verbose = 1;\r
- sim_in.plot_scatter = 1;\r
-\r
- sim_in.Esvec = 10; % Eb/No=Es/No-3\r
- sim_in.Ntrials = 30;\r
-\r
- sim_in.newldpc = 1;\r
- sim_in.ldpc_code_rate = 1/2;\r
- sim_in.ldpc_code = 0;\r
-\r
- sim_in.phase_est = 0;\r
- sim_in.phase_est_method = 3;\r
- sim_in.Np = 41;\r
- sim_in.phase_offset = 0;\r
- sim_in.w_offset = 0;\r
- sim_in.sim_coh_dpsk = 0;\r
-\r
- sim_in.hf_sim = 1;\r
- sim_in.hf_mag_only = 1;\r
-\r
- dqpsk = ber_test(sim_in, 'dqpsk');\r
- \r
- fep=fopen("dqpsk_errors_12dB.bin","wb"); fwrite(fep, dqpsk.errors_log, "short"); fclose(fep);\r
-\r
-endfunction\r
-\r
-% Start simulations ---------------------------------------\r
-\r
-more off;\r
-\r
-ideal();\r
-%phase_est_hf();\r
-%phase_est_awgn();\r
-%test_dpsk();\r
-%gen_error_pattern_qpsk\r
+% test_qps3k.m
+% David Rowe March 2014
+%
+% QPSK modem simulation, version 2. Simplifed version of
+% test_qpsk. Initially based on code by Bill Cowley Generates curves
+% BER versus E/No curves for different modems. Design to test
+% coherent demodulation ideas on HF channels without building a full
+% blown modem. Uses 'genie provided' estimates for timing estimation,
+% frame sync.
+%
+% Compared to test_qsk2.m this version supports phase estimation
+% (coherent demod)
+
+1;
+
+% main test function
+
+function sim_out = ber_test(sim_in, modulation)
+ Fs = 8000;
+
+ newldpc = sim_in.newldpc;
+ verbose = sim_in.verbose;
+ framesize = sim_in.framesize;
+ Ntrials = sim_in.Ntrials;
+ Esvec = sim_in.Esvec;
+ phase_offset = sim_in.phase_offset;
+ phase_est = sim_in.phase_est;
+ w_offset = sim_in.w_offset;
+ plot_scatter = sim_in.plot_scatter;
+ Rs = sim_in.Rs;
+ hf_sim = sim_in.hf_sim;
+ nhfdelay = sim_in.hf_delay_ms*Rs/1000;
+ hf_phase_only = sim_in.hf_phase_only;
+ hf_mag_only = sim_in.hf_mag_only;
+ Nc = sim_in.Nc;
+ sim_coh_dpsk = sim_in.sim_coh_dpsk;
+
+ bps = 2;
+ Nsymb = framesize/bps;
+ for k=1:Nc
+ prev_sym_tx(k) = qpsk_mod([0 0]);
+ prev_sym_rx(k) = qpsk_mod([0 0]);
+ end
+
+ phase_est_method = sim_in.phase_est_method;
+ if phase_est_method == 2
+ Np = sim_in.Np;
+ Ns = sim_in.Ns;
+ if Np/2 == floor(Np/2)
+ printf("Np must be odd\n");
+ return;
+ end
+ Nps = (Np-1)*Ns+1;
+ else
+ Nps = sim_in.Np;
+ end
+ r_delay_line = zeros(Nc, Nps);
+ s_delay_line = zeros(Nc, Nps);
+ ph_est_log = [];
+
+ phase_noise_amp = sim_in.phase_noise_amp;
+
+ ldpc_code = sim_in.ldpc_code;
+
+ tx_bits_buf = zeros(1,2*framesize);
+ rx_bits_buf = zeros(1,2*framesize);
+ rx_symb_buf = zeros(1,2*Nsymb);
+ hf_fading_buf = zeros(1,2*Nsymb);
+
+ % Init LDPC --------------------------------------------------------------------
+
+ if ldpc_code
+ % Start CML library
+
+ currentdir = pwd;
+ addpath '/home/david/tmp/cml/mat' % assume the source files stored here
+ cd /home/david/tmp/cml
+ CmlStartup % note that this is not in the cml path!
+ cd(currentdir)
+
+ % Our LDPC library
+
+ ldpc;
+
+ rate = sim_in.ldpc_code_rate;
+ mod_order = 4;
+ modulation2 = 'QPSK';
+ mapping = 'gray';
+
+ demod_type = 0;
+ decoder_type = 0;
+ max_iterations = 100;
+
+ code_param = ldpc_init(rate, framesize, modulation2, mod_order, mapping);
+ code_param.code_bits_per_frame = framesize;
+ code_param.symbols_per_frame = framesize/bps;
+ else
+ rate = 1;
+ end
+
+ % Init HF channel model from stored sample files of spreading signal ----------------------------------
+
+ % convert "spreading" samples from 1kHz carrier at Fs to complex
+ % baseband, generated by passing a 1kHz sine wave through PathSim
+ % with the ccir-poor model, enabling one path at a time.
+
+ Fc = 1000; M = Fs/Rs;
+ fspread = fopen("../raw/sine1k_2Hz_spread.raw","rb");
+ spread1k = fread(fspread, "int16")/10000;
+ fclose(fspread);
+ fspread = fopen("../raw/sine1k_2ms_delay_2Hz_spread.raw","rb");
+ spread1k_2ms = fread(fspread, "int16")/10000;
+ fclose(fspread);
+
+ % down convert to complex baseband
+ spreadbb = spread1k.*exp(-j*(2*pi*Fc/Fs)*(1:length(spread1k))');
+ spreadbb_2ms = spread1k_2ms.*exp(-j*(2*pi*Fc/Fs)*(1:length(spread1k_2ms))');
+
+ % remove -2000 Hz image
+ b = fir1(50, 5/Fs);
+ spread = filter(b,1,spreadbb);
+ spread_2ms = filter(b,1,spreadbb_2ms);
+
+ % discard first 1000 samples as these were near 0, probably as
+ % PathSim states were ramping up
+
+ spread = spread(1000:length(spread));
+ spread_2ms = spread_2ms(1000:length(spread_2ms));
+
+ % decimate down to Rs
+
+ spread = spread(1:M:length(spread));
+ spread_2ms = spread_2ms(1:M:length(spread_2ms));
+
+ % Determine "gain" of HF channel model, so we can normalise
+ % carrier power during HF channel sim to calibrate SNR. I imagine
+ % different implementations of ccir-poor would do this in
+ % different ways, leading to different BER results. Oh Well!
+
+ hf_gain = 1.0/sqrt(var(spread)+var(spread_2ms));
+
+ % Start Simulation ----------------------------------------------------------------
+
+ for ne = 1:length(Esvec)
+ EsNodB = Esvec(ne);
+ EsNo = 10^(EsNodB/10);
+
+ variance = 1/EsNo;
+ if verbose > 1
+ printf("EsNo (dB): %f EsNo: %f variance: %f\n", EsNodB, EsNo, variance);
+ end
+
+ Terrs = 0; Tbits = 0; Terrsldpc = 0; Tbitsldpc = 0; Ferrsldpc = 0;
+
+ tx_symb_log = [];
+ rx_symb_log = [];
+ noise_log = [];
+ mod_strip_log = [];
+
+ % init HF channel
+
+ hf_n = 1;
+ hf_angle_log = [];
+ hf_fading = ones(1,Nsymb); % default input for ldpc dec
+ hf_model = ones(Ntrials*Nsymb/Nc, Nc); % defaults for plotting surface
+
+ sim_out.errors_log = [];
+ sim_out.ldpc_errors_log = [];
+
+ for nn = 1: Ntrials
+
+ tx_bits = round( rand( 1, framesize*rate ) );
+
+ % modulate --------------------------------------------
+
+ if ldpc_code
+ [tx_bits, s] = ldpc_enc(tx_bits, code_param);
+ end
+ s = zeros(1, Nsymb);
+ for i=1:Nc:Nsymb
+ for k=1:Nc
+ tx_symb = qpsk_mod(tx_bits(2*(i-1+k-1)+1:2*(i+k-1)));
+ if strcmp(modulation,'dqpsk')
+ tx_symb *= prev_sym_tx(k);
+ prev_sym_tx(k) = tx_symb;
+ end
+ s(i+k-1) = tx_symb;
+ end
+ end
+ tx_bits_buf(1:framesize) = tx_bits_buf(framesize+1:2*framesize);
+ tx_bits_buf(framesize+1:2*framesize) = tx_bits;
+ s_ch = s;
+
+ % HF channel simulation ------------------------------------
+
+ if hf_sim
+
+ % separation between carriers. Note this is
+ % effectively under samples at Rs, I dont think this
+ % matters. Equivalent to doing freq shift at Fs, then
+ % decimating to Rs.
+
+ wsep = 2*pi*(1+0.5); % e.g. 75Hz spacing at Rs=50Hz, alpha=0.5 filters
+
+ if Nsymb/Nc != floor(Nsymb/Nc)
+ printf("Error: Nsymb/Nc must be an integrer\n")
+ return;
+ end
+
+ % arrange symbols in Nsymb/Nc by Nc matrix
+
+ for i=1:Nc:Nsymb
+
+ % Determine HF channel at each carrier for this symbol
+
+ for k=1:Nc
+ hf_model(hf_n, k) = hf_gain*(spread(hf_n) + exp(-j*k*wsep*nhfdelay)*spread_2ms(hf_n));
+ hf_fading(i+k-1) = abs(hf_model(hf_n, k));
+ if hf_mag_only
+ s_ch(i+k-1) *= abs(hf_model(hf_n, k));
+ else
+ s_ch(i+k-1) *= hf_model(hf_n, k);
+ end
+ end
+ hf_n++;
+ end
+ end
+
+ tx_symb_log = [tx_symb_log s_ch];
+
+ % AWGN noise and phase/freq offset channel simulation
+ % 0.5 factor ensures var(noise) == variance , i.e. splits power between Re & Im
+
+ noise = sqrt(variance*0.5)*(randn(1,Nsymb) + j*randn(1,Nsymb));
+ noise_log = [noise_log noise];
+ phase_noise = phase_noise_amp*(2.0*rand(1,Nsymb)-1.0);
+
+ % organise into carriers to apply frequency and phase offset
+
+ for i=1:Nc:Nsymb
+ for k=1:Nc
+ s_ch(i+k-1) = s_ch(i+k-1)*exp(j*(phase_offset+phase_noise(i+k-1))) + noise(i+k-1);
+ end
+ phase_offset += w_offset;
+ end
+
+ % phase estimation
+
+ ph_est = zeros(Nc,1);
+
+ if phase_est
+
+ % organise into carriers
+
+ for i=1:Nc:Nsymb
+
+ for k=1:Nc
+ centre = floor(Nps/2)+1;
+
+ % delay line for phase est window
+
+ r_delay_line(k,1:Nps-1) = r_delay_line(k,2:Nps);
+ r_delay_line(k,Nps) = s_ch(i+k-1);
+
+ % delay in tx data to compensate data for phase est window
+
+ s_delay_line(k,1:Nps-1) = s_delay_line(k,2:Nps);
+ s_delay_line(k,Nps) = s(i+k-1);
+
+ if phase_est_method == 1
+ % QPSK modulation strip and phase est
+
+ mod_strip_pol = angle(r_delay_line(k,:)) * 4;
+ mod_strip_rect = exp(j*mod_strip_pol);
+
+ ph_est_pol = atan2(sum(imag(mod_strip_rect)),sum(real(mod_strip_rect)))/4;
+ ph_est(k) = exp(j*ph_est_pol);
+
+ s_ch(i+k-1) = r_delay_line(k,centre).*exp(-j*ph_est_pol);
+ % s_ch(i+k-1) = r_delay_line(k,centre);
+ end
+
+ if phase_est_method == 3
+ % QPSK modulation strip and phase est with original symbol mags
+
+ mod_strip_pol = angle(r_delay_line(k,:)) * 4;
+ mod_strip_rect = abs(r_delay_line(k,:)) .* exp(j*mod_strip_pol);
+
+ ph_est_pol = atan2(sum(imag(mod_strip_rect)),sum(real(mod_strip_rect)))/4;
+ ph_est(k) = exp(j*ph_est_pol);
+
+ s_ch(i+k-1) = r_delay_line(k,centre).*exp(-j*ph_est_pol);
+ % s_ch(i+k-1) = r_delay_line(k,centre);
+ end
+
+ if phase_est_method == 2
+
+ % estimate phase from surrounding known pilot symbols and correct
+
+ corr = 0;
+ for m=1:Ns:Nps
+ if (m != centre)
+ corr += s_delay_line(k,m) * r_delay_line(k,m)';
+ end
+ end
+ ph_est(k) = conj(corr/(1E-6+abs(corr)));
+ s_ch(i+k-1) = r_delay_line(k,centre).*exp(j*angle(corr));
+ %s_ch(i+k-1) = r_delay_line(k,centre);
+ end
+
+ end
+
+ ph_est_log = [ph_est_log ph_est];
+ end
+ %printf("corr: %f angle: %f\n", corr, angle(corr));
+ end
+
+ % de-modulate
+
+ rx_bits = zeros(1, framesize);
+ for i=1:Nc:Nsymb
+ for k=1:Nc
+ rx_symb = s_ch(i+k-1);
+ if strcmp(modulation,'dqpsk')
+ tmp = rx_symb;
+ rx_symb *= conj(prev_sym_rx(k)/abs(prev_sym_rx(k)));
+ if sim_coh_dpsk
+ prev_sym_rx(k) = qpsk_mod(qpsk_demod(tmp));
+ else
+ prev_sym_rx(k) = tmp;
+ end
+ s_ch(i+k-1) = rx_symb;
+ end
+ rx_bits((2*(i-1+k-1)+1):(2*(i+k-1))) = qpsk_demod(rx_symb);
+ rx_symb_log = [rx_symb_log rx_symb];
+ end
+ end
+
+if newldpc
+ rx_bits_buf(1:framesize) = rx_bits_buf(framesize+1:2*framesize);
+ rx_bits_buf(framesize+1:2*framesize) = rx_bits;
+ rx_symb_buf(1:Nsymb) = rx_symb_buf(Nsymb+1:2*Nsymb);
+ rx_symb_buf(Nsymb+1:2*Nsymb) = s_ch;
+ hf_fading_buf(1:Nsymb) = hf_fading_buf(Nsymb+1:2*Nsymb);
+ hf_fading_buf(Nsymb+1:2*Nsymb) = hf_fading;
+
+ % determine location of start and end of frame depending on processing delays
+
+ if phase_est
+ st_rx_bits = 1+(floor(Nps/2)+1-1)*Nc*2;
+ st_rx_symb = 1+(floor(Nps/2)+1-1)*Nc;
+ else
+ st_rx_bits = 1;
+ st_rx_symb = 1;
+ end
+ en_rx_bits = st_rx_bits+framesize-1;
+ en_rx_symb = st_rx_symb+Nsymb-1;
+
+ if nn > 1
+ % Measure BER
+
+ %printf("nn: %d centre: %d\n", nn, floor(Nps/2)+1);
+ %tx_bits_buf(1:20)
+ %rx_bits_buf(st_rx_bits:st_rx_bits+20-1)
+ error_positions = xor(rx_bits_buf(st_rx_bits:en_rx_bits), tx_bits_buf(1:framesize));
+ Nerrs = sum(error_positions);
+ sim_out.errors_log = [sim_out.errors_log error_positions];
+ Terrs += Nerrs;
+ Tbits += length(tx_bits);
+
+ % Optionally LDPC decode
+
+ if ldpc_code
+ detected_data = ldpc_dec(code_param, max_iterations, demod_type, decoder_type, ...
+ rx_symb_buf(st_rx_symb:en_rx_symb), min(100,EsNo), hf_fading_buf(1:Nsymb));
+ error_positions = xor( detected_data(1:framesize*rate), tx_bits_buf(1:framesize*rate) );
+ %detected_data = ldpc_dec(code_param, max_iterations, demod_type, decoder_type, s_ch, min(100,EsNo), hf_fading);
+ %error_positions = xor( detected_data(1:framesize*rate), tx_bits(1:framesize*rate) );
+ Nerrs = sum(error_positions);
+ sim_out.ldpc_errors_log = [sim_out.ldpc_errors_log error_positions];
+ if Nerrs
+ Ferrsldpc++;
+ end
+ Terrsldpc += Nerrs;
+ Tbitsldpc += framesize*rate;
+ end
+ end
+
+else
+ error_positions = xor(rx_bits, tx_bits);
+ Nerrs = sum(error_positions);
+ Terrs += Nerrs;
+ Tbits += length(tx_bits);
+
+ % Optionally LDPC decode
+
+ if ldpc_code
+ detected_data = ldpc_dec(code_param, max_iterations, demod_type, decoder_type, s_ch, min(100,EsNo), hf_fading);
+ error_positions = xor( detected_data(1:framesize*rate), tx_bits(1:framesize*rate) );
+ Nerrs = sum(error_positions);
+ if Nerrs
+ Ferrsldpc++;
+ end
+ Terrsldpc += Nerrs;
+ Tbitsldpc += framesize*rate;
+
+ end
+ end
+end
+
+ TERvec(ne) = Terrs;
+ BERvec(ne) = Terrs/Tbits;
+ if ldpc_code
+ TERldpcvec(ne) = Terrsldpc;
+ FERldpcvec(ne) = Ferrsldpc;
+ BERldpcvec(ne) = Terrsldpc/Tbitsldpc;
+ end
+
+ if verbose
+ printf("EsNo (dB): %f Terrs: %d BER %f BER theory %f", EsNodB, Terrs,
+ Terrs/Tbits, 0.5*erfc(sqrt(EsNo/2)));
+ if ldpc_code
+ printf(" LDPC: Terrs: %d BER: %f Ferrs: %d FER: %f",
+ Terrsldpc, Terrsldpc/Tbitsldpc, Ferrsldpc, Ferrsldpc/(Ntrials-1));
+ end
+ printf("\n");
+ end
+ if verbose > 1
+ printf("Terrs: %d BER %f BER theory %f C %f N %f Es %f No %f Es/No %f\n\n", Terrs,
+ Terrs/Tbits, 0.5*erfc(sqrt(EsNo/2)), var(tx_symb_log), var(noise_log),
+ var(tx_symb_log), var(noise_log), var(tx_symb_log)/var(noise_log));
+ end
+ end
+
+ Ebvec = Esvec - 10*log10(bps);
+
+ % account for extra power rqd for pilot symbols
+
+ if (phase_est_method == 2) && (phase_est)
+ Ebvec += 10*log10(Ns/(Ns-1));
+ end
+
+ sim_out.BERvec = BERvec;
+ sim_out.Ebvec = Ebvec;
+ sim_out.TERvec = TERvec;
+ if ldpc_code
+ sim_out.BERldpcvec = BERldpcvec;
+ sim_out.TERldpcvec = TERldpcvec;
+ sim_out.FERldpcvec = FERldpcvec;
+ end
+
+ if plot_scatter
+ figure(2);
+ clf;
+ scat = rx_symb_log .* exp(j*pi/4);
+ plot(real(scat(Nps*Nc:length(scat))), imag(scat(Nps*Nc:length(scat))),'+');
+ title('Scatter plot');
+
+ figure(3);
+ clf;
+
+ y = 1:Rs*2;
+ x = 1:Nc;
+ EsNodBSurface = 20*log10(abs(hf_model(y,:))) - 10*log10(variance);
+ mesh(x,y,EsNodBSurface);
+ grid
+ %axis([1 Nc 1 Rs*2 -10 10])
+ title('HF Channel Es/No');
+
+ figure(4);
+ clf;
+ %mesh(x,y,unwrap(angle(hf_model(y,:))));
+ subplot(211)
+ plot(y,abs(hf_model(y,1)))
+ title('HF Channel Carrier 1 Mag');
+ subplot(212)
+ plot(y,angle(hf_model(y,1)))
+ title('HF Channel Carrier 1 Phase');
+
+ if phase_est
+ scat = ph_est_log(1,floor(Nps/2):Rs*2+floor(Nps/2)-1);
+ hold on;
+ plot(angle(scat),'r');
+ hold off;
+
+ figure(5)
+ clf;
+ scat = ph_est_log(1,y);
+ plot(real(scat), imag(scat),'+');
+ title('Carrier 1 Phase Est');
+ axis([-1 1 -1 1])
+ end
+if 0
+ figure(5);
+ clf;
+ subplot(211)
+ plot(real(spread));
+ hold on;
+ plot(imag(spread),'g');
+ hold off;
+ subplot(212)
+ plot(real(spread_2ms));
+ hold on;
+ plot(imag(spread_2ms),'g');
+ hold off;
+
+ figure(6)
+ tmp = [];
+ for i = 1:hf_n-1
+ tmp = [tmp abs(hf_model(i,:))];
+ end
+ hist(tmp);
+end
+ end
+
+size(sim_out.errors_log)
+
+endfunction
+
+% Gray coded QPSK modulation function
+
+function symbol = qpsk_mod(two_bits)
+ two_bits_decimal = sum(two_bits .* [2 1]);
+ switch(two_bits_decimal)
+ case (0) symbol = 1;
+ case (1) symbol = j;
+ case (2) symbol = -j;
+ case (3) symbol = -1;
+ endswitch
+endfunction
+
+% Gray coded QPSK demodulation function
+
+function two_bits = qpsk_demod(symbol)
+ if isscalar(symbol) == 0
+ printf("only works with scalars\n");
+ return;
+ end
+ bit0 = real(symbol*exp(j*pi/4)) < 0;
+ bit1 = imag(symbol*exp(j*pi/4)) < 0;
+ two_bits = [bit1 bit0];
+endfunction
+
+function sim_in = standard_init
+ sim_in.verbose = 1;
+ sim_in.plot_scatter = 0;
+
+ sim_in.Esvec = 5;
+ sim_in.Ntrials = 30;
+ sim_in.framesize = 576;
+ sim_in.Rs = 100;
+ sim_in.Nc = 8;
+
+ sim_in.phase_offset = 0;
+ sim_in.w_offset = 0;
+ sim_in.phase_noise_amp = 0;
+
+ sim_in.hf_delay_ms = 2;
+ sim_in.hf_sim = 0;
+ sim_in.hf_phase_only = 0;
+ sim_in.hf_mag_only = 1;
+
+ sim_in.phase_est = 0;
+ sim_in.phase_est_method = 1;
+ sim_in.Np = 5;
+ sim_in.Ns = 5;
+
+ sim_in.ldpc_code_rate = 1/2;
+ sim_in.ldpc_code = 1;
+endfunction
+
+function ideal
+
+ sim_in = standard_init();
+
+ sim_in.sim_coh_dpsk = 0;
+ sim_in.newldpc = 1;
+ sim_in.verbose = 2;
+ sim_in.plot_scatter = 1;
+
+ sim_in.Esvec = 5;
+ sim_in.hf_sim = 1;
+ sim_in.Ntrials = 30;
+
+ sim_qpsk_hf = ber_test(sim_in, 'qpsk');
+
+ sim_in.hf_sim = 0;
+ sim_in.plot_scatter = 0;
+ sim_in.Esvec = 2:15;
+ sim_in.ldpc_code = 0;
+ Ebvec = sim_in.Esvec - 10*log10(2);
+ BER_theory = 0.5*erfc(sqrt(10.^(Ebvec/10)));
+ sim_qpsk = ber_test(sim_in, 'qpsk');
+ sim_dqpsk = ber_test(sim_in, 'dqpsk');
+
+ sim_in.hf_sim = 1;
+ sim_in.Esvec = 2:15;
+ sim_qpsk_hf = ber_test(sim_in, 'qpsk');
+ sim_dqpsk_hf = ber_test(sim_in, 'dqpsk');
+ sim_in.ldpc_code = 1;
+ sim_in.ldpc_code_rate = 3/4;
+ sim_qpsk_hf_ldpc1 = ber_test(sim_in, 'qpsk');
+ sim_in.ldpc_code_rate = 1/2;
+ sim_qpsk_hf_ldpc2 = ber_test(sim_in, 'qpsk');
+ sim_in.ldpc_code_rate = 3/4;
+ sim_in.hf_sim = 0;
+ sim_qpsk_awgn_ldpc = ber_test(sim_in, 'qpsk');
+
+ figure(1);
+ clf;
+ semilogy(Ebvec, BER_theory,'r;QPSK theory;')
+ hold on;
+ semilogy(sim_qpsk.Ebvec, sim_qpsk.BERvec,'g;QPSK AWGN;')
+ semilogy(sim_qpsk_hf.Ebvec, sim_qpsk_hf.BERvec,'r;QPSK HF;')
+ semilogy(sim_dqpsk.Ebvec, sim_dqpsk.BERvec,'c;DQPSK AWGN;')
+ semilogy(sim_dqpsk_hf.Ebvec, sim_dqpsk_hf.BERvec,'m;DQPSK HF;')
+ semilogy(sim_qpsk_hf_ldpc1.Ebvec, sim_qpsk_hf_ldpc1.BERldpcvec,'k;QPSK HF LDPC 3/4;')
+ semilogy(sim_qpsk_hf_ldpc2.Ebvec, sim_qpsk_hf_ldpc2.BERldpcvec,'b;QPSK HF LDPC 1/2;')
+ semilogy(sim_qpsk_awgn_ldpc.Ebvec, sim_qpsk_awgn_ldpc.BERldpcvec,'k;QPSK AWGN LDPC 3/4;')
+
+ hold off;
+ xlabel('Eb/N0')
+ ylabel('BER')
+ grid("minor")
+ axis([min(Ebvec) max(Ebvec) 1E-3 1])
+endfunction
+
+function phase_noise
+ sim_in = standard_init();
+
+ sim_in.verbose = 1;
+ sim_in.plot_scatter = 1;
+
+ sim_in.Esvec = 100;
+ sim_in.Ntrials = 100;
+
+ sim_in.ldpc_code_rate = 1/2;
+ sim_in.ldpc_code = 1;
+
+ sim_in.phase_noise_amp = pi/16;
+ tmp = ber_test(sim_in, 'qpsk');
+
+ sim_in.plot_scatter = 0;
+ sim_in.Esvec = 2:8;
+ sim_qpsk_hf = ber_test(sim_in, 'qpsk');
+
+ Ebvec = sim_in.Esvec - 10*log10(2);
+ BER_theory = 0.5*erfc(sqrt(10.^(Ebvec/10)));
+
+ sim_in.phase_noise_amp = 0;
+ sim_qpsk = ber_test(sim_in, 'qpsk');
+ sim_in.phase_noise_amp = pi/8;
+ sim_qpsk_pn8 = ber_test(sim_in, 'qpsk');
+ sim_in.phase_noise_amp = pi/16;
+ sim_qpsk_pn16 = ber_test(sim_in, 'qpsk');
+ sim_in.phase_noise_amp = pi/32;
+ sim_qpsk_pn32 = ber_test(sim_in, 'qpsk');
+
+ figure(1);
+ clf;
+ semilogy(sim_qpsk.Ebvec, sim_qpsk.BERvec,'g;QPSK phase noise 0;')
+ hold on;
+ semilogy(sim_qpsk_pn8.Ebvec, sim_qpsk_pn8.BERvec,'c;QPSK phase noise +/- pi/8;')
+ semilogy(sim_qpsk_pn16.Ebvec, sim_qpsk_pn16.BERvec,'b;QPSK phase noise +/- pi/16;')
+ semilogy(sim_qpsk_pn32.Ebvec, sim_qpsk_pn32.BERvec,'k;QPSK phase noise +/- pi/32;')
+
+ semilogy(sim_qpsk.Ebvec, sim_qpsk.BERldpcvec,'g;QPSK phase noise 0 ldpc;')
+ semilogy(sim_qpsk_pn8.Ebvec, sim_qpsk_pn8.BERldpcvec,'c;QPSK phase noise +/- pi/8 ldpc;')
+ semilogy(sim_qpsk_pn16.Ebvec, sim_qpsk_pn16.BERldpcvec,'b;QPSK phase noise +/- pi/16 ldpc;')
+ semilogy(sim_qpsk_pn32.Ebvec, sim_qpsk_pn32.BERldpcvec,'k;QPSK phase noise +/- pi/32 ldpc;')
+
+ hold off;
+ xlabel('Eb/N0')
+ ylabel('BER')
+ grid("minor")
+ axis([min(Ebvec) max(Ebvec) 1E-2 1])
+endfunction
+
+function phase_est_hf
+ sim_in = standard_init();
+
+ sim_in.Rs = 100;
+ sim_in.Nc = 8;
+
+ sim_in.verbose = 1;
+ sim_in.plot_scatter = 0;
+
+ sim_in.Esvec = 5:15;
+ sim_in.Ntrials = 100;
+
+ sim_in.newldpc = 1;
+ sim_in.ldpc_code_rate = 1/2;
+ sim_in.ldpc_code = 1;
+
+ sim_in.phase_est = 0;
+ sim_in.sim_coh_dpsk = 0;
+ sim_in.phase_est_method = 2;
+ sim_in.Np = 3;
+ sim_in.phase_offset = 0;
+ sim_in.w_offset = 0;
+
+ sim_in.hf_sim = 1;
+ sim_in.hf_mag_only = 1;
+
+ Ebvec = sim_in.Esvec - 10*log10(2);
+
+ baseline = ber_test(sim_in, 'qpsk');
+
+ sim_in.hf_mag_only = 0;
+ sim_in.phase_est_method = 2;
+ sim_in.phase_est = 1;
+ sim_in.Np = 3;
+ pilot_3 = ber_test(sim_in, 'qpsk');
+ sim_in.Np = 5;
+ pilot_5 = ber_test(sim_in, 'qpsk');
+ sim_in.Np = 7;
+ pilot_7 = ber_test(sim_in, 'qpsk');
+
+if 1
+ sim_in.phase_est = 0;
+ dqpsk = ber_test(sim_in, 'dqpsk');
+
+ figure(1);
+ clf;
+ semilogy(baseline.Ebvec, baseline.BERvec,'r;QPSK CCIR poor;')
+ hold on;
+ semilogy(baseline.Ebvec, baseline.BERldpcvec,'r;QPSK CCIR poor ldpc;')
+ semilogy(pilot_3.Ebvec, pilot_3.BERvec,'b;QPSK CCIR poor ldpc pilot 3;')
+ semilogy(pilot_3.Ebvec, pilot_3.BERldpcvec,'b;QPSK CCIR poor ldpc pilot 3;')
+ semilogy(pilot_5.Ebvec, pilot_5.BERvec,'g;QPSK CCIR poor ldpc pilot 5;')
+ semilogy(pilot_5.Ebvec, pilot_5.BERldpcvec,'g;QPSK CCIR poor ldpc pilot 5;')
+ semilogy(pilot_7.Ebvec, pilot_7.BERvec,'m;QPSK CCIR poor ldpc pilot 7;')
+ semilogy(pilot_7.Ebvec, pilot_7.BERldpcvec,'m;QPSK CCIR poor ldpc pilot 7;')
+ semilogy(dqpsk.Ebvec, dqpsk.BERvec,'k;DQPSK CCIR poor ldpc;')
+ semilogy(dqpsk.Ebvec, dqpsk.BERldpcvec,'k;DQPSK CCIR poor ldpc;')
+
+ hold off;
+ xlabel('Eb/N0')
+ ylabel('BER')
+ grid("minor")
+ axis([min(Ebvec) max(Ebvec) 1E-2 1])
+end
+endfunction
+
+function phase_est_awgn
+ sim_in = standard_init();
+
+ sim_in.Rs = 100;
+ sim_in.Nc = 8;
+
+ sim_in.verbose = 1;
+ sim_in.plot_scatter = 0;
+
+ sim_in.Esvec = 0:0.5:3;
+ sim_in.Ntrials = 30;
+
+ sim_in.newldpc = 1;
+ sim_in.ldpc_code_rate = 1/2;
+ sim_in.ldpc_code = 1;
+
+ sim_in.phase_est = 0;
+ sim_in.phase_est_method = 1;
+ sim_in.Np = 3;
+ sim_in.phase_offset = 0;
+ sim_in.w_offset = 0;
+
+ sim_in.hf_sim = 0;
+ sim_in.hf_mag_only = 1;
+
+ ideal = ber_test(sim_in, 'qpsk');
+
+ sim_in.phase_est = 1;
+ sim_in.Np = 21;
+ sim_in.phase_est_method = 3;
+ strip_21_mag = ber_test(sim_in, 'qpsk');
+
+ sim_in.Np = 41;
+ strip_41_mag = ber_test(sim_in, 'qpsk');
+
+ sim_in.phase_est_method = 1;
+ sim_in.Np = 21;
+ strip_21 = ber_test(sim_in, 'qpsk');
+
+ sim_in.Np = 41;
+ strip_41 = ber_test(sim_in, 'qpsk');
+
+ sim_in.Np = 7;
+ sim_in.phase_est_method = 2;
+ pilot_7 = ber_test(sim_in, 'qpsk');
+
+ Ebvec = sim_in.Esvec - 10*log10(2);
+
+ figure(1);
+ clf;
+ semilogy(ideal.Ebvec, ideal.BERvec,'r;QPSK;')
+ hold on;
+ semilogy(ideal.Ebvec, ideal.BERldpcvec,'r;QPSK LDPC;')
+ semilogy(strip_21.Ebvec, strip_21.BERvec,'g;QPSK strip 21;')
+ semilogy(strip_21.Ebvec, strip_21.BERldpcvec,'g;QPSK LDPC strip 21;')
+ semilogy(strip_41.Ebvec, strip_41.BERvec,'b;QPSK strip 41;')
+ semilogy(strip_41.Ebvec, strip_41.BERldpcvec,'b;QPSK LDPC strip 41;')
+ semilogy(strip_21_mag.Ebvec, strip_21_mag.BERvec,'m;QPSK strip 21 mag;')
+ semilogy(strip_21_mag.Ebvec, strip_21_mag.BERldpcvec,'m;QPSK LDPC strip 21 mag;')
+ semilogy(strip_41_mag.Ebvec, strip_41_mag.BERvec,'c;QPSK strip 41 mag;')
+ semilogy(strip_41_mag.Ebvec, strip_41_mag.BERldpcvec,'c;QPSK LDPC strip 41 mag;')
+ semilogy(pilot_7.Ebvec, pilot_7.BERvec,'k;QPSK pilot 7;')
+ semilogy(pilot_7.Ebvec, pilot_7.BERldpcvec,'k;QPSK LDPC pilot 7;')
+
+ hold off;
+ xlabel('Eb/N0')
+ ylabel('BER')
+ grid("minor")
+ axis([min(Ebvec) max(Ebvec) 1E-2 1])
+endfunction
+
+function test_dpsk
+ sim_in = standard_init();
+
+ sim_in.Rs = 100;
+ sim_in.Nc = 8;
+
+ sim_in.verbose = 1;
+ sim_in.plot_scatter = 0;
+
+ sim_in.Esvec = 5;
+ sim_in.Ntrials = 30;
+
+ sim_in.newldpc = 1;
+ sim_in.ldpc_code_rate = 1/2;
+ sim_in.ldpc_code = 1;
+
+ sim_in.phase_est = 0;
+ sim_in.phase_est_method = 3;
+ sim_in.Np = 41;
+ sim_in.phase_offset = 0;
+ sim_in.w_offset = 0;
+ sim_in.sim_coh_dpsk = 0;
+
+ sim_in.hf_sim = 0;
+ sim_in.hf_mag_only = 1;
+
+ Ebvec = sim_in.Esvec - 10*log10(2);
+
+ baseline = ber_test(sim_in, 'qpsk');
+ sim_in.phase_est = 0;
+ dqpsk = ber_test(sim_in, 'dqpsk');
+
+ sim_in.phase_est = 1;
+ sim_in.phase_est_method = 3;
+ sim_in.sim_coh_dpsk = 1;
+ sim_in.Np = 41;
+ dqpsk_strip_41 = ber_test(sim_in, 'dqpsk');
+
+ figure(1);
+ clf;
+ semilogy(baseline.Ebvec, baseline.BERvec,'r;QPSK CCIR poor;')
+ hold on;
+ semilogy(baseline.Ebvec, baseline.BERldpcvec,'r;QPSK CCIR poor ldpc;')
+ semilogy(dqpsk.Ebvec, dqpsk.BERvec,'c;DQPSK CCIR poor ldpc;')
+ semilogy(dqpsk.Ebvec, dqpsk.BERldpcvec,'c;DQPSK CCIR poor ldpc;')
+ semilogy(dqpsk_strip_41.Ebvec, dqpsk_strip_41.BERvec,'m;DQPSK CCIR poor ldpc strip 41;')
+ semilogy(dqpsk_strip_41.Ebvec, dqpsk_strip_41.BERldpcvec,'m;DQPSK CCIR poor ldpc strip 41;')
+
+ hold off;
+ xlabel('Eb/N0')
+ ylabel('BER')
+ grid("minor")
+ axis([min(Ebvec) max(Ebvec) 1E-2 1])
+
+endfunction
+
+function gen_error_pattern_qpsk()
+ sim_in = standard_init();
+
+ % model codec and uncoded streams as 1000 bit/s each
+
+ sim_in.Rs = 100;
+ sim_in.Nc = 4;
+
+ sim_in.verbose = 1;
+ sim_in.plot_scatter = 0;
+
+ sim_in.Esvec = 10; % Eb/No=2dB
+ sim_in.Ntrials = 30;
+
+ sim_in.newldpc = 1;
+ sim_in.ldpc_code_rate = 1/2;
+ sim_in.ldpc_code = 1;
+
+ sim_in.phase_est = 1;
+ sim_in.phase_est_method = 2;
+ sim_in.Np = 5;
+ sim_in.phase_offset = 0;
+ sim_in.w_offset = 0;
+ sim_in.sim_coh_dpsk = 0;
+
+ sim_in.hf_sim = 1;
+ sim_in.hf_mag_only = 0;
+
+ qpsk = ber_test(sim_in, 'qpsk');
+
+ length(qpsk.errors_log)
+ length(qpsk.ldpc_errors_log)
+ % multiplex errors into prot and unprot halves of 52 bit codec frames
+
+ error_pattern = [];
+ for i=1:26:length(qpsk.ldpc_errors_log)-52
+ error_pattern = [error_pattern qpsk.ldpc_errors_log(i:i+25) qpsk.errors_log(i:i+25) zeros(1,4)];
+ %error_pattern = [error_pattern qpsk.ldpc_errors_log(i:i+25) zeros(1,26) zeros(1,4)];
+ %error_pattern = [error_pattern zeros(1,26) qpsk.errors_log(i:i+25) zeros(1,4)];
+ end
+
+ fep=fopen("qpsk_errors_2dB.bin","wb"); fwrite(fep, error_pattern, "short"); fclose(fep);
+
+endfunction
+
+function gen_error_pattern_dpsk()
+ sim_in = standard_init();
+
+ sim_in.Rs = 50;
+ sim_in.Nc = 16;
+
+ sim_in.verbose = 1;
+ sim_in.plot_scatter = 1;
+
+ sim_in.Esvec = 10; % Eb/No=Es/No-3
+ sim_in.Ntrials = 30;
+
+ sim_in.newldpc = 1;
+ sim_in.ldpc_code_rate = 1/2;
+ sim_in.ldpc_code = 0;
+
+ sim_in.phase_est = 0;
+ sim_in.phase_est_method = 3;
+ sim_in.Np = 41;
+ sim_in.phase_offset = 0;
+ sim_in.w_offset = 0;
+ sim_in.sim_coh_dpsk = 0;
+
+ sim_in.hf_sim = 1;
+ sim_in.hf_mag_only = 1;
+
+ dqpsk = ber_test(sim_in, 'dqpsk');
+
+ fep=fopen("dqpsk_errors_12dB.bin","wb"); fwrite(fep, dqpsk.errors_log, "short"); fclose(fep);
+
+endfunction
+
+% Start simulations ---------------------------------------
+
+more off;
+
+ideal();
+%phase_est_hf();
+%phase_est_awgn();
+%test_dpsk();
+%gen_error_pattern_qpsk
-/**\r
- ******************************************************************************\r
- * @file stm32f4xx_conf.h \r
- * @author MCD Application Team\r
- * @version V1.0.0\r
- * @date 19-September-2011\r
- * @brief Library configuration file.\r
- ******************************************************************************\r
- * @attention\r
- *\r
- * THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS\r
- * WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE\r
- * TIME. AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY\r
- * DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING\r
- * FROM THE CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE\r
- * CODING INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.\r
- *\r
- * <h2><center>© COPYRIGHT 2011 STMicroelectronics</center></h2>\r
- ******************************************************************************\r
- */ \r
-\r
-/* Define to prevent recursive inclusion -------------------------------------*/\r
-#ifndef __STM32F4xx_CONF_H\r
-#define __STM32F4xx_CONF_H\r
-\r
-#if defined (HSE_VALUE)\r
-/* Redefine the HSE value; it's equal to 8 MHz on the STM32F4-DISCOVERY Kit */\r
- #undef HSE_VALUE\r
- #define HSE_VALUE ((uint32_t)8000000) \r
-#endif /* HSE_VALUE */\r
-\r
-/* Includes ------------------------------------------------------------------*/\r
-/* Uncomment the line below to enable peripheral header file inclusion */\r
-#include "stm32f4xx_adc.h"\r
-#include "stm32f4xx_can.h"\r
-#include "stm32f4xx_crc.h"\r
-#include "stm32f4xx_cryp.h"\r
-#include "stm32f4xx_dac.h"\r
-#include "stm32f4xx_dbgmcu.h"\r
-#include "stm32f4xx_dcmi.h"\r
-#include "stm32f4xx_dma.h"\r
-#include "stm32f4xx_exti.h"\r
-#include "stm32f4xx_flash.h"\r
-#include "stm32f4xx_fsmc.h"\r
-#include "stm32f4xx_hash.h"\r
-#include "stm32f4xx_gpio.h"\r
-#include "stm32f4xx_i2c.h"\r
-#include "stm32f4xx_iwdg.h"\r
-#include "stm32f4xx_pwr.h"\r
-#include "stm32f4xx_rcc.h"\r
-#include "stm32f4xx_rng.h"\r
-#include "stm32f4xx_rtc.h"\r
-#include "stm32f4xx_sdio.h"\r
-#include "stm32f4xx_spi.h"\r
-#include "stm32f4xx_syscfg.h"\r
-#include "stm32f4xx_tim.h"\r
-#include "stm32f4xx_usart.h"\r
-#include "stm32f4xx_wwdg.h"\r
-#include "misc.h" /* High level functions for NVIC and SysTick (add-on to CMSIS functions) */\r
-\r
-/* Exported types ------------------------------------------------------------*/\r
-/* Exported constants --------------------------------------------------------*/\r
-\r
-/* If an external clock source is used, then the value of the following define \r
- should be set to the value of the external clock source, else, if no external \r
- clock is used, keep this define commented */\r
-/*#define I2S_EXTERNAL_CLOCK_VAL 12288000 */ /* Value of the external clock in Hz */\r
-\r
-\r
-/* Uncomment the line below to expanse the "assert_param" macro in the \r
- Standard Peripheral Library drivers code */\r
-/* #define USE_FULL_ASSERT 1 */\r
-\r
-/* Exported macro ------------------------------------------------------------*/\r
-#ifdef USE_FULL_ASSERT\r
-\r
-/**\r
- * @brief The assert_param macro is used for function's parameters check.\r
- * @param expr: If expr is false, it calls assert_failed function\r
- * which reports the name of the source file and the source\r
- * line number of the call that failed. \r
- * If expr is true, it returns no value.\r
- * @retval None\r
- */\r
- #define assert_param(expr) ((expr) ? (void)0 : assert_failed((uint8_t *)__FILE__, __LINE__))\r
-/* Exported functions ------------------------------------------------------- */\r
- void assert_failed(uint8_t* file, uint32_t line);\r
-#else\r
- #define assert_param(expr) ((void)0)\r
-#endif /* USE_FULL_ASSERT */\r
-\r
-#endif /* __STM32F4xx_CONF_H */\r
-\r
-/******************* (C) COPYRIGHT 2011 STMicroelectronics *****END OF FILE****/\r
+/**
+ ******************************************************************************
+ * @file stm32f4xx_conf.h
+ * @author MCD Application Team
+ * @version V1.0.0
+ * @date 19-September-2011
+ * @brief Library configuration file.
+ ******************************************************************************
+ * @attention
+ *
+ * THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS
+ * WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE
+ * TIME. AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY
+ * DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING
+ * FROM THE CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE
+ * CODING INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.
+ *
+ * <h2><center>© COPYRIGHT 2011 STMicroelectronics</center></h2>
+ ******************************************************************************
+ */
+
+/* Define to prevent recursive inclusion -------------------------------------*/
+#ifndef __STM32F4xx_CONF_H
+#define __STM32F4xx_CONF_H
+
+#if defined (HSE_VALUE)
+/* Redefine the HSE value; it's equal to 8 MHz on the STM32F4-DISCOVERY Kit */
+ #undef HSE_VALUE
+ #define HSE_VALUE ((uint32_t)8000000)
+#endif /* HSE_VALUE */
+
+/* Includes ------------------------------------------------------------------*/
+/* Uncomment the line below to enable peripheral header file inclusion */
+#include "stm32f4xx_adc.h"
+#include "stm32f4xx_can.h"
+#include "stm32f4xx_crc.h"
+#include "stm32f4xx_cryp.h"
+#include "stm32f4xx_dac.h"
+#include "stm32f4xx_dbgmcu.h"
+#include "stm32f4xx_dcmi.h"
+#include "stm32f4xx_dma.h"
+#include "stm32f4xx_exti.h"
+#include "stm32f4xx_flash.h"
+#include "stm32f4xx_fsmc.h"
+#include "stm32f4xx_hash.h"
+#include "stm32f4xx_gpio.h"
+#include "stm32f4xx_i2c.h"
+#include "stm32f4xx_iwdg.h"
+#include "stm32f4xx_pwr.h"
+#include "stm32f4xx_rcc.h"
+#include "stm32f4xx_rng.h"
+#include "stm32f4xx_rtc.h"
+#include "stm32f4xx_sdio.h"
+#include "stm32f4xx_spi.h"
+#include "stm32f4xx_syscfg.h"
+#include "stm32f4xx_tim.h"
+#include "stm32f4xx_usart.h"
+#include "stm32f4xx_wwdg.h"
+#include "misc.h" /* High level functions for NVIC and SysTick (add-on to CMSIS functions) */
+
+/* Exported types ------------------------------------------------------------*/
+/* Exported constants --------------------------------------------------------*/
+
+/* If an external clock source is used, then the value of the following define
+ should be set to the value of the external clock source, else, if no external
+ clock is used, keep this define commented */
+/*#define I2S_EXTERNAL_CLOCK_VAL 12288000 */ /* Value of the external clock in Hz */
+
+
+/* Uncomment the line below to expanse the "assert_param" macro in the
+ Standard Peripheral Library drivers code */
+/* #define USE_FULL_ASSERT 1 */
+
+/* Exported macro ------------------------------------------------------------*/
+#ifdef USE_FULL_ASSERT
+
+/**
+ * @brief The assert_param macro is used for function's parameters check.
+ * @param expr: If expr is false, it calls assert_failed function
+ * which reports the name of the source file and the source
+ * line number of the call that failed.
+ * If expr is true, it returns no value.
+ * @retval None
+ */
+ #define assert_param(expr) ((expr) ? (void)0 : assert_failed((uint8_t *)__FILE__, __LINE__))
+/* Exported functions ------------------------------------------------------- */
+ void assert_failed(uint8_t* file, uint32_t line);
+#else
+ #define assert_param(expr) ((void)0)
+#endif /* USE_FULL_ASSERT */
+
+#endif /* __STM32F4xx_CONF_H */
+
+/******************* (C) COPYRIGHT 2011 STMicroelectronics *****END OF FILE****/
-/*---------------------------------------------------------------------------*\\r
-\r
- FILE........: adc_rec.c\r
- AUTHOR......: David Rowe\r
- DATE CREATED: 30 May 2014\r
-\r
- Records a 16 kHz sample rate raw file from one of the ADC channels,\r
- which are connected to pins PA1 (ADC1) and PA2 (ADC2).\r
-\r
- Note the semi-hosting system isn't fast enough to transfer 2 16 kHz\r
- streams at once.\r
- \r
- ~/stlink$ sudo ./st-util -f ~/codec2-dev/stm32/adc_rec.elf\r
- ~/codec2-dev/stm32$ ~/gcc-arm-none-eabi-4_7-2013q1/bin/arm-none-eabi-gdb adc_rec.elf\r
- \r
- (when finished) \r
- $ play -r 16000 -s -2 ~/stlink/adc.raw\r
-\r
- adc1 -> "from radio" \r
- adc2 -> "mic amp"\r
-\r
-\*---------------------------------------------------------------------------*/\r
-\r
-/*\r
- Copyright (C) 2014 David Rowe\r
-\r
- All rights reserved.\r
-\r
- This program is free software; you can redistribute it and/or modify\r
- it under the terms of the GNU Lesser General Public License version 2.1, as\r
- published by the Free Software Foundation. This program is\r
- distributed in the hope that it will be useful, but WITHOUT ANY\r
- WARRANTY; without even the implied warranty of MERCHANTABILITY or\r
- FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public\r
- License for more details.\r
-\r
- You should have received a copy of the GNU Lesser General Public License\r
- along with this program; if not, see <http://www.gnu.org/licenses/>.\r
-*/\r
-\r
-#include <stdlib.h>\r
-#include "stm32f4_adc.h"\r
-#include "gdb_stdio.h"\r
-#include "stm32f4xx_gpio.h"\r
-\r
-#define REC_TIME_SECS 10\r
-#define N (ADC_BUF_SZ*6)\r
-#define FS 16000\r
-\r
-extern int adc_overflow1;\r
-extern int adc_overflow2;\r
-\r
-int main(void){\r
- short buf[N];\r
- FILE *fadc;\r
- int i, bufs;\r
-\r
- fadc = fopen("adc.raw", "wb");\r
- if (fadc == NULL) {\r
- printf("Error opening input file: adc.raw\n\nTerminating....\n");\r
- exit(1);\r
- }\r
- bufs = FS*REC_TIME_SECS/N;\r
-\r
- printf("Starting!\n");\r
- adc_open(4*N);\r
-\r
- for(i=0; i<bufs; i++) {\r
- while(adc2_read(buf, N) == -1);\r
- fwrite(buf, sizeof(short), N, fadc); \r
- printf("adc_overflow1: %d adc_overflow2: %d \n", adc_overflow1, adc_overflow2);\r
- }\r
- fclose(fadc);\r
-\r
- printf("Finished!\n");\r
-}\r
+/*---------------------------------------------------------------------------*\
+
+ FILE........: adc_rec.c
+ AUTHOR......: David Rowe
+ DATE CREATED: 30 May 2014
+
+ Records a 16 kHz sample rate raw file from one of the ADC channels,
+ which are connected to pins PA1 (ADC1) and PA2 (ADC2).
+
+ Note the semi-hosting system isn't fast enough to transfer 2 16 kHz
+ streams at once.
+
+ ~/stlink$ sudo ./st-util -f ~/codec2-dev/stm32/adc_rec.elf
+ ~/codec2-dev/stm32$ ~/gcc-arm-none-eabi-4_7-2013q1/bin/arm-none-eabi-gdb adc_rec.elf
+
+ (when finished)
+ $ play -r 16000 -s -2 ~/stlink/adc.raw
+
+ adc1 -> "from radio"
+ adc2 -> "mic amp"
+
+\*---------------------------------------------------------------------------*/
+
+/*
+ Copyright (C) 2014 David Rowe
+
+ All rights reserved.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License version 2.1, as
+ published by the Free Software Foundation. This program is
+ distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+ License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with this program; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <stdlib.h>
+#include "stm32f4_adc.h"
+#include "gdb_stdio.h"
+#include "stm32f4xx_gpio.h"
+
+#define REC_TIME_SECS 10
+#define N (ADC_BUF_SZ*6)
+#define FS 16000
+
+extern int adc_overflow1;
+extern int adc_overflow2;
+
+int main(void){
+ short buf[N];
+ FILE *fadc;
+ int i, bufs;
+
+ fadc = fopen("adc.raw", "wb");
+ if (fadc == NULL) {
+ printf("Error opening input file: adc.raw\n\nTerminating....\n");
+ exit(1);
+ }
+ bufs = FS*REC_TIME_SECS/N;
+
+ printf("Starting!\n");
+ adc_open(4*N);
+
+ for(i=0; i<bufs; i++) {
+ while(adc2_read(buf, N) == -1);
+ fwrite(buf, sizeof(short), N, fadc);
+ printf("adc_overflow1: %d adc_overflow2: %d \n", adc_overflow1, adc_overflow2);
+ }
+ fclose(fadc);
+
+ printf("Finished!\n");
+}
-/*---------------------------------------------------------------------------*\\r
-\r
- FILE........: adc_sd.c\r
- AUTHOR......: David Rowe\r
- DATE CREATED: 30 May 2014\r
-\r
- Measures the std deviation of the ADC signals. Used to check noise\r
- levels on each ADC.\r
-\r
-\*---------------------------------------------------------------------------*/\r
-\r
-/*\r
- Copyright (C) 2014 David Rowe\r
-\r
- All rights reserved.\r
-\r
- This program is free software; you can redistribute it and/or modify\r
- it under the terms of the GNU Lesser General Public License version 2.1, as\r
- published by the Free Software Foundation. This program is\r
- distributed in the hope that it will be useful, but WITHOUT ANY\r
- WARRANTY; without even the implied warranty of MERCHANTABILITY or\r
- FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public\r
- License for more details.\r
-\r
- You should have received a copy of the GNU Lesser General Public License\r
- along with this program; if not, see <http://www.gnu.org/licenses/>.\r
-*/\r
-\r
-#include <stdlib.h>\r
-#include <math.h>\r
-#include "stm32f4_adc.h"\r
-#include "stm32f4_dac.h"\r
-#include "gdb_stdio.h"\r
-\r
-#define REC_TIME_SECS 10\r
-#define N (ADC_BUF_SZ*4)\r
-#define FS 16000\r
-\r
-static float calc_sd(short x[], int n) {\r
- float sum, mean, sum_diff, sd;\r
- int i;\r
-\r
- sum = 0.0;\r
- for(i=0; i<n;i++) {\r
- sum += (float)x[i];\r
- }\r
- mean = sum/n;\r
-\r
- sum_diff = 0.0;\r
- for(i=0; i<n;i++) {\r
- sum_diff += ((float)x[i] - mean)*((float)x[i] - mean);\r
- }\r
- \r
- sd = sqrtf(sum_diff/n);\r
-\r
- return sd;\r
-}\r
-\r
-int main(void){\r
- short buf[N];\r
- float sd1, sd2;\r
-\r
- adc_open(2*N);\r
-\r
- printf("Starting!\n");\r
- while(1) {\r
- while(adc1_read(buf, N) == -1);\r
- sd1 = calc_sd(buf, N);\r
- while(adc2_read(buf, N) == -1);\r
- sd2 = calc_sd(buf, N);\r
-\r
- printf("adc1: %5.1f adc2: %5.1f\n", (double)sd1, (double)sd2);\r
- }\r
-\r
-}\r
+/*---------------------------------------------------------------------------*\
+
+ FILE........: adc_sd.c
+ AUTHOR......: David Rowe
+ DATE CREATED: 30 May 2014
+
+ Measures the std deviation of the ADC signals. Used to check noise
+ levels on each ADC.
+
+\*---------------------------------------------------------------------------*/
+
+/*
+ Copyright (C) 2014 David Rowe
+
+ All rights reserved.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License version 2.1, as
+ published by the Free Software Foundation. This program is
+ distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+ License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with this program; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <stdlib.h>
+#include <math.h>
+#include "stm32f4_adc.h"
+#include "stm32f4_dac.h"
+#include "gdb_stdio.h"
+
+#define REC_TIME_SECS 10
+#define N (ADC_BUF_SZ*4)
+#define FS 16000
+
+static float calc_sd(short x[], int n) {
+ float sum, mean, sum_diff, sd;
+ int i;
+
+ sum = 0.0;
+ for(i=0; i<n;i++) {
+ sum += (float)x[i];
+ }
+ mean = sum/n;
+
+ sum_diff = 0.0;
+ for(i=0; i<n;i++) {
+ sum_diff += ((float)x[i] - mean)*((float)x[i] - mean);
+ }
+
+ sd = sqrtf(sum_diff/n);
+
+ return sd;
+}
+
+int main(void){
+ short buf[N];
+ float sd1, sd2;
+
+ adc_open(2*N);
+
+ printf("Starting!\n");
+ while(1) {
+ while(adc1_read(buf, N) == -1);
+ sd1 = calc_sd(buf, N);
+ while(adc2_read(buf, N) == -1);
+ sd2 = calc_sd(buf, N);
+
+ printf("adc1: %5.1f adc2: %5.1f\n", (double)sd1, (double)sd2);
+ }
+
+}
-/*---------------------------------------------------------------------------*\\r
-\r
- FILE........: adc_sfdr_ut.c\r
- AUTHOR......: David Rowe\r
- DATE CREATED: August 2015\r
-\r
- Unit test for high speed ADC SFDR testing. Samples ADC1 from in PA1 at \r
- Fs=2 MHz and write raw samples to a file, in discontinuus blocks of \r
- ADC_TUNER_BUF_SZ/2 samples. The blocks are discontinuous as we \r
- don'thave the bandwitdh back to the host to support continuous sampling.\r
-\r
- To process the blocks, fread() ADC_TUNER_BUF_SZ/2 samples at a time,\r
- abs(fft) and sum results from next block.\r
-\r
-\*---------------------------------------------------------------------------*/\r
-\r
-/*\r
- Copyright (C) 2015 David Rowe\r
-\r
- All rights reserved.\r
-\r
- This program is free software; you can redistribute it and/or modify\r
- it under the terms of the GNU Lesser General Public License version 2.1, as\r
- published by the Free Software Foundation. This program is\r
- distributed in the hope that it will be useful, but WITHOUT ANY\r
- WARRANTY; without even the implied warranty of MERCHANTABILITY or\r
- FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public\r
- License for more details.\r
-\r
- You should have received a copy of the GNU Lesser General Public License\r
- along with this program; if not, see <http://www.gnu.org/licenses/>.\r
-*/\r
-\r
-#include <assert.h>\r
-#include <stdlib.h>\r
-#include "gdb_stdio.h"\r
-#include "stm32f4_dac.h"\r
-#include "stm32f4_adc_tuner.h"\r
-#include "iir_tuner.h"\r
-#include "sm1000_leds_switches.h"\r
-#include "../src/codec2_fm.h"\r
-#include "stm32f4xx.h"\r
-\r
-#define BUFS 10\r
-#define FS 2E6\r
-#define N 1024\r
-\r
-extern int adc_overflow1;\r
-\r
-int main(void) {\r
- unsigned short unsigned_buf[N];\r
- short buf[N];\r
- int sam;\r
- int i, j, fifo_sz;\r
- FILE *fadc;\r
-\r
- fadc = fopen("adc.raw", "wb");\r
- if (fadc == NULL) {\r
- printf("Error opening output file: adc.raw\n\nTerminating....\n");\r
- exit(1);\r
- }\r
- fifo_sz = ADC_TUNER_BUF_SZ;\r
- printf("Starting! bufs: %d %d\n", BUFS, fifo_sz);\r
- \r
- adc_open(fifo_sz);\r
- adc_set_tuner_en(0); /* dump raw samples, no tuner */\r
-\r
- sm1000_leds_switches_init();\r
-\r
- for (i=0; i<BUFS; i++) {\r
- while(adc1_read((short*)unsigned_buf, N) == -1);\r
-\r
- /* convert to signed */\r
-\r
- for(j=0; j<N; j++) {\r
- sam = (int)unsigned_buf[j] - 32768;\r
- buf[j] = sam;\r
- }\r
-\r
- /* most of the time will be spent here */\r
-\r
- GPIOE->ODR |= (1 << 3);\r
- fwrite(buf, sizeof(short), N, fadc);\r
- GPIOE->ODR &= ~(1 << 3);\r
- }\r
- fclose(fadc);\r
-\r
- printf("Finished!\n");\r
-}\r
-\r
+/*---------------------------------------------------------------------------*\
+
+ FILE........: adc_sfdr_ut.c
+ AUTHOR......: David Rowe
+ DATE CREATED: August 2015
+
+ Unit test for high speed ADC SFDR testing. Samples ADC1 from in PA1 at
+ Fs=2 MHz and write raw samples to a file, in discontinuus blocks of
+ ADC_TUNER_BUF_SZ/2 samples. The blocks are discontinuous as we
+ don'thave the bandwitdh back to the host to support continuous sampling.
+
+ To process the blocks, fread() ADC_TUNER_BUF_SZ/2 samples at a time,
+ abs(fft) and sum results from next block.
+
+\*---------------------------------------------------------------------------*/
+
+/*
+ Copyright (C) 2015 David Rowe
+
+ All rights reserved.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License version 2.1, as
+ published by the Free Software Foundation. This program is
+ distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+ License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with this program; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <assert.h>
+#include <stdlib.h>
+#include "gdb_stdio.h"
+#include "stm32f4_dac.h"
+#include "stm32f4_adc_tuner.h"
+#include "iir_tuner.h"
+#include "sm1000_leds_switches.h"
+#include "../src/codec2_fm.h"
+#include "stm32f4xx.h"
+
+#define BUFS 10
+#define FS 2E6
+#define N 1024
+
+extern int adc_overflow1;
+
+int main(void) {
+ unsigned short unsigned_buf[N];
+ short buf[N];
+ int sam;
+ int i, j, fifo_sz;
+ FILE *fadc;
+
+ fadc = fopen("adc.raw", "wb");
+ if (fadc == NULL) {
+ printf("Error opening output file: adc.raw\n\nTerminating....\n");
+ exit(1);
+ }
+ fifo_sz = ADC_TUNER_BUF_SZ;
+ printf("Starting! bufs: %d %d\n", BUFS, fifo_sz);
+
+ adc_open(fifo_sz);
+ adc_set_tuner_en(0); /* dump raw samples, no tuner */
+
+ sm1000_leds_switches_init();
+
+ for (i=0; i<BUFS; i++) {
+ while(adc1_read((short*)unsigned_buf, N) == -1);
+
+ /* convert to signed */
+
+ for(j=0; j<N; j++) {
+ sam = (int)unsigned_buf[j] - 32768;
+ buf[j] = sam;
+ }
+
+ /* most of the time will be spent here */
+
+ GPIOE->ODR |= (1 << 3);
+ fwrite(buf, sizeof(short), N, fadc);
+ GPIOE->ODR &= ~(1 << 3);
+ }
+ fclose(fadc);
+
+ printf("Finished!\n");
+}
+
-/*---------------------------------------------------------------------------*\\r
-\r
- FILE........: adcdac_ut.c\r
- AUTHOR......: David Rowe\r
- DATE CREATED: May 31 201310 Aug 2014\r
-\r
- Echoes ADC2 input (mic) to DAC2 output (speaker) on SM1000.\r
-\r
-\*---------------------------------------------------------------------------*/\r
-\r
-/*\r
- Copyright (C) 2013 David Rowe\r
-\r
- All rights reserved.\r
-\r
- This program is free software; you can redistribute it and/or modify\r
- it under the terms of the GNU Lesser General Public License version 2.1, as\r
- published by the Free Software Foundation. This program is\r
- distributed in the hope that it will be useful, but WITHOUT ANY\r
- WARRANTY; without even the implied warranty of MERCHANTABILITY or\r
- FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public\r
- License for more details.\r
-\r
- You should have received a copy of the GNU Lesser General Public License\r
- along with this program; if not, see <http://www.gnu.org/licenses/>.\r
-*/\r
-\r
-#include <assert.h>\r
-#include "stm32f4_dac.h"\r
-#include "stm32f4_adc.h"\r
-#include "sm1000_leds_switches.h"\r
-\r
-#define SINE_SAMPLES 32\r
-\r
-\r
-/* 32 sample sine wave which at Fs=16kHz will be 500Hz. Note samples\r
- are 16 bit 2's complement, the DAC driver convertsto 12 bit\r
- unsigned. */\r
-\r
-short aSine[] = {\r
- -16, 6384, 12528, 18192, 23200, 27232, 30256, 32128,\r
- 32752, 32128, 30256, 27232, 23152, 18192, 12528, 6384,\r
- -16, -6416, -12560, -18224, -23184, -27264, -30288, -32160,\r
- -32768, -32160, -30288, -27264, -23184, -18224, -12560, -6416\r
-};\r
-\r
-int main(void) {\r
- short buf[SINE_SAMPLES];\r
- int i;\r
-\r
- dac_open(4*DAC_BUF_SZ);\r
- adc_open(4*ADC_BUF_SZ);\r
- sm1000_leds_switches_init();\r
-\r
- while (1) {\r
-\r
- /* keep DAC FIFOs topped up */\r
-\r
- while(adc2_read(buf, SINE_SAMPLES) == -1);\r
- \r
- if (!switch_select()) {\r
- for(i=0; i<SINE_SAMPLES; i++)\r
- buf[i] = aSine[i];\r
- }\r
- \r
- dac2_write(buf, SINE_SAMPLES);\r
- }\r
- \r
-}\r
-\r
+/*---------------------------------------------------------------------------*\
+
+ FILE........: adcdac_ut.c
+ AUTHOR......: David Rowe
+ DATE CREATED: May 31 201310 Aug 2014
+
+ Echoes ADC2 input (mic) to DAC2 output (speaker) on SM1000.
+
+\*---------------------------------------------------------------------------*/
+
+/*
+ Copyright (C) 2013 David Rowe
+
+ All rights reserved.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License version 2.1, as
+ published by the Free Software Foundation. This program is
+ distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+ License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with this program; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <assert.h>
+#include "stm32f4_dac.h"
+#include "stm32f4_adc.h"
+#include "sm1000_leds_switches.h"
+
+#define SINE_SAMPLES 32
+
+
+/* 32 sample sine wave which at Fs=16kHz will be 500Hz. Note samples
+ are 16 bit 2's complement, the DAC driver convertsto 12 bit
+ unsigned. */
+
+short aSine[] = {
+ -16, 6384, 12528, 18192, 23200, 27232, 30256, 32128,
+ 32752, 32128, 30256, 27232, 23152, 18192, 12528, 6384,
+ -16, -6416, -12560, -18224, -23184, -27264, -30288, -32160,
+ -32768, -32160, -30288, -27264, -23184, -18224, -12560, -6416
+};
+
+int main(void) {
+ short buf[SINE_SAMPLES];
+ int i;
+
+ dac_open(4*DAC_BUF_SZ);
+ adc_open(4*ADC_BUF_SZ);
+ sm1000_leds_switches_init();
+
+ while (1) {
+
+ /* keep DAC FIFOs topped up */
+
+ while(adc2_read(buf, SINE_SAMPLES) == -1);
+
+ if (!switch_select()) {
+ for(i=0; i<SINE_SAMPLES; i++)
+ buf[i] = aSine[i];
+ }
+
+ dac2_write(buf, SINE_SAMPLES);
+ }
+
+}
+
-/*---------------------------------------------------------------------------*\\r
-\r
- FILE........: codec2_profile.c\r
- AUTHOR......: David Rowe\r
- DATE CREATED: 30 May 2013\r
-\r
- Profiling Codec 2 operation on the STM32F4.\r
-\r
-\*---------------------------------------------------------------------------*/\r
-\r
-/*\r
- Copyright (C) 2014 David Rowe\r
-\r
- All rights reserved.\r
-\r
- This program is free software; you can redistribute it and/or modify\r
- it under the terms of the GNU Lesser General Public License version 2.1, as\r
- published by the Free Software Foundation. This program is\r
- distributed in the hope that it will be useful, but WITHOUT ANY\r
- WARRANTY; without even the implied warranty of MERCHANTABILITY or\r
- FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public\r
- License for more details.\r
-\r
- You should have received a copy of the GNU Lesser General Public License\r
- along with this program; if not, see <http://www.gnu.org/licenses/>.\r
-*/\r
-\r
-#include <stdio.h>\r
-#include <stdlib.h>\r
-#include <stdint.h>\r
-#include <math.h>\r
-\r
-#include "stm32f4xx_conf.h"\r
-#include "stm32f4xx.h"\r
-#include "gdb_stdio.h"\r
-#include "codec2.h"\r
-#include "dump.h"\r
-#include "sine.h"\r
-#include "machdep.h"\r
-\r
-#ifdef __EMBEDDED__\r
-#define printf gdb_stdio_printf\r
-#define fopen gdb_stdio_fopen\r
-#define fclose gdb_stdio_fclose\r
-#define fread gdb_stdio_fread\r
-#define fwrite gdb_stdio_fwrite\r
-#endif\r
-\r
-static void c2demo(int mode, char inputfile[], char outputfile[])\r
-{\r
- struct CODEC2 *codec2;\r
- short *inbuf, *outbuf;\r
- unsigned char *bits;\r
- int nsam, nbit;\r
- FILE *fin, *fout;\r
- int frame;\r
- PROFILE_VAR(enc_start, dec_start);\r
-\r
- codec2 = codec2_create(mode);\r
- nsam = codec2_samples_per_frame(codec2);\r
- outbuf = (short*)malloc(nsam*sizeof(short));\r
- inbuf = (short*)malloc(nsam*sizeof(short));\r
- nbit = codec2_bits_per_frame(codec2);\r
- bits = (unsigned char*)malloc(nbit*sizeof(char));\r
-\r
- fin = fopen(inputfile, "rb");\r
- if (fin == NULL) {\r
- printf("Error opening input file: %s\n\nTerminating....\n",inputfile);\r
- exit(1);\r
- }\r
-\r
- fout = fopen(outputfile, "wb");\r
- if (fout == NULL) {\r
- printf("Error opening output file: %s\n\nTerminating....\n",outputfile);\r
- exit(1);\r
- }\r
-\r
- #ifdef DUMP\r
- dump_on("stm32f4");\r
- #endif\r
- frame = 0;\r
-\r
- while (fread(inbuf, sizeof(short), nsam, fin) == nsam) {\r
- PROFILE_SAMPLE(enc_start);\r
- codec2_encode(codec2, bits, inbuf);\r
- PROFILE_SAMPLE_AND_LOG(dec_start, enc_start, " enc"); \r
- codec2_decode(codec2, outbuf, bits);\r
- PROFILE_SAMPLE_AND_LOG2(dec_start, " dec"); \r
- PROFILE_SAMPLE_AND_LOG2(enc_start, " enc & dec"); \r
- fwrite((char*)outbuf, sizeof(short), nsam, fout);\r
- printf("frame: %d\n", ++frame);\r
- machdep_profile_print_logged_samples();\r
- }\r
-\r
- #ifdef DUMP\r
- dump_off("sm32f4");\r
- #endif\r
-\r
- fclose(fin);\r
- fclose(fout);\r
- free(inbuf);\r
- free(outbuf);\r
- free(bits);\r
- codec2_destroy(codec2);\r
-}\r
-\r
-#define SPEED_TEST_SAMPLES 24000\r
-\r
-static void c2speedtest(int mode, char inputfile[])\r
-{\r
- struct CODEC2 *codec2;\r
- short *inbuf, *outbuf, *pinbuf;\r
- unsigned char *bits;\r
- int nsam, nbit, nframes;\r
- FILE *fin;\r
- int f, nread;\r
-\r
- codec2 = codec2_create(mode);\r
- nsam = codec2_samples_per_frame(codec2);\r
- nframes = SPEED_TEST_SAMPLES/nsam;\r
- outbuf = (short*)malloc(nsam*sizeof(short));\r
- inbuf = (short*)malloc(SPEED_TEST_SAMPLES*sizeof(short));\r
- nbit = codec2_bits_per_frame(codec2);\r
- bits = (unsigned char*)malloc(nbit*sizeof(char));\r
-\r
- fin = fopen(inputfile, "rb");\r
- if (fin == NULL) {\r
- printf("Error opening input file: %s\nTerminating....\n",inputfile);\r
- exit(1);\r
- }\r
-\r
- nread = fread(inbuf, sizeof(short), SPEED_TEST_SAMPLES, fin);\r
- if (nread != SPEED_TEST_SAMPLES) {\r
- printf("error reading %s, %d samples reqd, %d read\n", \r
- inputfile, SPEED_TEST_SAMPLES, nread);\r
- }\r
- fclose(fin);\r
- \r
- pinbuf = inbuf;\r
- for(f=0; f<nframes; f++) {\r
- GPIOD->ODR = (1 << 13);\r
- codec2_encode(codec2, bits, pinbuf);\r
- pinbuf += nsam;\r
- GPIOD->ODR &= ~(1 << 13);\r
- codec2_decode(codec2, outbuf, bits);\r
- }\r
-\r
- free(inbuf);\r
- free(outbuf);\r
- free(bits);\r
- codec2_destroy(codec2);\r
-}\r
-\r
-void gpio_init() {\r
- RCC->AHB1ENR |= RCC_AHB1ENR_GPIODEN; // enable the clock to GPIOD \r
- GPIOD->MODER = (1 << 26); // set pin 13 to be general \r
- // purpose output\r
-}\r
-\r
-int main(int argc, char *argv[]) {\r
- gpio_init();\r
- machdep_profile_init ();\r
- \r
- printf("Starting c2demo\n");\r
-\r
- /* File I/O test for profiling or (with #define DUMP)\r
- dumping states for optimisation and tiuning */\r
-\r
- c2demo(CODEC2_MODE_1600, "stm_in.raw", "stm_out.raw");\r
-\r
- printf("Starting c2 speed test\n");\r
- \r
- /* Another test of execution speed. Look at PD13 with a\r
- oscilliscope. On time is enc, off is dec */\r
-\r
- c2speedtest(CODEC2_MODE_1600, "stm_in.raw");\r
-\r
- printf("Finished\n");\r
-\r
- return 0;\r
-}\r
-\r
+/*---------------------------------------------------------------------------*\
+
+ FILE........: codec2_profile.c
+ AUTHOR......: David Rowe
+ DATE CREATED: 30 May 2013
+
+ Profiling Codec 2 operation on the STM32F4.
+
+\*---------------------------------------------------------------------------*/
+
+/*
+ Copyright (C) 2014 David Rowe
+
+ All rights reserved.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License version 2.1, as
+ published by the Free Software Foundation. This program is
+ distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+ License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with this program; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <math.h>
+
+#include "stm32f4xx_conf.h"
+#include "stm32f4xx.h"
+#include "gdb_stdio.h"
+#include "codec2.h"
+#include "dump.h"
+#include "sine.h"
+#include "machdep.h"
+
+#ifdef __EMBEDDED__
+#define printf gdb_stdio_printf
+#define fopen gdb_stdio_fopen
+#define fclose gdb_stdio_fclose
+#define fread gdb_stdio_fread
+#define fwrite gdb_stdio_fwrite
+#endif
+
+static void c2demo(int mode, char inputfile[], char outputfile[])
+{
+ struct CODEC2 *codec2;
+ short *inbuf, *outbuf;
+ unsigned char *bits;
+ int nsam, nbit;
+ FILE *fin, *fout;
+ int frame;
+ PROFILE_VAR(enc_start, dec_start);
+
+ codec2 = codec2_create(mode);
+ nsam = codec2_samples_per_frame(codec2);
+ outbuf = (short*)malloc(nsam*sizeof(short));
+ inbuf = (short*)malloc(nsam*sizeof(short));
+ nbit = codec2_bits_per_frame(codec2);
+ bits = (unsigned char*)malloc(nbit*sizeof(char));
+
+ fin = fopen(inputfile, "rb");
+ if (fin == NULL) {
+ printf("Error opening input file: %s\n\nTerminating....\n",inputfile);
+ exit(1);
+ }
+
+ fout = fopen(outputfile, "wb");
+ if (fout == NULL) {
+ printf("Error opening output file: %s\n\nTerminating....\n",outputfile);
+ exit(1);
+ }
+
+ #ifdef DUMP
+ dump_on("stm32f4");
+ #endif
+ frame = 0;
+
+ while (fread(inbuf, sizeof(short), nsam, fin) == nsam) {
+ PROFILE_SAMPLE(enc_start);
+ codec2_encode(codec2, bits, inbuf);
+ PROFILE_SAMPLE_AND_LOG(dec_start, enc_start, " enc");
+ codec2_decode(codec2, outbuf, bits);
+ PROFILE_SAMPLE_AND_LOG2(dec_start, " dec");
+ PROFILE_SAMPLE_AND_LOG2(enc_start, " enc & dec");
+ fwrite((char*)outbuf, sizeof(short), nsam, fout);
+ printf("frame: %d\n", ++frame);
+ machdep_profile_print_logged_samples();
+ }
+
+ #ifdef DUMP
+ dump_off("sm32f4");
+ #endif
+
+ fclose(fin);
+ fclose(fout);
+ free(inbuf);
+ free(outbuf);
+ free(bits);
+ codec2_destroy(codec2);
+}
+
+#define SPEED_TEST_SAMPLES 24000
+
+static void c2speedtest(int mode, char inputfile[])
+{
+ struct CODEC2 *codec2;
+ short *inbuf, *outbuf, *pinbuf;
+ unsigned char *bits;
+ int nsam, nbit, nframes;
+ FILE *fin;
+ int f, nread;
+
+ codec2 = codec2_create(mode);
+ nsam = codec2_samples_per_frame(codec2);
+ nframes = SPEED_TEST_SAMPLES/nsam;
+ outbuf = (short*)malloc(nsam*sizeof(short));
+ inbuf = (short*)malloc(SPEED_TEST_SAMPLES*sizeof(short));
+ nbit = codec2_bits_per_frame(codec2);
+ bits = (unsigned char*)malloc(nbit*sizeof(char));
+
+ fin = fopen(inputfile, "rb");
+ if (fin == NULL) {
+ printf("Error opening input file: %s\nTerminating....\n",inputfile);
+ exit(1);
+ }
+
+ nread = fread(inbuf, sizeof(short), SPEED_TEST_SAMPLES, fin);
+ if (nread != SPEED_TEST_SAMPLES) {
+ printf("error reading %s, %d samples reqd, %d read\n",
+ inputfile, SPEED_TEST_SAMPLES, nread);
+ }
+ fclose(fin);
+
+ pinbuf = inbuf;
+ for(f=0; f<nframes; f++) {
+ GPIOD->ODR = (1 << 13);
+ codec2_encode(codec2, bits, pinbuf);
+ pinbuf += nsam;
+ GPIOD->ODR &= ~(1 << 13);
+ codec2_decode(codec2, outbuf, bits);
+ }
+
+ free(inbuf);
+ free(outbuf);
+ free(bits);
+ codec2_destroy(codec2);
+}
+
+void gpio_init() {
+ RCC->AHB1ENR |= RCC_AHB1ENR_GPIODEN; // enable the clock to GPIOD
+ GPIOD->MODER = (1 << 26); // set pin 13 to be general
+ // purpose output
+}
+
+int main(int argc, char *argv[]) {
+ gpio_init();
+ machdep_profile_init ();
+
+ printf("Starting c2demo\n");
+
+ /* File I/O test for profiling or (with #define DUMP)
+ dumping states for optimisation and tiuning */
+
+ c2demo(CODEC2_MODE_1600, "stm_in.raw", "stm_out.raw");
+
+ printf("Starting c2 speed test\n");
+
+ /* Another test of execution speed. Look at PD13 with a
+ oscilliscope. On time is enc, off is dec */
+
+ c2speedtest(CODEC2_MODE_1600, "stm_in.raw");
+
+ printf("Finished\n");
+
+ return 0;
+}
+
-/**\r
- ******************************************************************************\r
- * @file DMA/DMA_FLASHToRAM/stm32f4xx_it.c \r
- * @author MCD Application Team\r
- * @version V1.1.0\r
- * @date 18-January-2013\r
- * @brief Main Interrupt Service Routines.\r
- * This file provides template for all exceptions handler and \r
- * peripherals interrupt service routine.\r
- ******************************************************************************\r
- * @attention\r
- *\r
- * <h2><center>© COPYRIGHT 2013 STMicroelectronics</center></h2>\r
- *\r
- * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License");\r
- * You may not use this file except in compliance with the License.\r
- * You may obtain a copy of the License at:\r
- *\r
- * http://www.st.com/software_license_agreement_liberty_v2\r
- *\r
- * Unless required by applicable law or agreed to in writing, software \r
- * distributed under the License is distributed on an "AS IS" BASIS, \r
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
- * See the License for the specific language governing permissions and\r
- * limitations under the License.\r
- *\r
- ******************************************************************************\r
- */\r
-int interrupts;\r
-\r
-\r
-/* Includes ------------------------------------------------------------------*/\r
-#include "dac_it.h"\r
-\r
-/** @addtogroup STM32F4xx_StdPeriph_Examples\r
- * @{\r
- */\r
-\r
-/** @addtogroup DMA_FLASHToRAM\r
- * @{\r
- */ \r
-\r
-/* Private typedef -----------------------------------------------------------*/\r
-/* Private define ------------------------------------------------------------*/\r
-/* Private macro -------------------------------------------------------------*/\r
-/* Private variables ---------------------------------------------------------*/\r
-/* Private function prototypes -----------------------------------------------*/\r
-/* Private functions ---------------------------------------------------------*/\r
-\r
-/******************************************************************************/\r
-/* Cortex-M4 Processor Exceptions Handlers */\r
-/******************************************************************************/\r
-\r
-/**\r
- * @brief This function handles NMI exception.\r
- * @param None\r
- * @retval None\r
- */\r
-void NMI_Handler(void)\r
-{\r
-}\r
-\r
-/**\r
- * @brief This function handles Hard Fault exception.\r
- * @param None\r
- * @retval None\r
- */\r
-void HardFault_Handler(void)\r
-{\r
- /* Go to infinite loop when Hard Fault exception occurs */\r
- while (1)\r
- {\r
- }\r
-}\r
-\r
-/**\r
- * @brief This function handles Memory Manage exception.\r
- * @param None\r
- * @retval None\r
- */\r
-void MemManage_Handler(void)\r
-{\r
- /* Go to infinite loop when Memory Manage exception occurs */\r
- while (1)\r
- {\r
- }\r
-}\r
-\r
-/**\r
- * @brief This function handles Bus Fault exception.\r
- * @param None\r
- * @retval None\r
- */\r
-void BusFault_Handler(void)\r
-{\r
- /* Go to infinite loop when Bus Fault exception occurs */\r
- while (1)\r
- {\r
- }\r
-}\r
-\r
-/**\r
- * @brief This function handles Usage Fault exception.\r
- * @param None\r
- * @retval None\r
- */\r
-void UsageFault_Handler(void)\r
-{\r
- /* Go to infinite loop when Usage Fault exception occurs */\r
- while (1)\r
- {\r
- }\r
-}\r
-\r
-/**\r
- * @brief This function handles SVCall exception.\r
- * @param None\r
- * @retval None\r
- */\r
-void SVC_Handler(void)\r
-{\r
-}\r
-\r
-/**\r
- * @brief This function handles Debug Monitor exception.\r
- * @param None\r
- * @retval None\r
- */\r
-void DebugMon_Handler(void)\r
-{\r
-}\r
-\r
-/**\r
- * @brief This function handles PendSVC exception.\r
- * @param None\r
- * @retval None\r
- */\r
-void PendSV_Handler(void)\r
-{\r
-}\r
-\r
-/**\r
- * @brief This function handles SysTick Handler.\r
- * @param None\r
- * @retval None\r
- */\r
-void SysTick_Handler(void)\r
-{\r
-}\r
-\r
-/******************************************************************************/\r
-/* STM32F4xx Peripherals Interrupt Handlers */\r
-/* Add here the Interrupt Handler for the used peripheral(s) (PPP), for the */\r
-/* available peripheral interrupt handler's name please refer to the startup */\r
-/* file (startup_stm32f40xx.s/startup_stm32f427x.s). */\r
-/******************************************************************************/\r
-\r
-/**\r
- * @brief This function handles DMA Stream interrupt request.\r
- * @param None\r
- * @retval None\r
- */\r
-void DMA1_Stream6_IRQHandler(void)\r
-{\r
-\r
- /* Transfer half empty interrupt */\r
-\r
- if(DMA_GetITStatus(DMA1_Stream6, DMA_IT_HTIF6) != RESET))\r
- {\r
- /* fill first half from fifo */\r
-\r
- fifo_read(DMA1_Stream6_fifo, dac_buf, DAC_BUF_SZ/2);\r
-\r
- /* Clear DMA Stream Transfer Complete interrupt pending bit */\r
-\r
- DMA_ClearITPendingBit(DMA1_Stream6, DMA_IT_HTIF6); \r
-\r
- interrupts++;\r
- }\r
-\r
- /* Transfer complete interrupt */\r
-\r
- if(DMA_GetITStatus(DMA1_Stream6, DMA_IT_TCIF6) != RESET))\r
- {\r
- /* fill second half from fifo */\r
-\r
- fifo_read(DMA1_Stream6_fifo, &dac_buf[DAC_BUF_SZ/2], DAC_BUF_SZ/2);\r
-\r
- /* Clear DMA Stream Transfer Complete interrupt pending bit */\r
-\r
- DMA_ClearITPendingBit(DMA1_Stream6, DMA_IT_TCIF6); \r
-\r
- interrupts++;\r
- }\r
-}\r
-\r
-/**\r
- * @}\r
- */ \r
-\r
-/**\r
- * @}\r
- */\r
-\r
-/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/\r
+/**
+ ******************************************************************************
+ * @file DMA/DMA_FLASHToRAM/stm32f4xx_it.c
+ * @author MCD Application Team
+ * @version V1.1.0
+ * @date 18-January-2013
+ * @brief Main Interrupt Service Routines.
+ * This file provides template for all exceptions handler and
+ * peripherals interrupt service routine.
+ ******************************************************************************
+ * @attention
+ *
+ * <h2><center>© COPYRIGHT 2013 STMicroelectronics</center></h2>
+ *
+ * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License");
+ * You may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.st.com/software_license_agreement_liberty_v2
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************
+ */
+int interrupts;
+
+
+/* Includes ------------------------------------------------------------------*/
+#include "dac_it.h"
+
+/** @addtogroup STM32F4xx_StdPeriph_Examples
+ * @{
+ */
+
+/** @addtogroup DMA_FLASHToRAM
+ * @{
+ */
+
+/* Private typedef -----------------------------------------------------------*/
+/* Private define ------------------------------------------------------------*/
+/* Private macro -------------------------------------------------------------*/
+/* Private variables ---------------------------------------------------------*/
+/* Private function prototypes -----------------------------------------------*/
+/* Private functions ---------------------------------------------------------*/
+
+/******************************************************************************/
+/* Cortex-M4 Processor Exceptions Handlers */
+/******************************************************************************/
+
+/**
+ * @brief This function handles NMI exception.
+ * @param None
+ * @retval None
+ */
+void NMI_Handler(void)
+{
+}
+
+/**
+ * @brief This function handles Hard Fault exception.
+ * @param None
+ * @retval None
+ */
+void HardFault_Handler(void)
+{
+ /* Go to infinite loop when Hard Fault exception occurs */
+ while (1)
+ {
+ }
+}
+
+/**
+ * @brief This function handles Memory Manage exception.
+ * @param None
+ * @retval None
+ */
+void MemManage_Handler(void)
+{
+ /* Go to infinite loop when Memory Manage exception occurs */
+ while (1)
+ {
+ }
+}
+
+/**
+ * @brief This function handles Bus Fault exception.
+ * @param None
+ * @retval None
+ */
+void BusFault_Handler(void)
+{
+ /* Go to infinite loop when Bus Fault exception occurs */
+ while (1)
+ {
+ }
+}
+
+/**
+ * @brief This function handles Usage Fault exception.
+ * @param None
+ * @retval None
+ */
+void UsageFault_Handler(void)
+{
+ /* Go to infinite loop when Usage Fault exception occurs */
+ while (1)
+ {
+ }
+}
+
+/**
+ * @brief This function handles SVCall exception.
+ * @param None
+ * @retval None
+ */
+void SVC_Handler(void)
+{
+}
+
+/**
+ * @brief This function handles Debug Monitor exception.
+ * @param None
+ * @retval None
+ */
+void DebugMon_Handler(void)
+{
+}
+
+/**
+ * @brief This function handles PendSVC exception.
+ * @param None
+ * @retval None
+ */
+void PendSV_Handler(void)
+{
+}
+
+/**
+ * @brief This function handles SysTick Handler.
+ * @param None
+ * @retval None
+ */
+void SysTick_Handler(void)
+{
+}
+
+/******************************************************************************/
+/* STM32F4xx Peripherals Interrupt Handlers */
+/* Add here the Interrupt Handler for the used peripheral(s) (PPP), for the */
+/* available peripheral interrupt handler's name please refer to the startup */
+/* file (startup_stm32f40xx.s/startup_stm32f427x.s). */
+/******************************************************************************/
+
+/**
+ * @brief This function handles DMA Stream interrupt request.
+ * @param None
+ * @retval None
+ */
+void DMA1_Stream6_IRQHandler(void)
+{
+
+ /* Transfer half empty interrupt */
+
+ if(DMA_GetITStatus(DMA1_Stream6, DMA_IT_HTIF6) != RESET))
+ {
+ /* fill first half from fifo */
+
+ fifo_read(DMA1_Stream6_fifo, dac_buf, DAC_BUF_SZ/2);
+
+ /* Clear DMA Stream Transfer Complete interrupt pending bit */
+
+ DMA_ClearITPendingBit(DMA1_Stream6, DMA_IT_HTIF6);
+
+ interrupts++;
+ }
+
+ /* Transfer complete interrupt */
+
+ if(DMA_GetITStatus(DMA1_Stream6, DMA_IT_TCIF6) != RESET))
+ {
+ /* fill second half from fifo */
+
+ fifo_read(DMA1_Stream6_fifo, &dac_buf[DAC_BUF_SZ/2], DAC_BUF_SZ/2);
+
+ /* Clear DMA Stream Transfer Complete interrupt pending bit */
+
+ DMA_ClearITPendingBit(DMA1_Stream6, DMA_IT_TCIF6);
+
+ interrupts++;
+ }
+}
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
-/*---------------------------------------------------------------------------*\\r
-\r
- FILE........: dac_play.c\r
- AUTHOR......: David Rowe\r
- DATE CREATED: 1 June 2013\r
-\r
- Plays a 16 kHz sample rate raw file to the STM32F4 DACs. DAC1 is\r
- connected to pin PA4, DAC2 is connected to pin PA5.\r
-\r
-\*---------------------------------------------------------------------------*/\r
-\r
-/*\r
- Copyright (C) 2013 David Rowe\r
-\r
- All rights reserved.\r
-\r
- This program is free software; you can redistribute it and/or modify\r
- it under the terms of the GNU Lesser General Public License version 2.1, as\r
- published by the Free Software Foundation. This program is\r
- distributed in the hope that it will be useful, but WITHOUT ANY\r
- WARRANTY; without even the implied warranty of MERCHANTABILITY or\r
- FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public\r
- License for more details.\r
-\r
- You should have received a copy of the GNU Lesser General Public License\r
- along with this program; if not, see <http://www.gnu.org/licenses/>.\r
-*/\r
-\r
-#include <stdlib.h>\r
-#include "stm32f4_dac.h"\r
-#include "gdb_stdio.h"\r
-\r
-#define N (5*DAC_BUF_SZ)\r
-\r
-int main(void) {\r
- short buf[N];\r
- FILE *fplay;\r
-\r
- dac_open(2*N);\r
-\r
- while(1) {\r
- fplay = fopen("stm_in.raw", "rb");\r
- if (fplay == NULL) {\r
- printf("Error opening input file: stm_in.raw\n\nTerminating....\n");\r
- exit(1);\r
- }\r
- \r
- printf("Starting!\n");\r
-\r
- while(fread(buf, sizeof(short), N, fplay) == N) {\r
- while(dac1_write(buf, N) == -1);\r
- while(dac2_write(buf, N) == -1);\r
- } \r
-\r
- printf("Finished!\n");\r
- fclose(fplay);\r
- }\r
-\r
- /* let FIFO empty */\r
-\r
- while(1);\r
-}\r
-\r
+/*---------------------------------------------------------------------------*\
+
+ FILE........: dac_play.c
+ AUTHOR......: David Rowe
+ DATE CREATED: 1 June 2013
+
+ Plays a 16 kHz sample rate raw file to the STM32F4 DACs. DAC1 is
+ connected to pin PA4, DAC2 is connected to pin PA5.
+
+\*---------------------------------------------------------------------------*/
+
+/*
+ Copyright (C) 2013 David Rowe
+
+ All rights reserved.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License version 2.1, as
+ published by the Free Software Foundation. This program is
+ distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+ License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with this program; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <stdlib.h>
+#include "stm32f4_dac.h"
+#include "gdb_stdio.h"
+
+#define N (5*DAC_BUF_SZ)
+
+int main(void) {
+ short buf[N];
+ FILE *fplay;
+
+ dac_open(2*N);
+
+ while(1) {
+ fplay = fopen("stm_in.raw", "rb");
+ if (fplay == NULL) {
+ printf("Error opening input file: stm_in.raw\n\nTerminating....\n");
+ exit(1);
+ }
+
+ printf("Starting!\n");
+
+ while(fread(buf, sizeof(short), N, fplay) == N) {
+ while(dac1_write(buf, N) == -1);
+ while(dac2_write(buf, N) == -1);
+ }
+
+ printf("Finished!\n");
+ fclose(fplay);
+ }
+
+ /* let FIFO empty */
+
+ while(1);
+}
+
-/*---------------------------------------------------------------------------*\\r
-\r
- FILE........: dac_ut.c\r
- AUTHOR......: David Rowe\r
- DATE CREATED: May 31 2013\r
-\r
- Plays a 500 Hz sine wave sampled at 16 kHz out of PA5 on a Discovery board,\r
- or the speaker output of the SM1000.\r
-\r
-\*---------------------------------------------------------------------------*/\r
-\r
-/*\r
- Copyright (C) 2013 David Rowe\r
-\r
- All rights reserved.\r
-\r
- This program is free software; you can redistribute it and/or modify\r
- it under the terms of the GNU Lesser General Public License version 2.1, as\r
- published by the Free Software Foundation. This program is\r
- distributed in the hope that it will be useful, but WITHOUT ANY\r
- WARRANTY; without even the implied warranty of MERCHANTABILITY or\r
- FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public\r
- License for more details.\r
-\r
- You should have received a copy of the GNU Lesser General Public License\r
- along with this program; if not, see <http://www.gnu.org/licenses/>.\r
-*/\r
-\r
-#include <assert.h>\r
-#include "stm32f4_dac.h"\r
-\r
-#define SINE_SAMPLES 32\r
-\r
-\r
-/* 32 sample sine wave which at Fs=16kHz will be 500Hz. Note samples\r
- are 16 bit 2's complement, the DAC driver convertsto 12 bit\r
- unsigned. */\r
-\r
-short aSine[] = {\r
- -16, 6384, 12528, 18192, 23200, 27232, 30256, 32128,\r
- 32752, 32128, 30256, 27232, 23152, 18192, 12528, 6384,\r
- -16, -6416, -12560, -18224, -23184, -27264, -30288, -32160,\r
- -32768, -32160, -30288, -27264, -23184, -18224, -12560, -6416\r
-};\r
-\r
-int main(void) {\r
-\r
- dac_open(4*DAC_BUF_SZ);\r
-\r
- while (1) {\r
-\r
- /* keep DAC FIFOs topped up */\r
-\r
- dac1_write((short*)aSine, SINE_SAMPLES);\r
- dac2_write((short*)aSine, SINE_SAMPLES);\r
- }\r
- \r
-}\r
-\r
+/*---------------------------------------------------------------------------*\
+
+ FILE........: dac_ut.c
+ AUTHOR......: David Rowe
+ DATE CREATED: May 31 2013
+
+ Plays a 500 Hz sine wave sampled at 16 kHz out of PA5 on a Discovery board,
+ or the speaker output of the SM1000.
+
+\*---------------------------------------------------------------------------*/
+
+/*
+ Copyright (C) 2013 David Rowe
+
+ All rights reserved.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License version 2.1, as
+ published by the Free Software Foundation. This program is
+ distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+ License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with this program; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <assert.h>
+#include "stm32f4_dac.h"
+
+#define SINE_SAMPLES 32
+
+
+/* 32 sample sine wave which at Fs=16kHz will be 500Hz. Note samples
+ are 16 bit 2's complement, the DAC driver convertsto 12 bit
+ unsigned. */
+
+short aSine[] = {
+ -16, 6384, 12528, 18192, 23200, 27232, 30256, 32128,
+ 32752, 32128, 30256, 27232, 23152, 18192, 12528, 6384,
+ -16, -6416, -12560, -18224, -23184, -27264, -30288, -32160,
+ -32768, -32160, -30288, -27264, -23184, -18224, -12560, -6416
+};
+
+int main(void) {
+
+ dac_open(4*DAC_BUF_SZ);
+
+ while (1) {
+
+ /* keep DAC FIFOs topped up */
+
+ dac1_write((short*)aSine, SINE_SAMPLES);
+ dac2_write((short*)aSine, SINE_SAMPLES);
+ }
+
+}
+
-/*---------------------------------------------------------------------------*\\r
-\r
- FILE........: debugblinky.c\r
- AUTHOR......: David Rowe\r
- DATE CREATED: 12 August 2014\r
-\r
- Configures GPIO pins used for debug blinkies\r
-\r
-\*---------------------------------------------------------------------------*/\r
-\r
-/*\r
- Copyright (C) 2014 David Rowe\r
-\r
- All rights reserved.\r
-\r
- This program is free software; you can redistribute it and/or modify\r
- it under the terms of the GNU Lesser General Public License version 2.1, as\r
- published by the Free Software Foundation. This program is\r
- distributed in the hope that it will be useful, but WITHOUT ANY\r
- WARRANTY; without even the implied warranty of MERCHANTABILITY or\r
- FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public\r
- License for more details.\r
-\r
- You should have received a copy of the GNU Lesser General Public License\r
- along with this program; if not, see <http://www.gnu.org/licenses/>.\r
-*/\r
-\r
-#include "stm32f4xx.h"\r
-\r
-void init_debug_blinky(void) {\r
- GPIO_InitTypeDef GPIO_InitStruct;\r
-\r
- /* PE0-3 used to indicate activity */\r
-\r
- RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOE, ENABLE);\r
-\r
- GPIO_InitStruct.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3;\r
- GPIO_InitStruct.GPIO_Mode = GPIO_Mode_OUT; \r
- GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz; \r
- GPIO_InitStruct.GPIO_OType = GPIO_OType_PP; \r
- GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_NOPULL; \r
- GPIO_Init(GPIOE, &GPIO_InitStruct); \r
-\r
-}\r
-\r
+/*---------------------------------------------------------------------------*\
+
+ FILE........: debugblinky.c
+ AUTHOR......: David Rowe
+ DATE CREATED: 12 August 2014
+
+ Configures GPIO pins used for debug blinkies
+
+\*---------------------------------------------------------------------------*/
+
+/*
+ Copyright (C) 2014 David Rowe
+
+ All rights reserved.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License version 2.1, as
+ published by the Free Software Foundation. This program is
+ distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+ License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with this program; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "stm32f4xx.h"
+
+void init_debug_blinky(void) {
+ GPIO_InitTypeDef GPIO_InitStruct;
+
+ /* PE0-3 used to indicate activity */
+
+ RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOE, ENABLE);
+
+ GPIO_InitStruct.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3;
+ GPIO_InitStruct.GPIO_Mode = GPIO_Mode_OUT;
+ GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
+ GPIO_InitStruct.GPIO_OType = GPIO_OType_PP;
+ GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_NOPULL;
+ GPIO_Init(GPIOE, &GPIO_InitStruct);
+
+}
+
-/*---------------------------------------------------------------------------*\\r
-\r
- FILE........: dac_ut.c\r
- AUTHOR......: David Rowe\r
- DATE CREATED: May 31 2013\r
-\r
- Plays a 500 Hz sine wave sampled at 16 kHz out of PA5 on a Discovery board,\r
- or the speaker output of the SM1000.\r
-\r
-\*---------------------------------------------------------------------------*/\r
-\r
-/*\r
- Copyright (C) 2013 David Rowe\r
-\r
- All rights reserved.\r
-\r
- This program is free software; you can redistribute it and/or modify\r
- it under the terms of the GNU Lesser General Public License version 2.1, as\r
- published by the Free Software Foundation. This program is\r
- distributed in the hope that it will be useful, but WITHOUT ANY\r
- WARRANTY; without even the implied warranty of MERCHANTABILITY or\r
- FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public\r
- License for more details.\r
-\r
- You should have received a copy of the GNU Lesser General Public License\r
- along with this program; if not, see <http://www.gnu.org/licenses/>.\r
-*/\r
-\r
-#include <assert.h>\r
-#include <stdlib.h>\r
-#include "stm32f4_dacduc.h"\r
-#include "iir_duc.h"\r
-#include "stm32f4xx.h"\r
-#include <stm32f4xx_tim.h>\r
-#include <stm32f4xx_rcc.h>\r
-#include "gdb_stdio.h"\r
-#include "comp.h"\r
-//#include "gmsk_test_dat_m4.h"\r
-#define SINE_SAMPLES 32\r
-\r
-\r
-/* 32 sample sine wave which at Fs=16kHz will be 500Hz. Note samples\r
- are 16 bit 2's complement, the DAC driver convertsto 12 bit\r
- unsigned. */\r
- \r
-short aWave[] = {4095,0,4095,0,4095,0,4095,0,4095,0,4095,0,4095,0,4095,0,4095,0,4095,0,4095,0,4095,0,4095,0,4095,0,4095,0,4095,0,\r
- 4095,0,4095,0,4095,0,4095,0,4095,0,4095,0,4095,0,4095,0,4095,0,4095,0,4095,0,4095,0,4095,0,4095,0,4095,0,4095,0,};\r
-\r
-short aSine[] = {1600, 3200, 1601, 0, 1600, 3200, 1601, 0, 1600, 3200, 1601, 0, 1600, 3200, 1601, 0, 1600, 3200, 1601, 0, 1600, 3200, 1601, 0, 1600, 3200, 1600, 0, 1600, 3200, 1601, 0\r
-};\r
-\r
-//Sine at Fs/4\r
-float f4sine[] = {1,0,-1,0,1,0,-1,0,1,0,-1,0,1,0,-1,0,1,0,-1,0,1,0,-1,0,1,0,-1,0,1,0,-1,0,1,0,-1,0,1,0,-1,0,1,0,-1,0,1,0,-1,0,\r
-1,0,-1,0,1,0,-1,0,1,0,-1,0,1,0,-1,0,1,0,-1,0,1,0,-1,0,1,0,-1,0,1,0,-1,0,1,0,-1,0,1,0,-1,0,1,0,-1,0,1,0,-1,0,\r
-1,0,-1,0,1,0,-1,0,1,0,-1,0,1,0,-1,0,1,0,-1,0,1,0,-1,0,1,0,-1,0,1,0,-1,0,1,0,-1,0,1,0,-1,0,1,0,-1,0,1,0,-1,0,\r
-1,0,-1,0,1,0,-1,0,1,0,-1,0,1,0,-1,0,1,0,-1,0,1,0,-1,0,1,0,-1,0,1,0,-1,0,};\r
-\r
-//Intermediate 80k real before tx\r
-int tx_imm[DUC_N];\r
-\r
-//Complex input to chain\r
-COMP comp_in[DUC_N/10];\r
-\r
-unsigned short outbuf[DAC_DUC_BUF_SZ];\r
-\r
-void setup_timer()\r
-{\r
- RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);\r
-\r
- TIM_TimeBaseInitTypeDef timerInitStructure; \r
- timerInitStructure.TIM_Prescaler = 84;\r
- timerInitStructure.TIM_CounterMode = TIM_CounterMode_Up;\r
- timerInitStructure.TIM_Period = 0x8FFFFFFF;\r
- timerInitStructure.TIM_ClockDivision = 0;\r
- timerInitStructure.TIM_RepetitionCounter = 0;\r
- TIM_TimeBaseInit(TIM2, &timerInitStructure);\r
- TIM_Cmd(TIM2, ENABLE);\r
-}\r
-\r
-int main(void) {\r
- int tstart,tup,tend,cyc,i;\r
-\r
- memset((void*)outbuf,0,sizeof(short)*DAC_DUC_BUF_SZ);\r
- setup_timer();\r
- fast_dac_open(2*DAC_DUC_BUF_SZ,2*DAC_BUF_SZ);\r
- tstart=tend=tup=cyc=0;\r
- //Initalize complex input with signal at zero\r
- for(i=0;i<DUC_48N;i++){\r
- comp_in[i].real=1;\r
- comp_in[i].imag=0;\r
- }\r
- while (1) {\r
- cyc++;\r
- //if(cyc>GMSK_TEST_LEN)\r
- // cyc=0;\r
- if(cyc%10000==0){\r
- printf("48c80r takes %d uSecs\n",tup-tstart);\r
- printf("iir upconvert takes %d uSecs\n",tend-tup);\r
- }\r
- tstart = TIM_GetCounter(TIM2);\r
-\r
- upconv_48c_80r(comp_in,tx_imm,1);\r
-\r
- tup = TIM_GetCounter(TIM2);\r
-\r
- iir_upconv_fixp(tx_imm,outbuf);\r
-\r
- tend = TIM_GetCounter(TIM2);\r
-\r
- //Sit and spin until we can get more samples into the dac \r
- while(dac1_write((short*)outbuf,DAC_DUC_BUF_SZ)<0);\r
- }\r
- \r
-}\r
-\r
+/*---------------------------------------------------------------------------*\
+
+ FILE........: dac_ut.c
+ AUTHOR......: David Rowe
+ DATE CREATED: May 31 2013
+
+ Plays a 500 Hz sine wave sampled at 16 kHz out of PA5 on a Discovery board,
+ or the speaker output of the SM1000.
+
+\*---------------------------------------------------------------------------*/
+
+/*
+ Copyright (C) 2013 David Rowe
+
+ All rights reserved.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License version 2.1, as
+ published by the Free Software Foundation. This program is
+ distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+ License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with this program; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <assert.h>
+#include <stdlib.h>
+#include "stm32f4_dacduc.h"
+#include "iir_duc.h"
+#include "stm32f4xx.h"
+#include <stm32f4xx_tim.h>
+#include <stm32f4xx_rcc.h>
+#include "gdb_stdio.h"
+#include "comp.h"
+//#include "gmsk_test_dat_m4.h"
+#define SINE_SAMPLES 32
+
+
+/* 32 sample sine wave which at Fs=16kHz will be 500Hz. Note samples
+ are 16 bit 2's complement, the DAC driver convertsto 12 bit
+ unsigned. */
+
+short aWave[] = {4095,0,4095,0,4095,0,4095,0,4095,0,4095,0,4095,0,4095,0,4095,0,4095,0,4095,0,4095,0,4095,0,4095,0,4095,0,4095,0,
+ 4095,0,4095,0,4095,0,4095,0,4095,0,4095,0,4095,0,4095,0,4095,0,4095,0,4095,0,4095,0,4095,0,4095,0,4095,0,4095,0,};
+
+short aSine[] = {1600, 3200, 1601, 0, 1600, 3200, 1601, 0, 1600, 3200, 1601, 0, 1600, 3200, 1601, 0, 1600, 3200, 1601, 0, 1600, 3200, 1601, 0, 1600, 3200, 1600, 0, 1600, 3200, 1601, 0
+};
+
+//Sine at Fs/4
+float f4sine[] = {1,0,-1,0,1,0,-1,0,1,0,-1,0,1,0,-1,0,1,0,-1,0,1,0,-1,0,1,0,-1,0,1,0,-1,0,1,0,-1,0,1,0,-1,0,1,0,-1,0,1,0,-1,0,
+1,0,-1,0,1,0,-1,0,1,0,-1,0,1,0,-1,0,1,0,-1,0,1,0,-1,0,1,0,-1,0,1,0,-1,0,1,0,-1,0,1,0,-1,0,1,0,-1,0,1,0,-1,0,
+1,0,-1,0,1,0,-1,0,1,0,-1,0,1,0,-1,0,1,0,-1,0,1,0,-1,0,1,0,-1,0,1,0,-1,0,1,0,-1,0,1,0,-1,0,1,0,-1,0,1,0,-1,0,
+1,0,-1,0,1,0,-1,0,1,0,-1,0,1,0,-1,0,1,0,-1,0,1,0,-1,0,1,0,-1,0,1,0,-1,0,};
+
+//Intermediate 80k real before tx
+int tx_imm[DUC_N];
+
+//Complex input to chain
+COMP comp_in[DUC_N/10];
+
+unsigned short outbuf[DAC_DUC_BUF_SZ];
+
+void setup_timer()
+{
+ RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
+
+ TIM_TimeBaseInitTypeDef timerInitStructure;
+ timerInitStructure.TIM_Prescaler = 84;
+ timerInitStructure.TIM_CounterMode = TIM_CounterMode_Up;
+ timerInitStructure.TIM_Period = 0x8FFFFFFF;
+ timerInitStructure.TIM_ClockDivision = 0;
+ timerInitStructure.TIM_RepetitionCounter = 0;
+ TIM_TimeBaseInit(TIM2, &timerInitStructure);
+ TIM_Cmd(TIM2, ENABLE);
+}
+
+int main(void) {
+ int tstart,tup,tend,cyc,i;
+
+ memset((void*)outbuf,0,sizeof(short)*DAC_DUC_BUF_SZ);
+ setup_timer();
+ fast_dac_open(2*DAC_DUC_BUF_SZ,2*DAC_BUF_SZ);
+ tstart=tend=tup=cyc=0;
+ //Initalize complex input with signal at zero
+ for(i=0;i<DUC_48N;i++){
+ comp_in[i].real=1;
+ comp_in[i].imag=0;
+ }
+ while (1) {
+ cyc++;
+ //if(cyc>GMSK_TEST_LEN)
+ // cyc=0;
+ if(cyc%10000==0){
+ printf("48c80r takes %d uSecs\n",tup-tstart);
+ printf("iir upconvert takes %d uSecs\n",tend-tup);
+ }
+ tstart = TIM_GetCounter(TIM2);
+
+ upconv_48c_80r(comp_in,tx_imm,1);
+
+ tup = TIM_GetCounter(TIM2);
+
+ iir_upconv_fixp(tx_imm,outbuf);
+
+ tend = TIM_GetCounter(TIM2);
+
+ //Sit and spin until we can get more samples into the dac
+ while(dac1_write((short*)outbuf,DAC_DUC_BUF_SZ)<0);
+ }
+
+}
+
-/*---------------------------------------------------------------------------*\\r
-\r
- FILE........: fdmdv_dump_rt.c\r
- AUTHOR......: David Rowe\r
- DATE CREATED: 9 Sep 2014\r
-\r
- Runs the fdmdv demod in real time for a few seconds then dumps some\r
- modem info to a text file for plotting in Octave. Way to verify the\r
- "from radio" SM1000 hardware, ADC, and demod on the SM1000.\r
-\r
- Requires FreeDV signal to be sent to CN6 of SM1000.\r
-\r
- Octave:\r
-\r
- load scatter.txt\r
- l=length(scatter)\r
- plot(scatter(:,1:2:l),scatter(:,2:2:l),'+')\r
-\r
-\*---------------------------------------------------------------------------*/\r
-\r
-/*\r
- Copyright (C) 2014 David Rowe\r
-\r
- All rights reserved.\r
-\r
- This program is free software; you can redistribute it and/or modify\r
- it under the terms of the GNU Lesser General Public License version 2.1, as\r
- published by the Free Software Foundation. This program is\r
- distributed in the hope that it will be useful, but WITHOUT ANY\r
- WARRANTY; without even the implied warranty of MERCHANTABILITY or\r
- FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public\r
- License for more details.\r
-\r
- You should have received a copy of the GNU Lesser General Public License\r
- along with this program; if not, see <http://www.gnu.org/licenses/>.\r
-*/\r
-\r
-#include <assert.h>\r
-#include <stdio.h>\r
-#include <stdlib.h>\r
-#include <stdint.h>\r
-#include <math.h>\r
-\r
-#include <stm32f4xx_gpio.h>\r
-#include "stm32f4_adc.h"\r
-#include "stm32f4_dac.h"\r
-#include "freedv_api.h"\r
-#include "codec2_fdmdv.h"\r
-#include "sm1000_leds_switches.h"\r
-#include "gdb_stdio.h"\r
-\r
-#ifdef __EMBEDDED__\r
-#define printf gdb_stdio_printf\r
-#define fprintf gdb_stdio_fprintf\r
-#define fopen gdb_stdio_fopen\r
-#define fclose gdb_stdio_fclose\r
-#define fread gdb_stdio_fread\r
-#define fwrite gdb_stdio_fwrite\r
-#endif\r
-\r
-#define FREEDV_NSAMPLES_16K (2*FREEDV_NSAMPLES)\r
-#define START_LOG_FRAMES 100\r
-#define LOG_FRAMES 10\r
-#define STOP_LOG_FRAMES (START_LOG_FRAMES+LOG_FRAMES)\r
-#define NC 16\r
-\r
-int main(void) {\r
- struct freedv *f;\r
- short adc16k[FDMDV_OS_TAPS_16K+FREEDV_NSAMPLES_16K];\r
- short dac16k[FREEDV_NSAMPLES_16K];\r
- short adc8k[FREEDV_NSAMPLES];\r
- short dac8k[FDMDV_OS_TAPS_8K+FREEDV_NSAMPLES];\r
- \r
- int nin, nout, i, j, frames, lines;\r
-\r
- COMP *symb, *psymb;\r
-\r
- /* init all the drivers for various peripherals */\r
-\r
- sm1000_leds_switches_init();\r
- dac_open(4*DAC_BUF_SZ);\r
- adc_open(4*ADC_BUF_SZ);\r
- f = freedv_open(FREEDV_MODE_1600);\r
-\r
- /* clear filter memories */\r
-\r
- for(i=0; i<FDMDV_OS_TAPS_16K; i++)\r
- adc16k[i] = 0.0;\r
- for(i=0; i<FDMDV_OS_TAPS_8K; i++)\r
- dac8k[i] = 0.0;\r
-\r
- /* allocate storage for the symbols */\r
-\r
-#define TMP\r
-#ifdef TMP\r
- symb = (COMP*)malloc(sizeof(COMP)*(NC+1)*(STOP_LOG_FRAMES - START_LOG_FRAMES));\r
- assert(symb != NULL);\r
- psymb = symb;\r
- frames = 0;\r
- lines = 0;\r
-#endif\r
- while(1) {\r
-\r
- /* Receive --------------------------------------------------------------------------*/\r
-\r
- /* ADC1 is the demod in signal from the radio rx, DAC2 is the SM1000 speaker */\r
-\r
- nin = freedv_nin(f); \r
- nout = nin;\r
- f->total_bit_errors = 0;\r
-\r
- if (adc1_read(&adc16k[FDMDV_OS_TAPS_16K], 2*nin) == 0) {\r
- GPIOE->ODR = (1 << 3);\r
- fdmdv_16_to_8_short(adc8k, &adc16k[FDMDV_OS_TAPS_16K], nin);\r
- nout = freedv_rx(f, &dac8k[FDMDV_OS_TAPS_8K], adc8k);\r
- fdmdv_8_to_16_short(dac16k, &dac8k[FDMDV_OS_TAPS_8K], nout); \r
- dac2_write(dac16k, 2*nout);\r
- led_ptt(0); led_rt(f->fdmdv_stats.sync); led_err(f->total_bit_errors);\r
- GPIOE->ODR &= ~(1 << 3);\r
-\r
-#define TMP1\r
-#ifdef TMP1\r
- if (f->fdmdv_stats.sync)\r
- frames++;\r
- if ((frames >= START_LOG_FRAMES) && (lines < LOG_FRAMES)) {\r
- for(i=0; i<=f->fdmdv_stats.Nc; i++)\r
- psymb[i] = f->fdmdv_stats.rx_symbols[i];\r
- psymb += (f->fdmdv_stats.Nc+1);\r
- lines++;\r
- }\r
- \r
- if (frames >= STOP_LOG_FRAMES) {\r
- FILE *ft = fopen("scatter.txt", "wt");\r
- assert(ft != NULL);\r
- printf("Writing scatter file....\n");\r
- for(j=0; j<LOG_FRAMES; j++) {\r
- for(i=0; i<=f->fdmdv_stats.Nc; i++) {\r
- fprintf(ft, "%f\t%f\t", \r
- (double)symb[j*(f->fdmdv_stats.Nc+1)+i].real,\r
- (double)symb[j*(f->fdmdv_stats.Nc+1)+i].imag);\r
- printf("line: %d\n", j);\r
- }\r
- fprintf(ft, "\n");\r
- }\r
- fclose(ft);\r
- printf("SNR = %3.2f dB\nfinished!\n", (double)f->fdmdv_stats.snr_est);\r
- while(1);\r
- }\r
-#endif\r
- }\r
- \r
- } /* while(1) ... */\r
-}\r
-\r
+/*---------------------------------------------------------------------------*\
+
+ FILE........: fdmdv_dump_rt.c
+ AUTHOR......: David Rowe
+ DATE CREATED: 9 Sep 2014
+
+ Runs the fdmdv demod in real time for a few seconds then dumps some
+ modem info to a text file for plotting in Octave. Way to verify the
+ "from radio" SM1000 hardware, ADC, and demod on the SM1000.
+
+ Requires FreeDV signal to be sent to CN6 of SM1000.
+
+ Octave:
+
+ load scatter.txt
+ l=length(scatter)
+ plot(scatter(:,1:2:l),scatter(:,2:2:l),'+')
+
+\*---------------------------------------------------------------------------*/
+
+/*
+ Copyright (C) 2014 David Rowe
+
+ All rights reserved.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License version 2.1, as
+ published by the Free Software Foundation. This program is
+ distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+ License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with this program; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <math.h>
+
+#include <stm32f4xx_gpio.h>
+#include "stm32f4_adc.h"
+#include "stm32f4_dac.h"
+#include "freedv_api.h"
+#include "codec2_fdmdv.h"
+#include "sm1000_leds_switches.h"
+#include "gdb_stdio.h"
+
+#ifdef __EMBEDDED__
+#define printf gdb_stdio_printf
+#define fprintf gdb_stdio_fprintf
+#define fopen gdb_stdio_fopen
+#define fclose gdb_stdio_fclose
+#define fread gdb_stdio_fread
+#define fwrite gdb_stdio_fwrite
+#endif
+
+#define FREEDV_NSAMPLES_16K (2*FREEDV_NSAMPLES)
+#define START_LOG_FRAMES 100
+#define LOG_FRAMES 10
+#define STOP_LOG_FRAMES (START_LOG_FRAMES+LOG_FRAMES)
+#define NC 16
+
+int main(void) {
+ struct freedv *f;
+ short adc16k[FDMDV_OS_TAPS_16K+FREEDV_NSAMPLES_16K];
+ short dac16k[FREEDV_NSAMPLES_16K];
+ short adc8k[FREEDV_NSAMPLES];
+ short dac8k[FDMDV_OS_TAPS_8K+FREEDV_NSAMPLES];
+
+ int nin, nout, i, j, frames, lines;
+
+ COMP *symb, *psymb;
+
+ /* init all the drivers for various peripherals */
+
+ sm1000_leds_switches_init();
+ dac_open(4*DAC_BUF_SZ);
+ adc_open(4*ADC_BUF_SZ);
+ f = freedv_open(FREEDV_MODE_1600);
+
+ /* clear filter memories */
+
+ for(i=0; i<FDMDV_OS_TAPS_16K; i++)
+ adc16k[i] = 0.0;
+ for(i=0; i<FDMDV_OS_TAPS_8K; i++)
+ dac8k[i] = 0.0;
+
+ /* allocate storage for the symbols */
+
+#define TMP
+#ifdef TMP
+ symb = (COMP*)malloc(sizeof(COMP)*(NC+1)*(STOP_LOG_FRAMES - START_LOG_FRAMES));
+ assert(symb != NULL);
+ psymb = symb;
+ frames = 0;
+ lines = 0;
+#endif
+ while(1) {
+
+ /* Receive --------------------------------------------------------------------------*/
+
+ /* ADC1 is the demod in signal from the radio rx, DAC2 is the SM1000 speaker */
+
+ nin = freedv_nin(f);
+ nout = nin;
+ f->total_bit_errors = 0;
+
+ if (adc1_read(&adc16k[FDMDV_OS_TAPS_16K], 2*nin) == 0) {
+ GPIOE->ODR = (1 << 3);
+ fdmdv_16_to_8_short(adc8k, &adc16k[FDMDV_OS_TAPS_16K], nin);
+ nout = freedv_rx(f, &dac8k[FDMDV_OS_TAPS_8K], adc8k);
+ fdmdv_8_to_16_short(dac16k, &dac8k[FDMDV_OS_TAPS_8K], nout);
+ dac2_write(dac16k, 2*nout);
+ led_ptt(0); led_rt(f->fdmdv_stats.sync); led_err(f->total_bit_errors);
+ GPIOE->ODR &= ~(1 << 3);
+
+#define TMP1
+#ifdef TMP1
+ if (f->fdmdv_stats.sync)
+ frames++;
+ if ((frames >= START_LOG_FRAMES) && (lines < LOG_FRAMES)) {
+ for(i=0; i<=f->fdmdv_stats.Nc; i++)
+ psymb[i] = f->fdmdv_stats.rx_symbols[i];
+ psymb += (f->fdmdv_stats.Nc+1);
+ lines++;
+ }
+
+ if (frames >= STOP_LOG_FRAMES) {
+ FILE *ft = fopen("scatter.txt", "wt");
+ assert(ft != NULL);
+ printf("Writing scatter file....\n");
+ for(j=0; j<LOG_FRAMES; j++) {
+ for(i=0; i<=f->fdmdv_stats.Nc; i++) {
+ fprintf(ft, "%f\t%f\t",
+ (double)symb[j*(f->fdmdv_stats.Nc+1)+i].real,
+ (double)symb[j*(f->fdmdv_stats.Nc+1)+i].imag);
+ printf("line: %d\n", j);
+ }
+ fprintf(ft, "\n");
+ }
+ fclose(ft);
+ printf("SNR = %3.2f dB\nfinished!\n", (double)f->fdmdv_stats.snr_est);
+ while(1);
+ }
+#endif
+ }
+
+ } /* while(1) ... */
+}
+
-/*---------------------------------------------------------------------------*\\r
-\r
- FILE........: fdmdv_profile.c\r
- AUTHOR......: David Rowe\r
- DATE CREATED: 18 July 2014\r
-\r
- Profiling FDMDV modem operation on the STM32F4.\r
-\r
-\*---------------------------------------------------------------------------*/\r
-\r
-/*\r
- Copyright (C) 2014 David Rowe\r
-\r
- All rights reserved.\r
-\r
- This program is free software; you can redistribute it and/or modify\r
- it under the terms of the GNU Lesser General Public License version 2.1, as\r
- published by the Free Software Foundation. This program is\r
- distributed in the hope that it will be useful, but WITHOUT ANY\r
- WARRANTY; without even the implied warranty of MERCHANTABILITY or\r
- FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public\r
- License for more details.\r
-\r
- You should have received a copy of the GNU Lesser General Public License\r
- along with this program; if not, see <http://www.gnu.org/licenses/>.\r
-*/\r
-\r
-#include <assert.h>\r
-#include <stdio.h>\r
-#include <stdlib.h>\r
-#include <stdint.h>\r
-#include <math.h>\r
-\r
-#include "stm32f4xx_conf.h"\r
-#include "stm32f4xx.h"\r
-#include "gdb_stdio.h"\r
-#include "codec2_fdmdv.h"\r
-#include "dump.h"\r
-#include "sine.h"\r
-#include "machdep.h"\r
-\r
-#ifdef __EMBEDDED__\r
-#define printf gdb_stdio_printf\r
-#define fopen gdb_stdio_fopen\r
-#define fclose gdb_stdio_fclose\r
-#define fread gdb_stdio_fread\r
-#define fwrite gdb_stdio_fwrite\r
-#endif\r
-\r
-#define TEST_FRAMES 25\r
-#define CHANNEL_BUF_SIZE (10*FDMDV_NOM_SAMPLES_PER_FRAME)\r
-\r
-static int channel_count = 0;\r
-static COMP channel[CHANNEL_BUF_SIZE];\r
-\r
-static void channel_in(COMP tx_fdm[], int nout) {\r
- int i;\r
-\r
- /* add M tx samples to end of buffer */\r
-\r
- assert((channel_count + nout) < CHANNEL_BUF_SIZE);\r
- for(i=0; i<nout; i++)\r
- channel[channel_count+i] = tx_fdm[i];\r
- channel_count += M;\r
-}\r
-\r
-static void channel_out(COMP rx_fdm[], int nin) {\r
- int i,j;\r
-\r
- /* take nin samples from start of buffer */\r
-\r
- for(i=0; i<nin; i++) {\r
- rx_fdm[i] = channel[i];\r
- }\r
-\r
- /* shift buffer back */\r
-\r
- for(i=0,j=nin; j<channel_count; i++,j++)\r
- channel[i] = channel[j];\r
- channel_count -= nin;\r
-}\r
-\r
-int main(int argc, char *argv[]) {\r
- struct FDMDV *fdmdv;\r
- int bits_per_fdmdv_frame, bits_per_codec_frame;\r
- int *tx_bits;\r
- int *rx_bits;\r
- int *codec_bits;\r
- COMP tx_fdm[2*FDMDV_NOM_SAMPLES_PER_FRAME];\r
- COMP rx_fdm[FDMDV_NOM_SAMPLES_PER_FRAME];\r
- int i, j, nin, reliable_sync_bit[2], sync_bit, bit_errors, ntest_bits, test_frame_sync;\r
- short *error_pattern;\r
- struct MODEM_STATS stats;\r
- PROFILE_VAR(mod_start, demod_start);\r
-\r
- machdep_profile_init ();\r
- fdmdv = fdmdv_create(FDMDV_NC);\r
-\r
- bits_per_fdmdv_frame = fdmdv_bits_per_frame(fdmdv);\r
- bits_per_codec_frame = 2*fdmdv_bits_per_frame(fdmdv);\r
- tx_bits = (int*)malloc(sizeof(int)*bits_per_codec_frame); assert(tx_bits != NULL);\r
- rx_bits = (int*)malloc(sizeof(int)*bits_per_codec_frame); assert(rx_bits != NULL);\r
- codec_bits = (int*)malloc(sizeof(int)*bits_per_codec_frame); assert(rx_bits != NULL);\r
- error_pattern = (short*)malloc(fdmdv_error_pattern_size(fdmdv)*sizeof(int)); assert(error_pattern != NULL);\r
-\r
- nin = FDMDV_NOM_SAMPLES_PER_FRAME;\r
- test_frame_sync = 0;\r
-\r
- for(i=0; i<TEST_FRAMES; i++) {\r
- fdmdv_get_test_bits(fdmdv, tx_bits);\r
- fdmdv_get_test_bits(fdmdv, &tx_bits[bits_per_fdmdv_frame]);\r
-\r
- PROFILE_SAMPLE(mod_start);\r
-\r
- fdmdv_mod(fdmdv, tx_fdm, tx_bits, &sync_bit);\r
- assert(sync_bit == 1);\r
- fdmdv_mod(fdmdv, &tx_fdm[FDMDV_NOM_SAMPLES_PER_FRAME], &tx_bits[bits_per_fdmdv_frame], &sync_bit);\r
- assert(sync_bit == 0);\r
- channel_in(tx_fdm, 2*FDMDV_NOM_SAMPLES_PER_FRAME);\r
-\r
- PROFILE_SAMPLE_AND_LOG(demod_start, mod_start, " mod"); \r
-\r
- for(j=0; j<2; j++) {\r
- channel_out(rx_fdm, nin);\r
- fdmdv_demod(fdmdv, rx_bits, &reliable_sync_bit[j], rx_fdm, &nin);\r
- if (reliable_sync_bit[j] == 0)\r
- memcpy(codec_bits, rx_bits, bits_per_fdmdv_frame*sizeof(int));\r
- else {\r
- memcpy(&codec_bits[bits_per_fdmdv_frame], rx_bits, bits_per_fdmdv_frame*sizeof(int));\r
- fdmdv_put_test_bits(fdmdv, &test_frame_sync, error_pattern, &bit_errors, &ntest_bits, codec_bits);\r
- fdmdv_put_test_bits(fdmdv, &test_frame_sync, error_pattern, &bit_errors, &ntest_bits, &codec_bits[bits_per_fdmdv_frame]);\r
- }\r
- }\r
- PROFILE_SAMPLE_AND_LOG2(demod_start, " demod"); \r
- PROFILE_SAMPLE_AND_LOG2(mod_start, " mod & demod"); \r
-\r
- fdmdv_get_demod_stats(fdmdv, &stats);\r
-\r
- printf("frame: %d sync: %d reliable_sync_bit: %d %d SNR: %3.2f test_frame_sync: %d\n", \r
- i, stats.sync, reliable_sync_bit[0], reliable_sync_bit[1], (double)stats.snr_est, \r
- test_frame_sync);\r
- machdep_profile_print_logged_samples();\r
- }\r
-\r
- fdmdv_destroy(fdmdv);\r
-\r
- return 0;\r
-}\r
-\r
+/*---------------------------------------------------------------------------*\
+
+ FILE........: fdmdv_profile.c
+ AUTHOR......: David Rowe
+ DATE CREATED: 18 July 2014
+
+ Profiling FDMDV modem operation on the STM32F4.
+
+\*---------------------------------------------------------------------------*/
+
+/*
+ Copyright (C) 2014 David Rowe
+
+ All rights reserved.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License version 2.1, as
+ published by the Free Software Foundation. This program is
+ distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+ License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with this program; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <math.h>
+
+#include "stm32f4xx_conf.h"
+#include "stm32f4xx.h"
+#include "gdb_stdio.h"
+#include "codec2_fdmdv.h"
+#include "dump.h"
+#include "sine.h"
+#include "machdep.h"
+
+#ifdef __EMBEDDED__
+#define printf gdb_stdio_printf
+#define fopen gdb_stdio_fopen
+#define fclose gdb_stdio_fclose
+#define fread gdb_stdio_fread
+#define fwrite gdb_stdio_fwrite
+#endif
+
+#define TEST_FRAMES 25
+#define CHANNEL_BUF_SIZE (10*FDMDV_NOM_SAMPLES_PER_FRAME)
+
+static int channel_count = 0;
+static COMP channel[CHANNEL_BUF_SIZE];
+
+static void channel_in(COMP tx_fdm[], int nout) {
+ int i;
+
+ /* add M tx samples to end of buffer */
+
+ assert((channel_count + nout) < CHANNEL_BUF_SIZE);
+ for(i=0; i<nout; i++)
+ channel[channel_count+i] = tx_fdm[i];
+ channel_count += M;
+}
+
+static void channel_out(COMP rx_fdm[], int nin) {
+ int i,j;
+
+ /* take nin samples from start of buffer */
+
+ for(i=0; i<nin; i++) {
+ rx_fdm[i] = channel[i];
+ }
+
+ /* shift buffer back */
+
+ for(i=0,j=nin; j<channel_count; i++,j++)
+ channel[i] = channel[j];
+ channel_count -= nin;
+}
+
+int main(int argc, char *argv[]) {
+ struct FDMDV *fdmdv;
+ int bits_per_fdmdv_frame, bits_per_codec_frame;
+ int *tx_bits;
+ int *rx_bits;
+ int *codec_bits;
+ COMP tx_fdm[2*FDMDV_NOM_SAMPLES_PER_FRAME];
+ COMP rx_fdm[FDMDV_NOM_SAMPLES_PER_FRAME];
+ int i, j, nin, reliable_sync_bit[2], sync_bit, bit_errors, ntest_bits, test_frame_sync;
+ short *error_pattern;
+ struct MODEM_STATS stats;
+ PROFILE_VAR(mod_start, demod_start);
+
+ machdep_profile_init ();
+ fdmdv = fdmdv_create(FDMDV_NC);
+
+ bits_per_fdmdv_frame = fdmdv_bits_per_frame(fdmdv);
+ bits_per_codec_frame = 2*fdmdv_bits_per_frame(fdmdv);
+ tx_bits = (int*)malloc(sizeof(int)*bits_per_codec_frame); assert(tx_bits != NULL);
+ rx_bits = (int*)malloc(sizeof(int)*bits_per_codec_frame); assert(rx_bits != NULL);
+ codec_bits = (int*)malloc(sizeof(int)*bits_per_codec_frame); assert(rx_bits != NULL);
+ error_pattern = (short*)malloc(fdmdv_error_pattern_size(fdmdv)*sizeof(int)); assert(error_pattern != NULL);
+
+ nin = FDMDV_NOM_SAMPLES_PER_FRAME;
+ test_frame_sync = 0;
+
+ for(i=0; i<TEST_FRAMES; i++) {
+ fdmdv_get_test_bits(fdmdv, tx_bits);
+ fdmdv_get_test_bits(fdmdv, &tx_bits[bits_per_fdmdv_frame]);
+
+ PROFILE_SAMPLE(mod_start);
+
+ fdmdv_mod(fdmdv, tx_fdm, tx_bits, &sync_bit);
+ assert(sync_bit == 1);
+ fdmdv_mod(fdmdv, &tx_fdm[FDMDV_NOM_SAMPLES_PER_FRAME], &tx_bits[bits_per_fdmdv_frame], &sync_bit);
+ assert(sync_bit == 0);
+ channel_in(tx_fdm, 2*FDMDV_NOM_SAMPLES_PER_FRAME);
+
+ PROFILE_SAMPLE_AND_LOG(demod_start, mod_start, " mod");
+
+ for(j=0; j<2; j++) {
+ channel_out(rx_fdm, nin);
+ fdmdv_demod(fdmdv, rx_bits, &reliable_sync_bit[j], rx_fdm, &nin);
+ if (reliable_sync_bit[j] == 0)
+ memcpy(codec_bits, rx_bits, bits_per_fdmdv_frame*sizeof(int));
+ else {
+ memcpy(&codec_bits[bits_per_fdmdv_frame], rx_bits, bits_per_fdmdv_frame*sizeof(int));
+ fdmdv_put_test_bits(fdmdv, &test_frame_sync, error_pattern, &bit_errors, &ntest_bits, codec_bits);
+ fdmdv_put_test_bits(fdmdv, &test_frame_sync, error_pattern, &bit_errors, &ntest_bits, &codec_bits[bits_per_fdmdv_frame]);
+ }
+ }
+ PROFILE_SAMPLE_AND_LOG2(demod_start, " demod");
+ PROFILE_SAMPLE_AND_LOG2(mod_start, " mod & demod");
+
+ fdmdv_get_demod_stats(fdmdv, &stats);
+
+ printf("frame: %d sync: %d reliable_sync_bit: %d %d SNR: %3.2f test_frame_sync: %d\n",
+ i, stats.sync, reliable_sync_bit[0], reliable_sync_bit[1], (double)stats.snr_est,
+ test_frame_sync);
+ machdep_profile_print_logged_samples();
+ }
+
+ fdmdv_destroy(fdmdv);
+
+ return 0;
+}
+
-/* ---------------------------------------------------------------------- \r
-* Copyright (C) 2010 ARM Limited. All rights reserved. \r
-* \r
-* $Date: 29. November 2010 \r
-* $Revision: V1.0.3 \r
-* \r
-* Project: CMSIS DSP Library \r
-* Title: arm_fft_bin_example_f32.c \r
-* \r
-* Description: Example code demonstrating calculation of Max energy bin of \r
-* frequency domain of input signal. \r
-* \r
-* Target Processor: Cortex-M4/Cortex-M3 \r
-*\r
-*\r
-* Version 1.0.3 2010/11/29 \r
-* Re-organized the CMSIS folders and updated documentation. \r
-* \r
-* Version 1.0.1 2010/10/05 KK \r
-* Production release and review comments incorporated. \r
-*\r
-* Version 1.0.0 2010/09/20 KK\r
-* Production release and review comments incorporated.\r
-* ------------------------------------------------------------------- */ \r
- \r
-/** \r
- * @ingroup groupExamples \r
- */ \r
- \r
-/** \r
- * @defgroup FrequencyBin Frequency Bin Example \r
- * \r
- * \par Description\r
- * \par\r
- * Demonstrates the calculation of the maximum energy bin in the frequency \r
- * domain of the input signal with the use of Complex FFT, Complex \r
- * Magnitude, and Maximum functions. \r
- * \r
- * \par Algorithm:\r
- * \par\r
- * The input test signal contains a 10 kHz signal with uniformly distributed white noise. \r
- * Calculating the FFT of the input signal will give us the maximum energy of the \r
- * bin corresponding to the input frequency of 10 kHz. \r
- * \r
- * \par Block Diagram:\r
- * \image html FFTBin.gif "Block Diagram"\r
- * \par\r
- * The figure below shows the time domain signal of 10 kHz signal with \r
- * uniformly distributed white noise, and the next figure shows the input\r
- * in the frequency domain. The bin with maximum energy corresponds to 10 kHz signal. \r
- * \par\r
- * \image html FFTBinInput.gif "Input signal in Time domain" \r
- * \image html FFTBinOutput.gif "Input signal in Frequency domain"\r
- *\r
- * \par Variables Description:\r
- * \par\r
- * \li \c testInput_f32_10khz points to the input data\r
- * \li \c testOutput points to the output data\r
- * \li \c fftSize length of FFT\r
- * \li \c ifftFlag flag for the selection of CFFT/CIFFT\r
- * \li \c doBitReverse Flag for selection of normal order or bit reversed order\r
- * \li \c refIndex reference index value at which maximum energy of bin ocuurs\r
- * \li \c testIndex calculated index value at which maximum energy of bin ocuurs\r
- * \r
- * \par CMSIS DSP Software Library Functions Used:\r
- * \par\r
- * - arm_cfft_radix4_init_f32()\r
- * - arm_cfft_radix4_f32()\r
- * - arm_cmplx_mag_f32()\r
- * - arm_max_f32()\r
- *\r
- * <b> Refer </b> \r
- * \link arm_fft_bin_example_f32.c \endlink\r
- * \r
- */ \r
- \r
- \r
-/** \example arm_fft_bin_example_f32.c \r
- */ \r
-\r
- \r
-#include "arm_math.h" \r
-#include "gdb_stdio.h"\r
-#include "machdep.h"\r
-#include "kiss_fft.h"\r
- \r
-#define TEST_LENGTH_SAMPLES 1024\r
- \r
-/* ------------------------------------------------------------------- \r
-* External Input and Output buffer Declarations for FFT Bin Example \r
-* ------------------------------------------------------------------- */ \r
-extern float32_t testInput_f32_10khz[TEST_LENGTH_SAMPLES]; \r
-static float32_t testOutput[TEST_LENGTH_SAMPLES/2]; \r
-static float32_t kiss_complex_out[TEST_LENGTH_SAMPLES]; \r
- \r
-/* ------------------------------------------------------------------ \r
-* Global variables for FFT Bin Example \r
-* ------------------------------------------------------------------- */ \r
-uint32_t fftSize = TEST_LENGTH_SAMPLES/2; \r
-uint32_t ifftFlag = 0; \r
-uint32_t doBitReverse = 1; \r
- \r
-/* Reference index at which max energy of bin ocuurs */ \r
-uint32_t refIndex = 213, testIndex = 0; \r
- \r
-/* ---------------------------------------------------------------------- \r
-* Max magnitude FFT Bin test \r
-* ------------------------------------------------------------------- */ \r
- \r
-void SystemInit(void);\r
-\r
-int main(void) \r
-{ \r
- \r
- arm_status status; \r
- arm_cfft_radix2_instance_f32 S; \r
- float32_t maxValue; \r
- unsigned int fft_start, kiss_fft_start;\r
- kiss_fft_cfg fft_fwd_cfg;\r
-\r
- SystemInit();\r
- machdep_profile_init();\r
- fft_fwd_cfg = kiss_fft_alloc(fftSize, 0, NULL, NULL);\r
- kiss_fft_start = machdep_profile_sample(); \r
- kiss_fft(fft_fwd_cfg, (kiss_fft_cpx *)testInput_f32_10khz, \r
- (kiss_fft_cpx *)kiss_complex_out);\r
- machdep_profile_sample_and_log(kiss_fft_start, " kiss_fft"); \r
- \r
- status = ARM_MATH_SUCCESS; \r
- \r
- /* Initialize the CFFT/CIFFT module */ \r
- status = arm_cfft_radix2_init_f32(&S, fftSize, ifftFlag, doBitReverse); \r
-\r
- /* Process the data through the CFFT/CIFFT module */ \r
- fft_start = machdep_profile_sample(); \r
- arm_cfft_radix2_f32(&S, testInput_f32_10khz); \r
- machdep_profile_sample_and_log(fft_start, " fft"); \r
- machdep_profile_print_logged_samples();\r
-\r
- /* Process the data through the Complex Magnitude Module for \r
- calculating the magnitude at each bin */ \r
- arm_cmplx_mag_f32(testInput_f32_10khz, testOutput,fftSize); \r
- \r
- /* Calculates maxValue and returns corresponding BIN value */ \r
- arm_max_f32(testOutput, fftSize, &maxValue, &testIndex); \r
- \r
- if(testIndex != refIndex) \r
- { \r
- status = ARM_MATH_TEST_FAILURE; \r
- } \r
- \r
- /* ---------------------------------------------------------------------- \r
- ** Loop here if the signals fail the PASS check. \r
- ** This denotes a test failure \r
- ** ------------------------------------------------------------------- */ \r
- \r
- if( status != ARM_MATH_SUCCESS) \r
- { \r
- while(1); \r
- } \r
-\r
- while(1); /* main function does not return */\r
-\r
- return 0;\r
-} \r
- \r
- /** \endlink */ \r
- \r
- \r
-/*\r
- * Dummy function to avoid compiler error\r
- */\r
-void _init() { }\r
-\r
-\r
- \r
+/* ----------------------------------------------------------------------
+* Copyright (C) 2010 ARM Limited. All rights reserved.
+*
+* $Date: 29. November 2010
+* $Revision: V1.0.3
+*
+* Project: CMSIS DSP Library
+* Title: arm_fft_bin_example_f32.c
+*
+* Description: Example code demonstrating calculation of Max energy bin of
+* frequency domain of input signal.
+*
+* Target Processor: Cortex-M4/Cortex-M3
+*
+*
+* Version 1.0.3 2010/11/29
+* Re-organized the CMSIS folders and updated documentation.
+*
+* Version 1.0.1 2010/10/05 KK
+* Production release and review comments incorporated.
+*
+* Version 1.0.0 2010/09/20 KK
+* Production release and review comments incorporated.
+* ------------------------------------------------------------------- */
+
+/**
+ * @ingroup groupExamples
+ */
+
+/**
+ * @defgroup FrequencyBin Frequency Bin Example
+ *
+ * \par Description
+ * \par
+ * Demonstrates the calculation of the maximum energy bin in the frequency
+ * domain of the input signal with the use of Complex FFT, Complex
+ * Magnitude, and Maximum functions.
+ *
+ * \par Algorithm:
+ * \par
+ * The input test signal contains a 10 kHz signal with uniformly distributed white noise.
+ * Calculating the FFT of the input signal will give us the maximum energy of the
+ * bin corresponding to the input frequency of 10 kHz.
+ *
+ * \par Block Diagram:
+ * \image html FFTBin.gif "Block Diagram"
+ * \par
+ * The figure below shows the time domain signal of 10 kHz signal with
+ * uniformly distributed white noise, and the next figure shows the input
+ * in the frequency domain. The bin with maximum energy corresponds to 10 kHz signal.
+ * \par
+ * \image html FFTBinInput.gif "Input signal in Time domain"
+ * \image html FFTBinOutput.gif "Input signal in Frequency domain"
+ *
+ * \par Variables Description:
+ * \par
+ * \li \c testInput_f32_10khz points to the input data
+ * \li \c testOutput points to the output data
+ * \li \c fftSize length of FFT
+ * \li \c ifftFlag flag for the selection of CFFT/CIFFT
+ * \li \c doBitReverse Flag for selection of normal order or bit reversed order
+ * \li \c refIndex reference index value at which maximum energy of bin ocuurs
+ * \li \c testIndex calculated index value at which maximum energy of bin ocuurs
+ *
+ * \par CMSIS DSP Software Library Functions Used:
+ * \par
+ * - arm_cfft_radix4_init_f32()
+ * - arm_cfft_radix4_f32()
+ * - arm_cmplx_mag_f32()
+ * - arm_max_f32()
+ *
+ * <b> Refer </b>
+ * \link arm_fft_bin_example_f32.c \endlink
+ *
+ */
+
+
+/** \example arm_fft_bin_example_f32.c
+ */
+
+
+#include "arm_math.h"
+#include "gdb_stdio.h"
+#include "machdep.h"
+#include "kiss_fft.h"
+
+#define TEST_LENGTH_SAMPLES 1024
+
+/* -------------------------------------------------------------------
+* External Input and Output buffer Declarations for FFT Bin Example
+* ------------------------------------------------------------------- */
+extern float32_t testInput_f32_10khz[TEST_LENGTH_SAMPLES];
+static float32_t testOutput[TEST_LENGTH_SAMPLES/2];
+static float32_t kiss_complex_out[TEST_LENGTH_SAMPLES];
+
+/* ------------------------------------------------------------------
+* Global variables for FFT Bin Example
+* ------------------------------------------------------------------- */
+uint32_t fftSize = TEST_LENGTH_SAMPLES/2;
+uint32_t ifftFlag = 0;
+uint32_t doBitReverse = 1;
+
+/* Reference index at which max energy of bin ocuurs */
+uint32_t refIndex = 213, testIndex = 0;
+
+/* ----------------------------------------------------------------------
+* Max magnitude FFT Bin test
+* ------------------------------------------------------------------- */
+
+void SystemInit(void);
+
+int main(void)
+{
+
+ arm_status status;
+ arm_cfft_radix2_instance_f32 S;
+ float32_t maxValue;
+ unsigned int fft_start, kiss_fft_start;
+ kiss_fft_cfg fft_fwd_cfg;
+
+ SystemInit();
+ machdep_profile_init();
+ fft_fwd_cfg = kiss_fft_alloc(fftSize, 0, NULL, NULL);
+ kiss_fft_start = machdep_profile_sample();
+ kiss_fft(fft_fwd_cfg, (kiss_fft_cpx *)testInput_f32_10khz,
+ (kiss_fft_cpx *)kiss_complex_out);
+ machdep_profile_sample_and_log(kiss_fft_start, " kiss_fft");
+
+ status = ARM_MATH_SUCCESS;
+
+ /* Initialize the CFFT/CIFFT module */
+ status = arm_cfft_radix2_init_f32(&S, fftSize, ifftFlag, doBitReverse);
+
+ /* Process the data through the CFFT/CIFFT module */
+ fft_start = machdep_profile_sample();
+ arm_cfft_radix2_f32(&S, testInput_f32_10khz);
+ machdep_profile_sample_and_log(fft_start, " fft");
+ machdep_profile_print_logged_samples();
+
+ /* Process the data through the Complex Magnitude Module for
+ calculating the magnitude at each bin */
+ arm_cmplx_mag_f32(testInput_f32_10khz, testOutput,fftSize);
+
+ /* Calculates maxValue and returns corresponding BIN value */
+ arm_max_f32(testOutput, fftSize, &maxValue, &testIndex);
+
+ if(testIndex != refIndex)
+ {
+ status = ARM_MATH_TEST_FAILURE;
+ }
+
+ /* ----------------------------------------------------------------------
+ ** Loop here if the signals fail the PASS check.
+ ** This denotes a test failure
+ ** ------------------------------------------------------------------- */
+
+ if( status != ARM_MATH_SUCCESS)
+ {
+ while(1);
+ }
+
+ while(1); /* main function does not return */
+
+ return 0;
+}
+
+ /** \endlink */
+
+
+/*
+ * Dummy function to avoid compiler error
+ */
+void _init() { }
+
+
+
-/*---------------------------------------------------------------------------*\\r
-\r
- FILE........: freedv_rx_profile.c\r
- AUTHOR......: David Rowe\r
- DATE CREATED: 13 August 2014\r
-\r
- Profiling freedv_rx() operation on the STM32F4.\r
-\r
-\*---------------------------------------------------------------------------*/\r
-\r
-/*\r
- Copyright (C) 2014 David Rowe\r
-\r
- All rights reserved.\r
-\r
- This program is free software; you can redistribute it and/or modify\r
- it under the terms of the GNU Lesser General Public License version 2.1, as\r
- published by the Free Software Foundation. This program is\r
- distributed in the hope that it will be useful, but WITHOUT ANY\r
- WARRANTY; without even the implied warranty of MERCHANTABILITY or\r
- FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public\r
- License for more details.\r
-\r
- You should have received a copy of the GNU Lesser General Public License\r
- along with this program; if not, see <http://www.gnu.org/licenses/>.\r
-*/\r
-\r
-#define PROFILE\r
-\r
-#include <assert.h>\r
-#include <stdio.h>\r
-#include <stdlib.h>\r
-#include <stdint.h>\r
-#include <math.h>\r
-\r
-#include "stm32f4xx_conf.h"\r
-#include "stm32f4xx.h"\r
-#include "gdb_stdio.h"\r
-#include "freedv_api.h"\r
-#include "machdep.h"\r
-#include "codec2_fdmdv.h"\r
-\r
-#ifdef __EMBEDDED__\r
-#define printf gdb_stdio_printf\r
-#define fopen gdb_stdio_fopen\r
-#define fclose gdb_stdio_fclose\r
-#define fread gdb_stdio_fread\r
-#define fwrite gdb_stdio_fwrite\r
-#define fprintf gdb_stdio_fprintf\r
-#endif\r
-\r
-#define FREEDV_NSAMPLES_16K (2*FREEDV_NSAMPLES)\r
-\r
-int main(int argc, char *argv[]) {\r
- struct freedv *f;\r
- FILE *fin, *fout, *ftotal;\r
- int frame, nin_16k, nin, i, nout = 0;\r
- int n_samples, n_samples_16k;\r
- int sync;\r
- float snr_est;\r
-\r
- PROFILE_VAR(fdmdv_16_to_8_start, freedv_rx_start, fdmdv_8_to_16_start);\r
-\r
- machdep_profile_init();\r
-\r
- f = freedv_open(FREEDV_MODE_1600);\r
- n_samples = freedv_get_n_speech_samples(f);\r
- n_samples_16k = 2*n_samples;\r
-\r
- short adc16k[FDMDV_OS_TAPS_16K+n_samples_16k];\r
- short dac16k[n_samples_16k];\r
- short adc8k[n_samples];\r
- short dac8k[FDMDV_OS_TAPS_8K+n_samples];\r
-\r
- // Receive ---------------------------------------------------------------------\r
-\r
- frame = 0;\r
-\r
- fin = fopen("mod_16k.raw", "rb");\r
- if (fin == NULL) {\r
- printf("Error opening input file\n");\r
- exit(1);\r
- }\r
-\r
- fout = fopen("speechout_16k.raw", "wb");\r
- if (fout == NULL) {\r
- printf("Error opening output file\n");\r
- exit(1);\r
- }\r
-\r
- ftotal = fopen("total.txt", "wt");\r
- assert(ftotal != NULL);\r
-\r
- /* clear filter memories */\r
-\r
- for(i=0; i<FDMDV_OS_TAPS_16K; i++)\r
- adc16k[i] = 0.0;\r
- for(i=0; i<FDMDV_OS_TAPS_8K; i++)\r
- dac8k[i] = 0.0;\r
- \r
- nin = freedv_nin(f);\r
- nin_16k = 2*nin;\r
- nout = nin;\r
- while (fread(&adc16k[FDMDV_OS_TAPS_16K], sizeof(short), nin_16k, fin) == nin_16k) {\r
-\r
- PROFILE_SAMPLE(fdmdv_16_to_8_start);\r
-\r
- fdmdv_16_to_8_short(adc8k, &adc16k[FDMDV_OS_TAPS_16K], nin);\r
-\r
- PROFILE_SAMPLE_AND_LOG(freedv_rx_start, fdmdv_16_to_8_start, " fdmdv_16_to_8");\r
-\r
- nout = freedv_rx(f, &dac8k[FDMDV_OS_TAPS_8K], adc8k);\r
- nin = freedv_nin(f); nin_16k = 2*nin;\r
-\r
- PROFILE_SAMPLE_AND_LOG(fdmdv_8_to_16_start, freedv_rx_start, " freedv_rx"); \r
-\r
- fdmdv_8_to_16_short(dac16k, &dac8k[FDMDV_OS_TAPS_8K], nout); \r
-\r
- PROFILE_SAMPLE_AND_LOG2(fdmdv_8_to_16_start, " fdmdv_8_to_16");\r
-\r
- fprintf(ftotal, "%d\n", machdep_profile_sample() - fdmdv_16_to_8_start);\r
- machdep_profile_print_logged_samples();\r
-\r
- fwrite(dac16k, sizeof(short), 2*nout, fout);\r
- freedv_get_modem_stats(f, &sync, &snr_est);\r
- printf("frame: %d nin_16k: %d sync: %d SNR: %3.2f \n", \r
- ++frame, nin_16k, sync, (double)snr_est);\r
- }\r
-\r
- fclose(fin);\r
- fclose(fout);\r
- fclose(ftotal);\r
-\r
- return 0;\r
-}\r
-\r
+/*---------------------------------------------------------------------------*\
+
+ FILE........: freedv_rx_profile.c
+ AUTHOR......: David Rowe
+ DATE CREATED: 13 August 2014
+
+ Profiling freedv_rx() operation on the STM32F4.
+
+\*---------------------------------------------------------------------------*/
+
+/*
+ Copyright (C) 2014 David Rowe
+
+ All rights reserved.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License version 2.1, as
+ published by the Free Software Foundation. This program is
+ distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+ License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with this program; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#define PROFILE
+
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <math.h>
+
+#include "stm32f4xx_conf.h"
+#include "stm32f4xx.h"
+#include "gdb_stdio.h"
+#include "freedv_api.h"
+#include "machdep.h"
+#include "codec2_fdmdv.h"
+
+#ifdef __EMBEDDED__
+#define printf gdb_stdio_printf
+#define fopen gdb_stdio_fopen
+#define fclose gdb_stdio_fclose
+#define fread gdb_stdio_fread
+#define fwrite gdb_stdio_fwrite
+#define fprintf gdb_stdio_fprintf
+#endif
+
+#define FREEDV_NSAMPLES_16K (2*FREEDV_NSAMPLES)
+
+int main(int argc, char *argv[]) {
+ struct freedv *f;
+ FILE *fin, *fout, *ftotal;
+ int frame, nin_16k, nin, i, nout = 0;
+ int n_samples, n_samples_16k;
+ int sync;
+ float snr_est;
+
+ PROFILE_VAR(fdmdv_16_to_8_start, freedv_rx_start, fdmdv_8_to_16_start);
+
+ machdep_profile_init();
+
+ f = freedv_open(FREEDV_MODE_1600);
+ n_samples = freedv_get_n_speech_samples(f);
+ n_samples_16k = 2*n_samples;
+
+ short adc16k[FDMDV_OS_TAPS_16K+n_samples_16k];
+ short dac16k[n_samples_16k];
+ short adc8k[n_samples];
+ short dac8k[FDMDV_OS_TAPS_8K+n_samples];
+
+ // Receive ---------------------------------------------------------------------
+
+ frame = 0;
+
+ fin = fopen("mod_16k.raw", "rb");
+ if (fin == NULL) {
+ printf("Error opening input file\n");
+ exit(1);
+ }
+
+ fout = fopen("speechout_16k.raw", "wb");
+ if (fout == NULL) {
+ printf("Error opening output file\n");
+ exit(1);
+ }
+
+ ftotal = fopen("total.txt", "wt");
+ assert(ftotal != NULL);
+
+ /* clear filter memories */
+
+ for(i=0; i<FDMDV_OS_TAPS_16K; i++)
+ adc16k[i] = 0.0;
+ for(i=0; i<FDMDV_OS_TAPS_8K; i++)
+ dac8k[i] = 0.0;
+
+ nin = freedv_nin(f);
+ nin_16k = 2*nin;
+ nout = nin;
+ while (fread(&adc16k[FDMDV_OS_TAPS_16K], sizeof(short), nin_16k, fin) == nin_16k) {
+
+ PROFILE_SAMPLE(fdmdv_16_to_8_start);
+
+ fdmdv_16_to_8_short(adc8k, &adc16k[FDMDV_OS_TAPS_16K], nin);
+
+ PROFILE_SAMPLE_AND_LOG(freedv_rx_start, fdmdv_16_to_8_start, " fdmdv_16_to_8");
+
+ nout = freedv_rx(f, &dac8k[FDMDV_OS_TAPS_8K], adc8k);
+ nin = freedv_nin(f); nin_16k = 2*nin;
+
+ PROFILE_SAMPLE_AND_LOG(fdmdv_8_to_16_start, freedv_rx_start, " freedv_rx");
+
+ fdmdv_8_to_16_short(dac16k, &dac8k[FDMDV_OS_TAPS_8K], nout);
+
+ PROFILE_SAMPLE_AND_LOG2(fdmdv_8_to_16_start, " fdmdv_8_to_16");
+
+ fprintf(ftotal, "%d\n", machdep_profile_sample() - fdmdv_16_to_8_start);
+ machdep_profile_print_logged_samples();
+
+ fwrite(dac16k, sizeof(short), 2*nout, fout);
+ freedv_get_modem_stats(f, &sync, &snr_est);
+ printf("frame: %d nin_16k: %d sync: %d SNR: %3.2f \n",
+ ++frame, nin_16k, sync, (double)snr_est);
+ }
+
+ fclose(fin);
+ fclose(fout);
+ fclose(ftotal);
+
+ return 0;
+}
+
-/*---------------------------------------------------------------------------*\\r
-\r
- FILE........: freedv_tx_profile.c\r
- AUTHOR......: David Rowe\r
- DATE CREATED: 13 August 2014\r
-\r
- Profiling freedv_tx() operation on the STM32F4.\r
-\r
-\*---------------------------------------------------------------------------*/\r
-\r
-/*\r
- Copyright (C) 2014 David Rowe\r
-\r
- All rights reserved.\r
-\r
- This program is free software; you can redistribute it and/or modify\r
- it under the terms of the GNU Lesser General Public License version 2.1, as\r
- published by the Free Software Foundation. This program is\r
- distributed in the hope that it will be useful, but WITHOUT ANY\r
- WARRANTY; without even the implied warranty of MERCHANTABILITY or\r
- FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public\r
- License for more details.\r
-\r
- You should have received a copy of the GNU Lesser General Public License\r
- along with this program; if not, see <http://www.gnu.org/licenses/>.\r
-*/\r
-\r
-#include <stdio.h>\r
-#include <stdlib.h>\r
-#include <stdint.h>\r
-#include <math.h>\r
-\r
-#include "stm32f4xx_conf.h"\r
-#include "stm32f4xx.h"\r
-#include "gdb_stdio.h"\r
-#include "freedv_api.h"\r
-#include "machdep.h"\r
-\r
-#ifdef __EMBEDDED__\r
-#define printf gdb_stdio_printf\r
-#define fopen gdb_stdio_fopen\r
-#define fclose gdb_stdio_fclose\r
-#define fread gdb_stdio_fread\r
-#define fwrite gdb_stdio_fwrite\r
-#endif\r
-\r
-int main(int argc, char *argv[]) {\r
- struct freedv *f;\r
- FILE *fin, *fout;\r
- int frame, n_samples;\r
- PROFILE_VAR(freedv_start);\r
-\r
- machdep_profile_init();\r
-\r
- f = freedv_open(FREEDV_MODE_1600);\r
- n_samples = freedv_get_n_speech_samples(f);\r
- short inbuf[n_samples], outbuf[n_samples];\r
-\r
- // Transmit ---------------------------------------------------------------------\r
-\r
- fin = fopen("stm_in.raw", "rb");\r
- if (fin == NULL) {\r
- printf("Error opening input file\n");\r
- exit(1);\r
- }\r
-\r
- fout = fopen("mod.raw", "wb");\r
- if (fout == NULL) {\r
- printf("Error opening output file\n");\r
- exit(1);\r
- }\r
-\r
- frame = 0;\r
-\r
- while (fread(inbuf, sizeof(short), n_samples, fin) == n_samples) {\r
- PROFILE_SAMPLE(freedv_start);\r
- freedv_tx(f, outbuf, inbuf);\r
- PROFILE_SAMPLE_AND_LOG2(freedv_start, " freedv_tx"); \r
- \r
- fwrite(outbuf, sizeof(short), n_samples, fout);\r
- printf("frame: %d\n", ++frame);\r
- machdep_profile_print_logged_samples();\r
- }\r
-\r
- fclose(fin);\r
- fclose(fout);\r
-\r
- return 0;\r
-}\r
-\r
+/*---------------------------------------------------------------------------*\
+
+ FILE........: freedv_tx_profile.c
+ AUTHOR......: David Rowe
+ DATE CREATED: 13 August 2014
+
+ Profiling freedv_tx() operation on the STM32F4.
+
+\*---------------------------------------------------------------------------*/
+
+/*
+ Copyright (C) 2014 David Rowe
+
+ All rights reserved.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License version 2.1, as
+ published by the Free Software Foundation. This program is
+ distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+ License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with this program; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <math.h>
+
+#include "stm32f4xx_conf.h"
+#include "stm32f4xx.h"
+#include "gdb_stdio.h"
+#include "freedv_api.h"
+#include "machdep.h"
+
+#ifdef __EMBEDDED__
+#define printf gdb_stdio_printf
+#define fopen gdb_stdio_fopen
+#define fclose gdb_stdio_fclose
+#define fread gdb_stdio_fread
+#define fwrite gdb_stdio_fwrite
+#endif
+
+int main(int argc, char *argv[]) {
+ struct freedv *f;
+ FILE *fin, *fout;
+ int frame, n_samples;
+ PROFILE_VAR(freedv_start);
+
+ machdep_profile_init();
+
+ f = freedv_open(FREEDV_MODE_1600);
+ n_samples = freedv_get_n_speech_samples(f);
+ short inbuf[n_samples], outbuf[n_samples];
+
+ // Transmit ---------------------------------------------------------------------
+
+ fin = fopen("stm_in.raw", "rb");
+ if (fin == NULL) {
+ printf("Error opening input file\n");
+ exit(1);
+ }
+
+ fout = fopen("mod.raw", "wb");
+ if (fout == NULL) {
+ printf("Error opening output file\n");
+ exit(1);
+ }
+
+ frame = 0;
+
+ while (fread(inbuf, sizeof(short), n_samples, fin) == n_samples) {
+ PROFILE_SAMPLE(freedv_start);
+ freedv_tx(f, outbuf, inbuf);
+ PROFILE_SAMPLE_AND_LOG2(freedv_start, " freedv_tx");
+
+ fwrite(outbuf, sizeof(short), n_samples, fout);
+ printf("frame: %d\n", ++frame);
+ machdep_profile_print_logged_samples();
+ }
+
+ fclose(fin);
+ fclose(fout);
+
+ return 0;
+}
+
-/*---------------------------------------------------------------------------*\\r
-\r
- FILE........: power_ut.c\r
- AUTHOR......: David Rowe\r
- DATE CREATED: 30 May 2014\r
-\r
- Runs Codec 2, ADC, and DAC, to fully exercise STM32C so we can a feel for\r
- run-time power consumption for SM1000 and hence dimension regulators.\r
-\r
-\*---------------------------------------------------------------------------*/\r
-\r
-/*\r
- Copyright (C) 2014 David Rowe\r
-\r
- All rights reserved.\r
-\r
- This program is free software; you can redistribute it and/or modify\r
- it under the terms of the GNU Lesser General Public License version 2.1, as\r
- published by the Free Software Foundation. This program is\r
- distributed in the hope that it will be useful, but WITHOUT ANY\r
- WARRANTY; without even the implied warranty of MERCHANTABILITY or\r
- FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public\r
- License for more details.\r
-\r
- You should have received a copy of the GNU Lesser General Public License\r
- along with this program; if not, see <http://www.gnu.org/licenses/>.\r
-*/\r
-\r
-#include <stdio.h>\r
-#include <stdlib.h>\r
-#include <stdint.h>\r
-#include <math.h>\r
-\r
-#include "stm32f4xx_conf.h"\r
-#include "stm32f4xx.h"\r
-#include "stm32f4_adc.h"\r
-#include "stm32f4_dac.h"\r
-#include "gdb_stdio.h"\r
-#include "codec2.h"\r
-#include "dump.h"\r
-#include "sine.h"\r
-#include "machdep.h"\r
-\r
-#ifdef __EMBEDDED__\r
-#define printf gdb_stdio_printf\r
-#define fopen gdb_stdio_fopen\r
-#define fclose gdb_stdio_fclose\r
-#define fread gdb_stdio_fread\r
-#define fwrite gdb_stdio_fwrite\r
-#endif\r
-\r
-#define SPEED_TEST_SAMPLES 24000\r
-\r
-/* modification of test used to measure codec2 execuation speed. We read/write ADC/DAC\r
- but dont do anything with the samples, as they are at 16 kHz and codec needs 8 kHz. Just\r
- trying to exercise everything to get a feel for power consumption */\r
-\r
-static void c2speedtest(int mode, char inputfile[])\r
-{\r
- struct CODEC2 *codec2;\r
- short *inbuf, *outbuf, *pinbuf, *dummy_buf;\r
- unsigned char *bits;\r
- int nsam, nbit, nframes;\r
- FILE *fin;\r
- int f, nread;\r
-\r
- codec2 = codec2_create(mode);\r
- nsam = codec2_samples_per_frame(codec2);\r
- nframes = SPEED_TEST_SAMPLES/nsam;\r
- outbuf = (short*)malloc(nsam*sizeof(short));\r
- inbuf = (short*)malloc(SPEED_TEST_SAMPLES*sizeof(short));\r
- nbit = codec2_bits_per_frame(codec2);\r
- bits = (unsigned char*)malloc(nbit*sizeof(char));\r
- dummy_buf = (short*)malloc(2*nsam*sizeof(short));\r
-\r
- fin = fopen(inputfile, "rb");\r
- if (fin == NULL) {\r
- printf("Error opening input file: %s\nTerminating....\n",inputfile);\r
- exit(1);\r
- }\r
-\r
- printf("reading samples ....\n");\r
- nread = fread(inbuf, sizeof(short), SPEED_TEST_SAMPLES, fin);\r
- if (nread != SPEED_TEST_SAMPLES) {\r
- printf("error reading %s, %d samples reqd, %d read\n", \r
- inputfile, SPEED_TEST_SAMPLES, nread);\r
- }\r
- fclose(fin);\r
- \r
- pinbuf = inbuf;\r
- for(f=0; f<nframes; f++) {\r
- //printf("read ADC\n");\r
- while(adc1_read(dummy_buf, nsam*2) == -1); /* runs at Fs = 16kHz */\r
-\r
- //printf("Codec 2 enc\n");\r
- GPIOD->ODR = (1 << 13);\r
- codec2_encode(codec2, bits, pinbuf);\r
- pinbuf += nsam;\r
- GPIOD->ODR &= ~(1 << 13);\r
- //printf("Codec 2 dec\n");\r
- codec2_decode(codec2, outbuf, bits);\r
- \r
- //printf("write to DAC\n");\r
- while(dac1_write(dummy_buf, nsam*2) == -1); /* runs at Fs = 16kHz */\r
- //printf(".");\r
- }\r
-\r
- free(inbuf);\r
- free(outbuf);\r
- free(bits);\r
- codec2_destroy(codec2);\r
-}\r
-\r
-void gpio_init() {\r
- RCC->AHB1ENR |= RCC_AHB1ENR_GPIODEN; // enable the clock to GPIOD \r
- GPIOD->MODER = (1 << 26); // set pin 13 to be general \r
- // purpose output\r
-}\r
-\r
-int main(int argc, char *argv[]) {\r
- SystemInit();\r
- gpio_init();\r
- machdep_profile_init ();\r
- adc_open(4*DAC_BUF_SZ);\r
- dac_open(4*DAC_BUF_SZ);\r
-\r
- printf("Starting power_ut\n");\r
-\r
- c2speedtest(CODEC2_MODE_1600, "stm_in.raw");\r
-\r
- printf("Finished\n");\r
-\r
- return 0;\r
-}\r
-\r
+/*---------------------------------------------------------------------------*\
+
+ FILE........: power_ut.c
+ AUTHOR......: David Rowe
+ DATE CREATED: 30 May 2014
+
+ Runs Codec 2, ADC, and DAC, to fully exercise STM32C so we can a feel for
+ run-time power consumption for SM1000 and hence dimension regulators.
+
+\*---------------------------------------------------------------------------*/
+
+/*
+ Copyright (C) 2014 David Rowe
+
+ All rights reserved.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License version 2.1, as
+ published by the Free Software Foundation. This program is
+ distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+ License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with this program; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <math.h>
+
+#include "stm32f4xx_conf.h"
+#include "stm32f4xx.h"
+#include "stm32f4_adc.h"
+#include "stm32f4_dac.h"
+#include "gdb_stdio.h"
+#include "codec2.h"
+#include "dump.h"
+#include "sine.h"
+#include "machdep.h"
+
+#ifdef __EMBEDDED__
+#define printf gdb_stdio_printf
+#define fopen gdb_stdio_fopen
+#define fclose gdb_stdio_fclose
+#define fread gdb_stdio_fread
+#define fwrite gdb_stdio_fwrite
+#endif
+
+#define SPEED_TEST_SAMPLES 24000
+
+/* modification of test used to measure codec2 execuation speed. We read/write ADC/DAC
+ but dont do anything with the samples, as they are at 16 kHz and codec needs 8 kHz. Just
+ trying to exercise everything to get a feel for power consumption */
+
+static void c2speedtest(int mode, char inputfile[])
+{
+ struct CODEC2 *codec2;
+ short *inbuf, *outbuf, *pinbuf, *dummy_buf;
+ unsigned char *bits;
+ int nsam, nbit, nframes;
+ FILE *fin;
+ int f, nread;
+
+ codec2 = codec2_create(mode);
+ nsam = codec2_samples_per_frame(codec2);
+ nframes = SPEED_TEST_SAMPLES/nsam;
+ outbuf = (short*)malloc(nsam*sizeof(short));
+ inbuf = (short*)malloc(SPEED_TEST_SAMPLES*sizeof(short));
+ nbit = codec2_bits_per_frame(codec2);
+ bits = (unsigned char*)malloc(nbit*sizeof(char));
+ dummy_buf = (short*)malloc(2*nsam*sizeof(short));
+
+ fin = fopen(inputfile, "rb");
+ if (fin == NULL) {
+ printf("Error opening input file: %s\nTerminating....\n",inputfile);
+ exit(1);
+ }
+
+ printf("reading samples ....\n");
+ nread = fread(inbuf, sizeof(short), SPEED_TEST_SAMPLES, fin);
+ if (nread != SPEED_TEST_SAMPLES) {
+ printf("error reading %s, %d samples reqd, %d read\n",
+ inputfile, SPEED_TEST_SAMPLES, nread);
+ }
+ fclose(fin);
+
+ pinbuf = inbuf;
+ for(f=0; f<nframes; f++) {
+ //printf("read ADC\n");
+ while(adc1_read(dummy_buf, nsam*2) == -1); /* runs at Fs = 16kHz */
+
+ //printf("Codec 2 enc\n");
+ GPIOD->ODR = (1 << 13);
+ codec2_encode(codec2, bits, pinbuf);
+ pinbuf += nsam;
+ GPIOD->ODR &= ~(1 << 13);
+ //printf("Codec 2 dec\n");
+ codec2_decode(codec2, outbuf, bits);
+
+ //printf("write to DAC\n");
+ while(dac1_write(dummy_buf, nsam*2) == -1); /* runs at Fs = 16kHz */
+ //printf(".");
+ }
+
+ free(inbuf);
+ free(outbuf);
+ free(bits);
+ codec2_destroy(codec2);
+}
+
+void gpio_init() {
+ RCC->AHB1ENR |= RCC_AHB1ENR_GPIODEN; // enable the clock to GPIOD
+ GPIOD->MODER = (1 << 26); // set pin 13 to be general
+ // purpose output
+}
+
+int main(int argc, char *argv[]) {
+ SystemInit();
+ gpio_init();
+ machdep_profile_init ();
+ adc_open(4*DAC_BUF_SZ);
+ dac_open(4*DAC_BUF_SZ);
+
+ printf("Starting power_ut\n");
+
+ c2speedtest(CODEC2_MODE_1600, "stm_in.raw");
+
+ printf("Finished\n");
+
+ return 0;
+}
+
-/*---------------------------------------------------------------------------*\\r
-\r
- FILE........: sm1000_leds_switches_ut.c\r
- AUTHOR......: David Rowe\r
- DATE CREATED: August 5 2014\r
-\r
- Unit Test program for the SM1000 switches and LEDs driver.\r
-\r
-\*---------------------------------------------------------------------------*/\r
-\r
-/*\r
- Copyright (C) 2014 David Rowe\r
-\r
- All rights reserved.\r
-\r
- This program is free software; you can redistribute it and/or modify\r
- it under the terms of the GNU Lesser General Public License version 2.1, as\r
- published by the Free Software Foundation. This program is\r
- distributed in the hope that it will be useful, but WITHOUT ANY\r
- WARRANTY; without even the implied warranty of MERCHANTABILITY or\r
- FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public\r
- License for more details.\r
-\r
- You should have received a copy of the GNU Lesser General Public License\r
- along with this program; if not, see <http://www.gnu.org/licenses/>.\r
-*/\r
-\r
-#include <assert.h>\r
-#include "sm1000_leds_switches.h"\r
-\r
-int main(void) {\r
- sm1000_leds_switches_init();\r
-\r
- while(1) {\r
- led_pwr(switch_select());\r
- led_ptt(switch_ptt());\r
- led_rt(switch_back());\r
- led_err(!switch_back());\r
- }\r
-}\r
-\r
+/*---------------------------------------------------------------------------*\
+
+ FILE........: sm1000_leds_switches_ut.c
+ AUTHOR......: David Rowe
+ DATE CREATED: August 5 2014
+
+ Unit Test program for the SM1000 switches and LEDs driver.
+
+\*---------------------------------------------------------------------------*/
+
+/*
+ Copyright (C) 2014 David Rowe
+
+ All rights reserved.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License version 2.1, as
+ published by the Free Software Foundation. This program is
+ distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+ License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with this program; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <assert.h>
+#include "sm1000_leds_switches.h"
+
+int main(void) {
+ sm1000_leds_switches_init();
+
+ while(1) {
+ led_pwr(switch_select());
+ led_ptt(switch_ptt());
+ led_rt(switch_back());
+ led_err(!switch_back());
+ }
+}
+
-/**\r
- ******************************************************************************\r
- * @file startup_stm32f4xx.s\r
- * @author MCD Application Team\r
- * @version V1.0.0\r
- * @date 30-September-2011\r
- * @brief STM32F4xx Devices vector table for Atollic TrueSTUDIO toolchain.\r
- * This module performs:\r
- * - Set the initial SP\r
- * - Set the initial PC == Reset_Handler,\r
- * - Set the vector table entries with the exceptions ISR address\r
- * - Configure the clock system and the external SRAM mounted on\r
- * STM324xG-EVAL board to be used as data memory (optional,\r
- * to be enabled by user)\r
- * - Branches to main in the C library (which eventually\r
- * calls main()).\r
- * After Reset the Cortex-M4 processor is in Thread mode,\r
- * priority is Privileged, and the Stack is set to Main.\r
- ******************************************************************************\r
- * @attention\r
- *\r
- * THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS\r
- * WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE\r
- * TIME. AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY\r
- * DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING\r
- * FROM THE CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE\r
- * CODING INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.\r
- *\r
- * <h2><center>© COPYRIGHT 2011 STMicroelectronics</center></h2>\r
- ******************************************************************************\r
- */\r
-\r
- .syntax unified\r
- .cpu cortex-m3\r
- .fpu softvfp\r
- .thumb\r
-\r
-.global g_pfnVectors\r
-.global Default_Handler\r
-\r
-/* start address for the initialization values of the .data section.\r
-defined in linker script */\r
-.word _sidata\r
-/* start address for the .data section. defined in linker script */\r
-.word _sdata\r
-/* end address for the .data section. defined in linker script */\r
-.word _edata\r
-/* start address for the .bss section. defined in linker script */\r
-.word _sbss\r
-/* end address for the .bss section. defined in linker script */\r
-.word _ebss\r
-/* stack used for SystemInit_ExtMemCtl; always internal RAM used */\r
-\r
-/**\r
- * @brief This is the code that gets called when the processor first\r
- * starts execution following a reset event. Only the absolutely\r
- * necessary set is performed, after which the application\r
- * supplied main() routine is called.\r
- * @param None\r
- * @retval : None\r
-*/\r
-\r
- .section .text.Reset_Handler\r
- .weak Reset_Handler\r
- .type Reset_Handler, %function\r
-Reset_Handler:\r
-\r
-/* Copy the data segment initializers from flash to SRAM */\r
- movs r1, #0\r
- b LoopCopyDataInit\r
-\r
-CopyDataInit:\r
- ldr r3, =_sidata\r
- ldr r3, [r3, r1]\r
- str r3, [r0, r1]\r
- adds r1, r1, #4\r
-\r
-LoopCopyDataInit:\r
- ldr r0, =_sdata\r
- ldr r3, =_edata\r
- adds r2, r0, r1\r
- cmp r2, r3\r
- bcc CopyDataInit\r
- ldr r2, =_sbss\r
- b LoopFillZerobss\r
-/* Zero fill the bss segment. */\r
-FillZerobss:\r
- movs r3, #0\r
- str r3, [r2], #4\r
-\r
-LoopFillZerobss:\r
- ldr r3, = _ebss\r
- cmp r2, r3\r
- bcc FillZerobss\r
-\r
-/* Call the clock system intitialization function.*/\r
- bl SystemInit\r
-/* Call static constructors */\r
- bl __libc_init_array\r
-/* Call the application's entry point.*/\r
- bl main\r
- bx lr\r
-.size Reset_Handler, .-Reset_Handler\r
-\r
-/**\r
- * @brief This is the code that gets called when the processor receives an\r
- * unexpected interrupt. This simply enters an infinite loop, preserving\r
- * the system state for examination by a debugger.\r
- * @param None\r
- * @retval None\r
-*/\r
- .section .text.Default_Handler,"ax",%progbits\r
-Default_Handler:\r
-Infinite_Loop:\r
- b Infinite_Loop\r
- .size Default_Handler, .-Default_Handler\r
-/******************************************************************************\r
-*\r
-* The minimal vector table for a Cortex M3. Note that the proper constructs\r
-* must be placed on this to ensure that it ends up at physical address\r
-* 0x0000.0000.\r
-*\r
-*******************************************************************************/\r
- .section .isr_vector,"a",%progbits\r
- .type g_pfnVectors, %object\r
- .size g_pfnVectors, .-g_pfnVectors\r
-\r
-\r
-g_pfnVectors:\r
- .word _estack\r
- .word Reset_Handler\r
- .word NMI_Handler\r
- .word HardFault_Handler\r
- .word MemManage_Handler\r
- .word BusFault_Handler\r
- .word UsageFault_Handler\r
- .word 0\r
- .word 0\r
- .word 0\r
- .word 0\r
- .word SVC_Handler\r
- .word DebugMon_Handler\r
- .word 0\r
- .word PendSV_Handler\r
- .word SysTick_Handler\r
-\r
- /* External Interrupts */\r
- .word WWDG_IRQHandler /* Window WatchDog */\r
- .word PVD_IRQHandler /* PVD through EXTI Line detection */\r
- .word TAMP_STAMP_IRQHandler /* Tamper and TimeStamps through the EXTI line */\r
- .word RTC_WKUP_IRQHandler /* RTC Wakeup through the EXTI line */\r
- .word FLASH_IRQHandler /* FLASH */\r
- .word RCC_IRQHandler /* RCC */\r
- .word EXTI0_IRQHandler /* EXTI Line0 */\r
- .word EXTI1_IRQHandler /* EXTI Line1 */\r
- .word EXTI2_IRQHandler /* EXTI Line2 */\r
- .word EXTI3_IRQHandler /* EXTI Line3 */\r
- .word EXTI4_IRQHandler /* EXTI Line4 */\r
- .word DMA1_Stream0_IRQHandler /* DMA1 Stream 0 */\r
- .word DMA1_Stream1_IRQHandler /* DMA1 Stream 1 */\r
- .word DMA1_Stream2_IRQHandler /* DMA1 Stream 2 */\r
- .word DMA1_Stream3_IRQHandler /* DMA1 Stream 3 */\r
- .word DMA1_Stream4_IRQHandler /* DMA1 Stream 4 */\r
- .word DMA1_Stream5_IRQHandler /* DMA1 Stream 5 */\r
- .word DMA1_Stream6_IRQHandler /* DMA1 Stream 6 */\r
- .word ADC_IRQHandler /* ADC1, ADC2 and ADC3s */\r
- .word CAN1_TX_IRQHandler /* CAN1 TX */\r
- .word CAN1_RX0_IRQHandler /* CAN1 RX0 */\r
- .word CAN1_RX1_IRQHandler /* CAN1 RX1 */\r
- .word CAN1_SCE_IRQHandler /* CAN1 SCE */\r
- .word EXTI9_5_IRQHandler /* External Line[9:5]s */\r
- .word TIM1_BRK_TIM9_IRQHandler /* TIM1 Break and TIM9 */\r
- .word TIM1_UP_TIM10_IRQHandler /* TIM1 Update and TIM10 */\r
- .word TIM1_TRG_COM_TIM11_IRQHandler /* TIM1 Trigger and Commutation and TIM11 */\r
- .word TIM1_CC_IRQHandler /* TIM1 Capture Compare */\r
- .word TIM2_IRQHandler /* TIM2 */\r
- .word TIM3_IRQHandler /* TIM3 */\r
- .word TIM4_IRQHandler /* TIM4 */\r
- .word I2C1_EV_IRQHandler /* I2C1 Event */\r
- .word I2C1_ER_IRQHandler /* I2C1 Error */\r
- .word I2C2_EV_IRQHandler /* I2C2 Event */\r
- .word I2C2_ER_IRQHandler /* I2C2 Error */\r
- .word SPI1_IRQHandler /* SPI1 */\r
- .word SPI2_IRQHandler /* SPI2 */\r
- .word USART1_IRQHandler /* USART1 */\r
- .word USART2_IRQHandler /* USART2 */\r
- .word USART3_IRQHandler /* USART3 */\r
- .word EXTI15_10_IRQHandler /* External Line[15:10]s */\r
- .word RTC_Alarm_IRQHandler /* RTC Alarm (A and B) through EXTI Line */\r
- .word OTG_FS_WKUP_IRQHandler /* USB OTG FS Wakeup through EXTI line */\r
- .word TIM8_BRK_TIM12_IRQHandler /* TIM8 Break and TIM12 */\r
- .word TIM8_UP_TIM13_IRQHandler /* TIM8 Update and TIM13 */\r
- .word TIM8_TRG_COM_TIM14_IRQHandler /* TIM8 Trigger and Commutation and TIM14 */\r
- .word TIM8_CC_IRQHandler /* TIM8 Capture Compare */\r
- .word DMA1_Stream7_IRQHandler /* DMA1 Stream7 */\r
- .word FSMC_IRQHandler /* FSMC */\r
- .word SDIO_IRQHandler /* SDIO */\r
- .word TIM5_IRQHandler /* TIM5 */\r
- .word SPI3_IRQHandler /* SPI3 */\r
- .word UART4_IRQHandler /* UART4 */\r
- .word UART5_IRQHandler /* UART5 */\r
- .word TIM6_DAC_IRQHandler /* TIM6 and DAC1&2 underrun errors */\r
- .word TIM7_IRQHandler /* TIM7 */\r
- .word DMA2_Stream0_IRQHandler /* DMA2 Stream 0 */\r
- .word DMA2_Stream1_IRQHandler /* DMA2 Stream 1 */\r
- .word DMA2_Stream2_IRQHandler /* DMA2 Stream 2 */\r
- .word DMA2_Stream3_IRQHandler /* DMA2 Stream 3 */\r
- .word DMA2_Stream4_IRQHandler /* DMA2 Stream 4 */\r
- .word ETH_IRQHandler /* Ethernet */\r
- .word ETH_WKUP_IRQHandler /* Ethernet Wakeup through EXTI line */\r
- .word CAN2_TX_IRQHandler /* CAN2 TX */\r
- .word CAN2_RX0_IRQHandler /* CAN2 RX0 */\r
- .word CAN2_RX1_IRQHandler /* CAN2 RX1 */\r
- .word CAN2_SCE_IRQHandler /* CAN2 SCE */\r
- .word OTG_FS_IRQHandler /* USB OTG FS */\r
- .word DMA2_Stream5_IRQHandler /* DMA2 Stream 5 */\r
- .word DMA2_Stream6_IRQHandler /* DMA2 Stream 6 */\r
- .word DMA2_Stream7_IRQHandler /* DMA2 Stream 7 */\r
- .word USART6_IRQHandler /* USART6 */\r
- .word I2C3_EV_IRQHandler /* I2C3 event */\r
- .word I2C3_ER_IRQHandler /* I2C3 error */\r
- .word OTG_HS_EP1_OUT_IRQHandler /* USB OTG HS End Point 1 Out */\r
- .word OTG_HS_EP1_IN_IRQHandler /* USB OTG HS End Point 1 In */\r
- .word OTG_HS_WKUP_IRQHandler /* USB OTG HS Wakeup through EXTI */\r
- .word OTG_HS_IRQHandler /* USB OTG HS */\r
- .word DCMI_IRQHandler /* DCMI */\r
- .word CRYP_IRQHandler /* CRYP crypto */\r
- .word HASH_RNG_IRQHandler /* Hash and Rng */\r
- .word FPU_IRQHandler /* FPU */\r
-\r
-\r
-/*******************************************************************************\r
-*\r
-* Provide weak aliases for each Exception handler to the Default_Handler.\r
-* As they are weak aliases, any function with the same name will override\r
-* this definition.\r
-*\r
-*******************************************************************************/\r
- .weak NMI_Handler\r
- .thumb_set NMI_Handler,Default_Handler\r
-\r
- .weak HardFault_Handler\r
- .thumb_set HardFault_Handler,Default_Handler\r
-\r
- .weak MemManage_Handler\r
- .thumb_set MemManage_Handler,Default_Handler\r
-\r
- .weak BusFault_Handler\r
- .thumb_set BusFault_Handler,Default_Handler\r
-\r
- .weak UsageFault_Handler\r
- .thumb_set UsageFault_Handler,Default_Handler\r
-\r
- .weak SVC_Handler\r
- .thumb_set SVC_Handler,Default_Handler\r
-\r
- .weak DebugMon_Handler\r
- .thumb_set DebugMon_Handler,Default_Handler\r
-\r
- .weak PendSV_Handler\r
- .thumb_set PendSV_Handler,Default_Handler\r
-\r
- .weak SysTick_Handler\r
- .thumb_set SysTick_Handler,Default_Handler\r
-\r
- .weak WWDG_IRQHandler\r
- .thumb_set WWDG_IRQHandler,Default_Handler\r
-\r
- .weak PVD_IRQHandler\r
- .thumb_set PVD_IRQHandler,Default_Handler\r
-\r
- .weak TAMP_STAMP_IRQHandler\r
- .thumb_set TAMP_STAMP_IRQHandler,Default_Handler\r
-\r
- .weak RTC_WKUP_IRQHandler\r
- .thumb_set RTC_WKUP_IRQHandler,Default_Handler\r
-\r
- .weak FLASH_IRQHandler\r
- .thumb_set FLASH_IRQHandler,Default_Handler\r
-\r
- .weak RCC_IRQHandler\r
- .thumb_set RCC_IRQHandler,Default_Handler\r
-\r
- .weak EXTI0_IRQHandler\r
- .thumb_set EXTI0_IRQHandler,Default_Handler\r
-\r
- .weak EXTI1_IRQHandler\r
- .thumb_set EXTI1_IRQHandler,Default_Handler\r
-\r
- .weak EXTI2_IRQHandler\r
- .thumb_set EXTI2_IRQHandler,Default_Handler\r
-\r
- .weak EXTI3_IRQHandler\r
- .thumb_set EXTI3_IRQHandler,Default_Handler\r
-\r
- .weak EXTI4_IRQHandler\r
- .thumb_set EXTI4_IRQHandler,Default_Handler\r
-\r
- .weak DMA1_Stream0_IRQHandler\r
- .thumb_set DMA1_Stream0_IRQHandler,Default_Handler\r
-\r
- .weak DMA1_Stream1_IRQHandler\r
- .thumb_set DMA1_Stream1_IRQHandler,Default_Handler\r
-\r
- .weak DMA1_Stream2_IRQHandler\r
- .thumb_set DMA1_Stream2_IRQHandler,Default_Handler\r
-\r
- .weak DMA1_Stream3_IRQHandler\r
- .thumb_set DMA1_Stream3_IRQHandler,Default_Handler\r
-\r
- .weak DMA1_Stream4_IRQHandler\r
- .thumb_set DMA1_Stream4_IRQHandler,Default_Handler\r
-\r
- .weak DMA1_Stream5_IRQHandler\r
- .thumb_set DMA1_Stream5_IRQHandler,Default_Handler\r
-\r
- .weak DMA1_Stream6_IRQHandler\r
- .thumb_set DMA1_Stream6_IRQHandler,Default_Handler\r
-\r
- .weak ADC_IRQHandler\r
- .thumb_set ADC_IRQHandler,Default_Handler\r
-\r
- .weak CAN1_TX_IRQHandler\r
- .thumb_set CAN1_TX_IRQHandler,Default_Handler\r
-\r
- .weak CAN1_RX0_IRQHandler\r
- .thumb_set CAN1_RX0_IRQHandler,Default_Handler\r
-\r
- .weak CAN1_RX1_IRQHandler\r
- .thumb_set CAN1_RX1_IRQHandler,Default_Handler\r
-\r
- .weak CAN1_SCE_IRQHandler\r
- .thumb_set CAN1_SCE_IRQHandler,Default_Handler\r
-\r
- .weak EXTI9_5_IRQHandler\r
- .thumb_set EXTI9_5_IRQHandler,Default_Handler\r
-\r
- .weak TIM1_BRK_TIM9_IRQHandler\r
- .thumb_set TIM1_BRK_TIM9_IRQHandler,Default_Handler\r
-\r
- .weak TIM1_UP_TIM10_IRQHandler\r
- .thumb_set TIM1_UP_TIM10_IRQHandler,Default_Handler\r
-\r
- .weak TIM1_TRG_COM_TIM11_IRQHandler\r
- .thumb_set TIM1_TRG_COM_TIM11_IRQHandler,Default_Handler\r
-\r
- .weak TIM1_CC_IRQHandler\r
- .thumb_set TIM1_CC_IRQHandler,Default_Handler\r
-\r
- .weak TIM2_IRQHandler\r
- .thumb_set TIM2_IRQHandler,Default_Handler\r
-\r
- .weak TIM3_IRQHandler\r
- .thumb_set TIM3_IRQHandler,Default_Handler\r
-\r
- .weak TIM4_IRQHandler\r
- .thumb_set TIM4_IRQHandler,Default_Handler\r
-\r
- .weak I2C1_EV_IRQHandler\r
- .thumb_set I2C1_EV_IRQHandler,Default_Handler\r
-\r
- .weak I2C1_ER_IRQHandler\r
- .thumb_set I2C1_ER_IRQHandler,Default_Handler\r
-\r
- .weak I2C2_EV_IRQHandler\r
- .thumb_set I2C2_EV_IRQHandler,Default_Handler\r
-\r
- .weak I2C2_ER_IRQHandler\r
- .thumb_set I2C2_ER_IRQHandler,Default_Handler\r
-\r
- .weak SPI1_IRQHandler\r
- .thumb_set SPI1_IRQHandler,Default_Handler\r
-\r
- .weak SPI2_IRQHandler\r
- .thumb_set SPI2_IRQHandler,Default_Handler\r
-\r
- .weak USART1_IRQHandler\r
- .thumb_set USART1_IRQHandler,Default_Handler\r
-\r
- .weak USART2_IRQHandler\r
- .thumb_set USART2_IRQHandler,Default_Handler\r
-\r
- .weak USART3_IRQHandler\r
- .thumb_set USART3_IRQHandler,Default_Handler\r
-\r
- .weak EXTI15_10_IRQHandler\r
- .thumb_set EXTI15_10_IRQHandler,Default_Handler\r
-\r
- .weak RTC_Alarm_IRQHandler\r
- .thumb_set RTC_Alarm_IRQHandler,Default_Handler\r
-\r
- .weak OTG_FS_WKUP_IRQHandler\r
- .thumb_set OTG_FS_WKUP_IRQHandler,Default_Handler\r
-\r
- .weak TIM8_BRK_TIM12_IRQHandler\r
- .thumb_set TIM8_BRK_TIM12_IRQHandler,Default_Handler\r
-\r
- .weak TIM8_UP_TIM13_IRQHandler\r
- .thumb_set TIM8_UP_TIM13_IRQHandler,Default_Handler\r
-\r
- .weak TIM8_TRG_COM_TIM14_IRQHandler\r
- .thumb_set TIM8_TRG_COM_TIM14_IRQHandler,Default_Handler\r
-\r
- .weak TIM8_CC_IRQHandler\r
- .thumb_set TIM8_CC_IRQHandler,Default_Handler\r
-\r
- .weak DMA1_Stream7_IRQHandler\r
- .thumb_set DMA1_Stream7_IRQHandler,Default_Handler\r
-\r
- .weak FSMC_IRQHandler\r
- .thumb_set FSMC_IRQHandler,Default_Handler\r
-\r
- .weak SDIO_IRQHandler\r
- .thumb_set SDIO_IRQHandler,Default_Handler\r
-\r
- .weak TIM5_IRQHandler\r
- .thumb_set TIM5_IRQHandler,Default_Handler\r
-\r
- .weak SPI3_IRQHandler\r
- .thumb_set SPI3_IRQHandler,Default_Handler\r
-\r
- .weak UART4_IRQHandler\r
- .thumb_set UART4_IRQHandler,Default_Handler\r
-\r
- .weak UART5_IRQHandler\r
- .thumb_set UART5_IRQHandler,Default_Handler\r
-\r
- .weak TIM6_DAC_IRQHandler\r
- .thumb_set TIM6_DAC_IRQHandler,Default_Handler\r
-\r
- .weak TIM7_IRQHandler\r
- .thumb_set TIM7_IRQHandler,Default_Handler\r
-\r
- .weak DMA2_Stream0_IRQHandler\r
- .thumb_set DMA2_Stream0_IRQHandler,Default_Handler\r
-\r
- .weak DMA2_Stream1_IRQHandler\r
- .thumb_set DMA2_Stream1_IRQHandler,Default_Handler\r
-\r
- .weak DMA2_Stream2_IRQHandler\r
- .thumb_set DMA2_Stream2_IRQHandler,Default_Handler\r
-\r
- .weak DMA2_Stream3_IRQHandler\r
- .thumb_set DMA2_Stream3_IRQHandler,Default_Handler\r
-\r
- .weak DMA2_Stream4_IRQHandler\r
- .thumb_set DMA2_Stream4_IRQHandler,Default_Handler\r
-\r
- .weak ETH_IRQHandler\r
- .thumb_set ETH_IRQHandler,Default_Handler\r
-\r
- .weak ETH_WKUP_IRQHandler\r
- .thumb_set ETH_WKUP_IRQHandler,Default_Handler\r
-\r
- .weak CAN2_TX_IRQHandler\r
- .thumb_set CAN2_TX_IRQHandler,Default_Handler\r
-\r
- .weak CAN2_RX0_IRQHandler\r
- .thumb_set CAN2_RX0_IRQHandler,Default_Handler\r
-\r
- .weak CAN2_RX1_IRQHandler\r
- .thumb_set CAN2_RX1_IRQHandler,Default_Handler\r
-\r
- .weak CAN2_SCE_IRQHandler\r
- .thumb_set CAN2_SCE_IRQHandler,Default_Handler\r
-\r
- .weak OTG_FS_IRQHandler\r
- .thumb_set OTG_FS_IRQHandler,Default_Handler\r
-\r
- .weak DMA2_Stream5_IRQHandler\r
- .thumb_set DMA2_Stream5_IRQHandler,Default_Handler\r
-\r
- .weak DMA2_Stream6_IRQHandler\r
- .thumb_set DMA2_Stream6_IRQHandler,Default_Handler\r
-\r
- .weak DMA2_Stream7_IRQHandler\r
- .thumb_set DMA2_Stream7_IRQHandler,Default_Handler\r
-\r
- .weak USART6_IRQHandler\r
- .thumb_set USART6_IRQHandler,Default_Handler\r
-\r
- .weak I2C3_EV_IRQHandler\r
- .thumb_set I2C3_EV_IRQHandler,Default_Handler\r
-\r
- .weak I2C3_ER_IRQHandler\r
- .thumb_set I2C3_ER_IRQHandler,Default_Handler\r
-\r
- .weak OTG_HS_EP1_OUT_IRQHandler\r
- .thumb_set OTG_HS_EP1_OUT_IRQHandler,Default_Handler\r
-\r
- .weak OTG_HS_EP1_IN_IRQHandler\r
- .thumb_set OTG_HS_EP1_IN_IRQHandler,Default_Handler\r
-\r
- .weak OTG_HS_WKUP_IRQHandler\r
- .thumb_set OTG_HS_WKUP_IRQHandler,Default_Handler\r
-\r
- .weak OTG_HS_IRQHandler\r
- .thumb_set OTG_HS_IRQHandler,Default_Handler\r
-\r
- .weak DCMI_IRQHandler\r
- .thumb_set DCMI_IRQHandler,Default_Handler\r
-\r
- .weak CRYP_IRQHandler\r
- .thumb_set CRYP_IRQHandler,Default_Handler\r
-\r
- .weak HASH_RNG_IRQHandler\r
- .thumb_set HASH_RNG_IRQHandler,Default_Handler\r
-\r
- .weak FPU_IRQHandler\r
- .thumb_set FPU_IRQHandler,Default_Handler\r
-\r
-/******************* (C) COPYRIGHT 2011 STMicroelectronics *****END OF FILE****/\r
+/**
+ ******************************************************************************
+ * @file startup_stm32f4xx.s
+ * @author MCD Application Team
+ * @version V1.0.0
+ * @date 30-September-2011
+ * @brief STM32F4xx Devices vector table for Atollic TrueSTUDIO toolchain.
+ * This module performs:
+ * - Set the initial SP
+ * - Set the initial PC == Reset_Handler,
+ * - Set the vector table entries with the exceptions ISR address
+ * - Configure the clock system and the external SRAM mounted on
+ * STM324xG-EVAL board to be used as data memory (optional,
+ * to be enabled by user)
+ * - Branches to main in the C library (which eventually
+ * calls main()).
+ * After Reset the Cortex-M4 processor is in Thread mode,
+ * priority is Privileged, and the Stack is set to Main.
+ ******************************************************************************
+ * @attention
+ *
+ * THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS
+ * WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE
+ * TIME. AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY
+ * DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING
+ * FROM THE CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE
+ * CODING INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.
+ *
+ * <h2><center>© COPYRIGHT 2011 STMicroelectronics</center></h2>
+ ******************************************************************************
+ */
+
+ .syntax unified
+ .cpu cortex-m3
+ .fpu softvfp
+ .thumb
+
+.global g_pfnVectors
+.global Default_Handler
+
+/* start address for the initialization values of the .data section.
+defined in linker script */
+.word _sidata
+/* start address for the .data section. defined in linker script */
+.word _sdata
+/* end address for the .data section. defined in linker script */
+.word _edata
+/* start address for the .bss section. defined in linker script */
+.word _sbss
+/* end address for the .bss section. defined in linker script */
+.word _ebss
+/* stack used for SystemInit_ExtMemCtl; always internal RAM used */
+
+/**
+ * @brief This is the code that gets called when the processor first
+ * starts execution following a reset event. Only the absolutely
+ * necessary set is performed, after which the application
+ * supplied main() routine is called.
+ * @param None
+ * @retval : None
+*/
+
+ .section .text.Reset_Handler
+ .weak Reset_Handler
+ .type Reset_Handler, %function
+Reset_Handler:
+
+/* Copy the data segment initializers from flash to SRAM */
+ movs r1, #0
+ b LoopCopyDataInit
+
+CopyDataInit:
+ ldr r3, =_sidata
+ ldr r3, [r3, r1]
+ str r3, [r0, r1]
+ adds r1, r1, #4
+
+LoopCopyDataInit:
+ ldr r0, =_sdata
+ ldr r3, =_edata
+ adds r2, r0, r1
+ cmp r2, r3
+ bcc CopyDataInit
+ ldr r2, =_sbss
+ b LoopFillZerobss
+/* Zero fill the bss segment. */
+FillZerobss:
+ movs r3, #0
+ str r3, [r2], #4
+
+LoopFillZerobss:
+ ldr r3, = _ebss
+ cmp r2, r3
+ bcc FillZerobss
+
+/* Call the clock system intitialization function.*/
+ bl SystemInit
+/* Call static constructors */
+ bl __libc_init_array
+/* Call the application's entry point.*/
+ bl main
+ bx lr
+.size Reset_Handler, .-Reset_Handler
+
+/**
+ * @brief This is the code that gets called when the processor receives an
+ * unexpected interrupt. This simply enters an infinite loop, preserving
+ * the system state for examination by a debugger.
+ * @param None
+ * @retval None
+*/
+ .section .text.Default_Handler,"ax",%progbits
+Default_Handler:
+Infinite_Loop:
+ b Infinite_Loop
+ .size Default_Handler, .-Default_Handler
+/******************************************************************************
+*
+* The minimal vector table for a Cortex M3. Note that the proper constructs
+* must be placed on this to ensure that it ends up at physical address
+* 0x0000.0000.
+*
+*******************************************************************************/
+ .section .isr_vector,"a",%progbits
+ .type g_pfnVectors, %object
+ .size g_pfnVectors, .-g_pfnVectors
+
+
+g_pfnVectors:
+ .word _estack
+ .word Reset_Handler
+ .word NMI_Handler
+ .word HardFault_Handler
+ .word MemManage_Handler
+ .word BusFault_Handler
+ .word UsageFault_Handler
+ .word 0
+ .word 0
+ .word 0
+ .word 0
+ .word SVC_Handler
+ .word DebugMon_Handler
+ .word 0
+ .word PendSV_Handler
+ .word SysTick_Handler
+
+ /* External Interrupts */
+ .word WWDG_IRQHandler /* Window WatchDog */
+ .word PVD_IRQHandler /* PVD through EXTI Line detection */
+ .word TAMP_STAMP_IRQHandler /* Tamper and TimeStamps through the EXTI line */
+ .word RTC_WKUP_IRQHandler /* RTC Wakeup through the EXTI line */
+ .word FLASH_IRQHandler /* FLASH */
+ .word RCC_IRQHandler /* RCC */
+ .word EXTI0_IRQHandler /* EXTI Line0 */
+ .word EXTI1_IRQHandler /* EXTI Line1 */
+ .word EXTI2_IRQHandler /* EXTI Line2 */
+ .word EXTI3_IRQHandler /* EXTI Line3 */
+ .word EXTI4_IRQHandler /* EXTI Line4 */
+ .word DMA1_Stream0_IRQHandler /* DMA1 Stream 0 */
+ .word DMA1_Stream1_IRQHandler /* DMA1 Stream 1 */
+ .word DMA1_Stream2_IRQHandler /* DMA1 Stream 2 */
+ .word DMA1_Stream3_IRQHandler /* DMA1 Stream 3 */
+ .word DMA1_Stream4_IRQHandler /* DMA1 Stream 4 */
+ .word DMA1_Stream5_IRQHandler /* DMA1 Stream 5 */
+ .word DMA1_Stream6_IRQHandler /* DMA1 Stream 6 */
+ .word ADC_IRQHandler /* ADC1, ADC2 and ADC3s */
+ .word CAN1_TX_IRQHandler /* CAN1 TX */
+ .word CAN1_RX0_IRQHandler /* CAN1 RX0 */
+ .word CAN1_RX1_IRQHandler /* CAN1 RX1 */
+ .word CAN1_SCE_IRQHandler /* CAN1 SCE */
+ .word EXTI9_5_IRQHandler /* External Line[9:5]s */
+ .word TIM1_BRK_TIM9_IRQHandler /* TIM1 Break and TIM9 */
+ .word TIM1_UP_TIM10_IRQHandler /* TIM1 Update and TIM10 */
+ .word TIM1_TRG_COM_TIM11_IRQHandler /* TIM1 Trigger and Commutation and TIM11 */
+ .word TIM1_CC_IRQHandler /* TIM1 Capture Compare */
+ .word TIM2_IRQHandler /* TIM2 */
+ .word TIM3_IRQHandler /* TIM3 */
+ .word TIM4_IRQHandler /* TIM4 */
+ .word I2C1_EV_IRQHandler /* I2C1 Event */
+ .word I2C1_ER_IRQHandler /* I2C1 Error */
+ .word I2C2_EV_IRQHandler /* I2C2 Event */
+ .word I2C2_ER_IRQHandler /* I2C2 Error */
+ .word SPI1_IRQHandler /* SPI1 */
+ .word SPI2_IRQHandler /* SPI2 */
+ .word USART1_IRQHandler /* USART1 */
+ .word USART2_IRQHandler /* USART2 */
+ .word USART3_IRQHandler /* USART3 */
+ .word EXTI15_10_IRQHandler /* External Line[15:10]s */
+ .word RTC_Alarm_IRQHandler /* RTC Alarm (A and B) through EXTI Line */
+ .word OTG_FS_WKUP_IRQHandler /* USB OTG FS Wakeup through EXTI line */
+ .word TIM8_BRK_TIM12_IRQHandler /* TIM8 Break and TIM12 */
+ .word TIM8_UP_TIM13_IRQHandler /* TIM8 Update and TIM13 */
+ .word TIM8_TRG_COM_TIM14_IRQHandler /* TIM8 Trigger and Commutation and TIM14 */
+ .word TIM8_CC_IRQHandler /* TIM8 Capture Compare */
+ .word DMA1_Stream7_IRQHandler /* DMA1 Stream7 */
+ .word FSMC_IRQHandler /* FSMC */
+ .word SDIO_IRQHandler /* SDIO */
+ .word TIM5_IRQHandler /* TIM5 */
+ .word SPI3_IRQHandler /* SPI3 */
+ .word UART4_IRQHandler /* UART4 */
+ .word UART5_IRQHandler /* UART5 */
+ .word TIM6_DAC_IRQHandler /* TIM6 and DAC1&2 underrun errors */
+ .word TIM7_IRQHandler /* TIM7 */
+ .word DMA2_Stream0_IRQHandler /* DMA2 Stream 0 */
+ .word DMA2_Stream1_IRQHandler /* DMA2 Stream 1 */
+ .word DMA2_Stream2_IRQHandler /* DMA2 Stream 2 */
+ .word DMA2_Stream3_IRQHandler /* DMA2 Stream 3 */
+ .word DMA2_Stream4_IRQHandler /* DMA2 Stream 4 */
+ .word ETH_IRQHandler /* Ethernet */
+ .word ETH_WKUP_IRQHandler /* Ethernet Wakeup through EXTI line */
+ .word CAN2_TX_IRQHandler /* CAN2 TX */
+ .word CAN2_RX0_IRQHandler /* CAN2 RX0 */
+ .word CAN2_RX1_IRQHandler /* CAN2 RX1 */
+ .word CAN2_SCE_IRQHandler /* CAN2 SCE */
+ .word OTG_FS_IRQHandler /* USB OTG FS */
+ .word DMA2_Stream5_IRQHandler /* DMA2 Stream 5 */
+ .word DMA2_Stream6_IRQHandler /* DMA2 Stream 6 */
+ .word DMA2_Stream7_IRQHandler /* DMA2 Stream 7 */
+ .word USART6_IRQHandler /* USART6 */
+ .word I2C3_EV_IRQHandler /* I2C3 event */
+ .word I2C3_ER_IRQHandler /* I2C3 error */
+ .word OTG_HS_EP1_OUT_IRQHandler /* USB OTG HS End Point 1 Out */
+ .word OTG_HS_EP1_IN_IRQHandler /* USB OTG HS End Point 1 In */
+ .word OTG_HS_WKUP_IRQHandler /* USB OTG HS Wakeup through EXTI */
+ .word OTG_HS_IRQHandler /* USB OTG HS */
+ .word DCMI_IRQHandler /* DCMI */
+ .word CRYP_IRQHandler /* CRYP crypto */
+ .word HASH_RNG_IRQHandler /* Hash and Rng */
+ .word FPU_IRQHandler /* FPU */
+
+
+/*******************************************************************************
+*
+* Provide weak aliases for each Exception handler to the Default_Handler.
+* As they are weak aliases, any function with the same name will override
+* this definition.
+*
+*******************************************************************************/
+ .weak NMI_Handler
+ .thumb_set NMI_Handler,Default_Handler
+
+ .weak HardFault_Handler
+ .thumb_set HardFault_Handler,Default_Handler
+
+ .weak MemManage_Handler
+ .thumb_set MemManage_Handler,Default_Handler
+
+ .weak BusFault_Handler
+ .thumb_set BusFault_Handler,Default_Handler
+
+ .weak UsageFault_Handler
+ .thumb_set UsageFault_Handler,Default_Handler
+
+ .weak SVC_Handler
+ .thumb_set SVC_Handler,Default_Handler
+
+ .weak DebugMon_Handler
+ .thumb_set DebugMon_Handler,Default_Handler
+
+ .weak PendSV_Handler
+ .thumb_set PendSV_Handler,Default_Handler
+
+ .weak SysTick_Handler
+ .thumb_set SysTick_Handler,Default_Handler
+
+ .weak WWDG_IRQHandler
+ .thumb_set WWDG_IRQHandler,Default_Handler
+
+ .weak PVD_IRQHandler
+ .thumb_set PVD_IRQHandler,Default_Handler
+
+ .weak TAMP_STAMP_IRQHandler
+ .thumb_set TAMP_STAMP_IRQHandler,Default_Handler
+
+ .weak RTC_WKUP_IRQHandler
+ .thumb_set RTC_WKUP_IRQHandler,Default_Handler
+
+ .weak FLASH_IRQHandler
+ .thumb_set FLASH_IRQHandler,Default_Handler
+
+ .weak RCC_IRQHandler
+ .thumb_set RCC_IRQHandler,Default_Handler
+
+ .weak EXTI0_IRQHandler
+ .thumb_set EXTI0_IRQHandler,Default_Handler
+
+ .weak EXTI1_IRQHandler
+ .thumb_set EXTI1_IRQHandler,Default_Handler
+
+ .weak EXTI2_IRQHandler
+ .thumb_set EXTI2_IRQHandler,Default_Handler
+
+ .weak EXTI3_IRQHandler
+ .thumb_set EXTI3_IRQHandler,Default_Handler
+
+ .weak EXTI4_IRQHandler
+ .thumb_set EXTI4_IRQHandler,Default_Handler
+
+ .weak DMA1_Stream0_IRQHandler
+ .thumb_set DMA1_Stream0_IRQHandler,Default_Handler
+
+ .weak DMA1_Stream1_IRQHandler
+ .thumb_set DMA1_Stream1_IRQHandler,Default_Handler
+
+ .weak DMA1_Stream2_IRQHandler
+ .thumb_set DMA1_Stream2_IRQHandler,Default_Handler
+
+ .weak DMA1_Stream3_IRQHandler
+ .thumb_set DMA1_Stream3_IRQHandler,Default_Handler
+
+ .weak DMA1_Stream4_IRQHandler
+ .thumb_set DMA1_Stream4_IRQHandler,Default_Handler
+
+ .weak DMA1_Stream5_IRQHandler
+ .thumb_set DMA1_Stream5_IRQHandler,Default_Handler
+
+ .weak DMA1_Stream6_IRQHandler
+ .thumb_set DMA1_Stream6_IRQHandler,Default_Handler
+
+ .weak ADC_IRQHandler
+ .thumb_set ADC_IRQHandler,Default_Handler
+
+ .weak CAN1_TX_IRQHandler
+ .thumb_set CAN1_TX_IRQHandler,Default_Handler
+
+ .weak CAN1_RX0_IRQHandler
+ .thumb_set CAN1_RX0_IRQHandler,Default_Handler
+
+ .weak CAN1_RX1_IRQHandler
+ .thumb_set CAN1_RX1_IRQHandler,Default_Handler
+
+ .weak CAN1_SCE_IRQHandler
+ .thumb_set CAN1_SCE_IRQHandler,Default_Handler
+
+ .weak EXTI9_5_IRQHandler
+ .thumb_set EXTI9_5_IRQHandler,Default_Handler
+
+ .weak TIM1_BRK_TIM9_IRQHandler
+ .thumb_set TIM1_BRK_TIM9_IRQHandler,Default_Handler
+
+ .weak TIM1_UP_TIM10_IRQHandler
+ .thumb_set TIM1_UP_TIM10_IRQHandler,Default_Handler
+
+ .weak TIM1_TRG_COM_TIM11_IRQHandler
+ .thumb_set TIM1_TRG_COM_TIM11_IRQHandler,Default_Handler
+
+ .weak TIM1_CC_IRQHandler
+ .thumb_set TIM1_CC_IRQHandler,Default_Handler
+
+ .weak TIM2_IRQHandler
+ .thumb_set TIM2_IRQHandler,Default_Handler
+
+ .weak TIM3_IRQHandler
+ .thumb_set TIM3_IRQHandler,Default_Handler
+
+ .weak TIM4_IRQHandler
+ .thumb_set TIM4_IRQHandler,Default_Handler
+
+ .weak I2C1_EV_IRQHandler
+ .thumb_set I2C1_EV_IRQHandler,Default_Handler
+
+ .weak I2C1_ER_IRQHandler
+ .thumb_set I2C1_ER_IRQHandler,Default_Handler
+
+ .weak I2C2_EV_IRQHandler
+ .thumb_set I2C2_EV_IRQHandler,Default_Handler
+
+ .weak I2C2_ER_IRQHandler
+ .thumb_set I2C2_ER_IRQHandler,Default_Handler
+
+ .weak SPI1_IRQHandler
+ .thumb_set SPI1_IRQHandler,Default_Handler
+
+ .weak SPI2_IRQHandler
+ .thumb_set SPI2_IRQHandler,Default_Handler
+
+ .weak USART1_IRQHandler
+ .thumb_set USART1_IRQHandler,Default_Handler
+
+ .weak USART2_IRQHandler
+ .thumb_set USART2_IRQHandler,Default_Handler
+
+ .weak USART3_IRQHandler
+ .thumb_set USART3_IRQHandler,Default_Handler
+
+ .weak EXTI15_10_IRQHandler
+ .thumb_set EXTI15_10_IRQHandler,Default_Handler
+
+ .weak RTC_Alarm_IRQHandler
+ .thumb_set RTC_Alarm_IRQHandler,Default_Handler
+
+ .weak OTG_FS_WKUP_IRQHandler
+ .thumb_set OTG_FS_WKUP_IRQHandler,Default_Handler
+
+ .weak TIM8_BRK_TIM12_IRQHandler
+ .thumb_set TIM8_BRK_TIM12_IRQHandler,Default_Handler
+
+ .weak TIM8_UP_TIM13_IRQHandler
+ .thumb_set TIM8_UP_TIM13_IRQHandler,Default_Handler
+
+ .weak TIM8_TRG_COM_TIM14_IRQHandler
+ .thumb_set TIM8_TRG_COM_TIM14_IRQHandler,Default_Handler
+
+ .weak TIM8_CC_IRQHandler
+ .thumb_set TIM8_CC_IRQHandler,Default_Handler
+
+ .weak DMA1_Stream7_IRQHandler
+ .thumb_set DMA1_Stream7_IRQHandler,Default_Handler
+
+ .weak FSMC_IRQHandler
+ .thumb_set FSMC_IRQHandler,Default_Handler
+
+ .weak SDIO_IRQHandler
+ .thumb_set SDIO_IRQHandler,Default_Handler
+
+ .weak TIM5_IRQHandler
+ .thumb_set TIM5_IRQHandler,Default_Handler
+
+ .weak SPI3_IRQHandler
+ .thumb_set SPI3_IRQHandler,Default_Handler
+
+ .weak UART4_IRQHandler
+ .thumb_set UART4_IRQHandler,Default_Handler
+
+ .weak UART5_IRQHandler
+ .thumb_set UART5_IRQHandler,Default_Handler
+
+ .weak TIM6_DAC_IRQHandler
+ .thumb_set TIM6_DAC_IRQHandler,Default_Handler
+
+ .weak TIM7_IRQHandler
+ .thumb_set TIM7_IRQHandler,Default_Handler
+
+ .weak DMA2_Stream0_IRQHandler
+ .thumb_set DMA2_Stream0_IRQHandler,Default_Handler
+
+ .weak DMA2_Stream1_IRQHandler
+ .thumb_set DMA2_Stream1_IRQHandler,Default_Handler
+
+ .weak DMA2_Stream2_IRQHandler
+ .thumb_set DMA2_Stream2_IRQHandler,Default_Handler
+
+ .weak DMA2_Stream3_IRQHandler
+ .thumb_set DMA2_Stream3_IRQHandler,Default_Handler
+
+ .weak DMA2_Stream4_IRQHandler
+ .thumb_set DMA2_Stream4_IRQHandler,Default_Handler
+
+ .weak ETH_IRQHandler
+ .thumb_set ETH_IRQHandler,Default_Handler
+
+ .weak ETH_WKUP_IRQHandler
+ .thumb_set ETH_WKUP_IRQHandler,Default_Handler
+
+ .weak CAN2_TX_IRQHandler
+ .thumb_set CAN2_TX_IRQHandler,Default_Handler
+
+ .weak CAN2_RX0_IRQHandler
+ .thumb_set CAN2_RX0_IRQHandler,Default_Handler
+
+ .weak CAN2_RX1_IRQHandler
+ .thumb_set CAN2_RX1_IRQHandler,Default_Handler
+
+ .weak CAN2_SCE_IRQHandler
+ .thumb_set CAN2_SCE_IRQHandler,Default_Handler
+
+ .weak OTG_FS_IRQHandler
+ .thumb_set OTG_FS_IRQHandler,Default_Handler
+
+ .weak DMA2_Stream5_IRQHandler
+ .thumb_set DMA2_Stream5_IRQHandler,Default_Handler
+
+ .weak DMA2_Stream6_IRQHandler
+ .thumb_set DMA2_Stream6_IRQHandler,Default_Handler
+
+ .weak DMA2_Stream7_IRQHandler
+ .thumb_set DMA2_Stream7_IRQHandler,Default_Handler
+
+ .weak USART6_IRQHandler
+ .thumb_set USART6_IRQHandler,Default_Handler
+
+ .weak I2C3_EV_IRQHandler
+ .thumb_set I2C3_EV_IRQHandler,Default_Handler
+
+ .weak I2C3_ER_IRQHandler
+ .thumb_set I2C3_ER_IRQHandler,Default_Handler
+
+ .weak OTG_HS_EP1_OUT_IRQHandler
+ .thumb_set OTG_HS_EP1_OUT_IRQHandler,Default_Handler
+
+ .weak OTG_HS_EP1_IN_IRQHandler
+ .thumb_set OTG_HS_EP1_IN_IRQHandler,Default_Handler
+
+ .weak OTG_HS_WKUP_IRQHandler
+ .thumb_set OTG_HS_WKUP_IRQHandler,Default_Handler
+
+ .weak OTG_HS_IRQHandler
+ .thumb_set OTG_HS_IRQHandler,Default_Handler
+
+ .weak DCMI_IRQHandler
+ .thumb_set DCMI_IRQHandler,Default_Handler
+
+ .weak CRYP_IRQHandler
+ .thumb_set CRYP_IRQHandler,Default_Handler
+
+ .weak HASH_RNG_IRQHandler
+ .thumb_set HASH_RNG_IRQHandler,Default_Handler
+
+ .weak FPU_IRQHandler
+ .thumb_set FPU_IRQHandler,Default_Handler
+
+/******************* (C) COPYRIGHT 2011 STMicroelectronics *****END OF FILE****/
-/*---------------------------------------------------------------------------*\\r
-\r
- FILE........: stm32f4_dac.c\r
- AUTHOR......: David Rowe\r
- DATE CREATED: 1 June 2013\r
-\r
- DAC driver module for STM32F4. DAC1 is connected to pin PA4, DAC2\r
- is connected to pin PA5.\r
-\r
-\*---------------------------------------------------------------------------*/\r
-\r
-/*\r
- Copyright (C) 2013 David Rowe\r
-\r
- All rights reserved.\r
-\r
- This program is free software; you can redistribute it and/or modify\r
- it under the terms of the GNU Lesser General Public License version 2.1, as\r
- published by the Free Software Foundation. This program is\r
- distributed in the hope that it will be useful, but WITHOUT ANY\r
- WARRANTY; without even the implied warranty of MERCHANTABILITY or\r
- FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public\r
- License for more details.\r
-\r
- You should have received a copy of the GNU Lesser General Public License\r
- along with this program; if not, see <http://www.gnu.org/licenses/>.\r
-*/\r
-\r
-#include <assert.h>\r
-#include <stdlib.h>\r
-#include <string.h>\r
-#include "stm32f4xx.h"\r
-#include "codec2_fifo.h"\r
-#include "stm32f4_dac.h"\r
-#include "debugblinky.h"\r
-\r
-/* write to these registers for 12 bit left aligned data, as per data sheet \r
- make sure 4 least sig bits set to 0 */\r
-\r
-#define DAC_DHR12R1_ADDRESS 0x40007408\r
-#define DAC_DHR12R2_ADDRESS 0x40007414\r
-\r
-#define DAC_MAX 4096 /* maximum amplitude */\r
-\r
-/* y=mx+c mapping of samples16 bit shorts to DAC samples. Table: 74\r
- of data sheet indicates With DAC buffer on, DAC range is limited to\r
- 0x0E0 to 0xF1C at VREF+ = 3.6 V, we have Vref=3.3V which is close.\r
- */\r
-\r
-#define M ((3868.0-224.0)/65536.0)\r
-#define C 2047.0\r
-\r
-static struct FIFO *dac1_fifo;\r
-static struct FIFO *dac2_fifo;\r
-\r
-static unsigned short dac1_buf[DAC_BUF_SZ];\r
-static unsigned short dac2_buf[DAC_BUF_SZ];\r
-\r
-static void tim6_config(void);\r
-static void dac1_config(void);\r
-static void dac2_config(void);\r
-\r
-int dac_underflow;\r
-\r
-void dac_open(int fifo_size) {\r
-\r
- memset(dac1_buf, 32768, sizeof(short)*DAC_BUF_SZ);\r
- memset(dac2_buf, 32768, sizeof(short)*DAC_BUF_SZ);\r
-\r
- /* Create fifos */\r
-\r
- dac1_fifo = fifo_create(fifo_size);\r
- dac2_fifo = fifo_create(fifo_size);\r
- assert(dac1_fifo != NULL);\r
- assert(dac2_fifo != NULL);\r
-\r
- /* Turn on the clocks we need -----------------------------------------------*/\r
-\r
- /* DMA1 clock enable */\r
- RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA1, ENABLE);\r
- /* GPIOA clock enable (to be used with DAC) */\r
- RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE); \r
- /* DAC Periph clock enable */\r
- RCC_APB1PeriphClockCmd(RCC_APB1Periph_DAC, ENABLE);\r
-\r
- /* GPIO Pin configuration DAC1->PA.4, DAC2->PA.5 configuration --------------*/\r
-\r
- GPIO_InitTypeDef GPIO_InitStructure;\r
- GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4 | GPIO_Pin_5;\r
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;\r
- GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;\r
- GPIO_Init(GPIOA, &GPIO_InitStructure);\r
-\r
- /* Timer and DAC 1 & 2 Configuration ----------------------------------------*/\r
-\r
- tim6_config(); \r
- dac1_config();\r
- dac2_config();\r
-\r
- init_debug_blinky();\r
-}\r
-\r
-/* Call these puppies to send samples to the DACs. For your\r
- convenience they accept signed 16 bit samples. */\r
-\r
-int dac1_write(short buf[], int n) { \r
- return fifo_write(dac1_fifo, buf, n);\r
-}\r
-\r
-int dac2_write(short buf[], int n) { \r
- return fifo_write(dac2_fifo, buf, n);\r
-}\r
-\r
-int dac1_free() {\r
- return fifo_free(dac1_fifo);\r
-}\r
-\r
-int dac2_free() {\r
- return fifo_free(dac2_fifo);\r
-}\r
-\r
-static void tim6_config(void)\r
-{\r
- TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;\r
-\r
- /* TIM6 Periph clock enable */\r
- RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM6, ENABLE);\r
- \r
- /* --------------------------------------------------------\r
- \r
- TIM6 input clock (TIM6CLK) is set to 2 * APB1 clock (PCLK1), since\r
- APB1 prescaler is different from 1 (see system_stm32f4xx.c and Fig\r
- 13 clock tree figure in DM0031020.pdf).\r
-\r
- Sample rate Fs = 2*PCLK1/TIM_ClockDivision \r
- = (HCLK/2)/TIM_ClockDivision\r
- \r
- ----------------------------------------------------------- */\r
-\r
- /* Time base configuration */\r
-\r
- TIM_TimeBaseStructInit(&TIM_TimeBaseStructure); \r
- TIM_TimeBaseStructure.TIM_Period = 5250; \r
- TIM_TimeBaseStructure.TIM_Prescaler = 0; \r
- TIM_TimeBaseStructure.TIM_ClockDivision = 0; \r
- TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; \r
- TIM_TimeBaseInit(TIM6, &TIM_TimeBaseStructure);\r
-\r
- /* TIM6 TRGO selection */\r
-\r
- TIM_SelectOutputTrigger(TIM6, TIM_TRGOSource_Update);\r
- \r
- /* TIM6 enable counter */\r
-\r
- TIM_Cmd(TIM6, ENABLE);\r
-}\r
-\r
-static void dac1_config(void)\r
-{\r
- DAC_InitTypeDef DAC_InitStructure;\r
- DMA_InitTypeDef DMA_InitStructure;\r
- NVIC_InitTypeDef NVIC_InitStructure;\r
- \r
- /* DAC channel 1 Configuration */\r
-\r
- /* \r
- This line fixed a bug that cost me 5 days, bad wave amplitude\r
- value, and some STM32F4 periph library bugs caused triangle wave\r
- geneartion to be enable resulting in a low level tone on the\r
- SM1000, that we thought was caused by analog issues like layour\r
- or power supply biasing\r
- */\r
- DAC_StructInit(&DAC_InitStructure); \r
-\r
- DAC_InitStructure.DAC_Trigger = DAC_Trigger_T6_TRGO; \r
- DAC_InitStructure.DAC_WaveGeneration = DAC_WaveGeneration_None;\r
- DAC_InitStructure.DAC_OutputBuffer = DAC_OutputBuffer_Enable;\r
- DAC_Init(DAC_Channel_1, &DAC_InitStructure);\r
-\r
- /* DMA1_Stream5 channel7 configuration **************************************/\r
- /* Table 35 page 219 of the monster data sheet */\r
-\r
- DMA_DeInit(DMA1_Stream5);\r
- DMA_InitStructure.DMA_Channel = DMA_Channel_7; \r
- DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)DAC_DHR12R1_ADDRESS;\r
- DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)dac1_buf;\r
- DMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToPeripheral;\r
- DMA_InitStructure.DMA_BufferSize = DAC_BUF_SZ;\r
- DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;\r
- DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;\r
- DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;\r
- DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;\r
- DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;\r
- DMA_InitStructure.DMA_Priority = DMA_Priority_High;\r
- DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable; \r
- DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_HalfFull;\r
- DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;\r
- DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;\r
- DMA_Init(DMA1_Stream5, &DMA_InitStructure);\r
-\r
- /* Enable DMA Half & Complete interrupts */\r
-\r
- DMA_ITConfig(DMA1_Stream5, DMA_IT_TC | DMA_IT_HT, ENABLE);\r
-\r
- /* Enable the DMA Stream IRQ Channel */\r
-\r
- NVIC_InitStructure.NVIC_IRQChannel = DMA1_Stream5_IRQn;\r
- NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;\r
- NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;\r
- NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;\r
- NVIC_Init(&NVIC_InitStructure); \r
-\r
- /* Enable DMA1_Stream5 */\r
-\r
- DMA_Cmd(DMA1_Stream5, ENABLE);\r
-\r
- /* Enable DAC Channel 1 */\r
-\r
- DAC_Cmd(DAC_Channel_1, ENABLE);\r
-\r
- /* Enable DMA for DAC Channel 1 */\r
-\r
- DAC_DMACmd(DAC_Channel_1, ENABLE);\r
-}\r
-\r
-static void dac2_config(void)\r
-{\r
- DAC_InitTypeDef DAC_InitStructure;\r
- DMA_InitTypeDef DMA_InitStructure;\r
- NVIC_InitTypeDef NVIC_InitStructure;\r
- \r
- /* DAC channel 2 Configuration (see notes in dac1_config() above) */\r
-\r
- DAC_StructInit(&DAC_InitStructure);\r
- DAC_InitStructure.DAC_Trigger = DAC_Trigger_T6_TRGO;\r
- DAC_InitStructure.DAC_WaveGeneration = DAC_WaveGeneration_None;\r
- DAC_InitStructure.DAC_OutputBuffer = DAC_OutputBuffer_Enable;\r
- DAC_Init(DAC_Channel_2, &DAC_InitStructure);\r
-\r
- /* DMA1_Stream6 channel7 configuration **************************************/\r
-\r
- DMA_DeInit(DMA1_Stream6);\r
- DMA_InitStructure.DMA_Channel = DMA_Channel_7; \r
- DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)DAC_DHR12R2_ADDRESS;\r
- DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)dac2_buf;\r
- DMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToPeripheral;\r
- DMA_InitStructure.DMA_BufferSize = DAC_BUF_SZ;\r
- DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;\r
- DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;\r
- DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;\r
- DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;\r
- DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;\r
- DMA_InitStructure.DMA_Priority = DMA_Priority_High;\r
- DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable; \r
- DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_HalfFull;\r
- DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;\r
- DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;\r
- DMA_Init(DMA1_Stream6, &DMA_InitStructure);\r
-\r
- /* Enable DMA Half & Complete interrupts */\r
-\r
- DMA_ITConfig(DMA1_Stream6, DMA_IT_TC | DMA_IT_HT, ENABLE);\r
-\r
- /* Enable the DMA Stream IRQ Channel */\r
-\r
- NVIC_InitStructure.NVIC_IRQChannel = DMA1_Stream6_IRQn;\r
- NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;\r
- NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;\r
- NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;\r
- NVIC_Init(&NVIC_InitStructure); \r
-\r
- /* Enable DMA1_Stream6 */\r
-\r
- DMA_Cmd(DMA1_Stream6, ENABLE);\r
-\r
- /* Enable DAC Channel 2 */\r
-\r
- DAC_Cmd(DAC_Channel_2, ENABLE);\r
-\r
- /* Enable DMA for DAC Channel 2 */\r
-\r
- DAC_DMACmd(DAC_Channel_2, ENABLE);\r
-\r
-}\r
-\r
-/******************************************************************************/\r
-/* STM32F4xx Peripherals Interrupt Handlers */\r
-/* Add here the Interrupt Handler for the used peripheral(s) (PPP), for the */\r
-/* available peripheral interrupt handler's name please refer to the startup */\r
-/* file (startup_stm32f40xx.s/startup_stm32f427x.s). */\r
-/******************************************************************************/\r
-\r
-/*\r
- This function handles DMA1 Stream 5 interrupt request for DAC1.\r
-*/\r
-\r
-void DMA1_Stream5_IRQHandler(void) {\r
- int i, j, sam;\r
- short signed_buf[DAC_BUF_SZ/2];\r
-\r
- GPIOE->ODR |= (1 << 1);\r
-\r
- /* Transfer half empty interrupt - refill first half */\r
-\r
- if(DMA_GetITStatus(DMA1_Stream5, DMA_IT_HTIF5) != RESET) {\r
- /* fill first half from fifo */\r
-\r
- if (fifo_read(dac1_fifo, signed_buf, DAC_BUF_SZ/2) == -1) {\r
- memset(signed_buf, 0, sizeof(short)*DAC_BUF_SZ/2);\r
- dac_underflow++;\r
- }\r
-\r
- /* convert to unsigned */\r
-\r
- for(i=0; i<DAC_BUF_SZ/2; i++) {\r
- sam = (int)(M*(float)signed_buf[i] + C);\r
- dac1_buf[i] = (unsigned short)sam;\r
- }\r
-\r
- /* Clear DMA Stream Transfer Complete interrupt pending bit */\r
-\r
- DMA_ClearITPendingBit(DMA1_Stream5, DMA_IT_HTIF5); \r
- }\r
-\r
- /* Transfer complete interrupt - refill 2nd half */\r
-\r
- if(DMA_GetITStatus(DMA1_Stream5, DMA_IT_TCIF5) != RESET) {\r
- /* fill second half from fifo */\r
-\r
- if (fifo_read(dac1_fifo, signed_buf, DAC_BUF_SZ/2) == -1) {\r
- memset(signed_buf, 0, sizeof(short)*DAC_BUF_SZ/2);\r
- dac_underflow++;\r
- }\r
-\r
- /* convert to unsigned */\r
-\r
- for(i=0, j=DAC_BUF_SZ/2; i<DAC_BUF_SZ/2; i++,j++) {\r
- sam = (int)(M*(float)signed_buf[i] + C);\r
- dac1_buf[j] = (unsigned short)sam;\r
- }\r
-\r
- /* Clear DMA Stream Transfer Complete interrupt pending bit */\r
-\r
- DMA_ClearITPendingBit(DMA1_Stream5, DMA_IT_TCIF5); \r
- }\r
-\r
- GPIOE->ODR &= ~(1 << 1);\r
-}\r
-\r
-/*\r
- This function handles DMA1 Stream 6 interrupt request for DAC2.\r
-*/\r
-\r
-void DMA1_Stream6_IRQHandler(void) {\r
- int i, j, sam;\r
- short signed_buf[DAC_BUF_SZ/2];\r
-\r
- GPIOE->ODR |= (1 << 2);\r
-\r
- /* Transfer half empty interrupt - refill first half */\r
-\r
- if(DMA_GetITStatus(DMA1_Stream6, DMA_IT_HTIF6) != RESET) {\r
- /* fill first half from fifo */\r
-\r
- if (fifo_read(dac2_fifo, signed_buf, DAC_BUF_SZ/2) == -1) {\r
- memset(signed_buf, 0, sizeof(short)*DAC_BUF_SZ/2);\r
- dac_underflow++;\r
- }\r
-\r
- /* convert to unsigned */\r
-\r
- for(i=0; i<DAC_BUF_SZ/2; i++) {\r
- sam = (int)(M*(float)signed_buf[i] + C);\r
- dac2_buf[i] = (unsigned short)sam;\r
- }\r
-\r
- /* Clear DMA Stream Transfer Complete interrupt pending bit */\r
-\r
- DMA_ClearITPendingBit(DMA1_Stream6, DMA_IT_HTIF6); \r
- }\r
-\r
- /* Transfer complete interrupt - refill 2nd half */\r
-\r
- if(DMA_GetITStatus(DMA1_Stream6, DMA_IT_TCIF6) != RESET) {\r
- /* fill second half from fifo */\r
-\r
- if (fifo_read(dac2_fifo, signed_buf, DAC_BUF_SZ/2) == -1) {\r
- memset(signed_buf, 0, sizeof(short)*DAC_BUF_SZ/2);\r
- dac_underflow++;\r
- }\r
-\r
- /* convert to unsigned */\r
-\r
- for(i=0, j=DAC_BUF_SZ/2; i<DAC_BUF_SZ/2; i++,j++) {\r
- sam = (int)(M*(float)signed_buf[i] + C);\r
- dac2_buf[j] = (unsigned short)sam;\r
- }\r
-\r
- /* Clear DMA Stream Transfer Complete interrupt pending bit */\r
-\r
- DMA_ClearITPendingBit(DMA1_Stream6, DMA_IT_TCIF6); \r
- }\r
-\r
- GPIOE->ODR &= ~(1 << 2);\r
-}\r
-\r
+/*---------------------------------------------------------------------------*\
+
+ FILE........: stm32f4_dac.c
+ AUTHOR......: David Rowe
+ DATE CREATED: 1 June 2013
+
+ DAC driver module for STM32F4. DAC1 is connected to pin PA4, DAC2
+ is connected to pin PA5.
+
+\*---------------------------------------------------------------------------*/
+
+/*
+ Copyright (C) 2013 David Rowe
+
+ All rights reserved.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License version 2.1, as
+ published by the Free Software Foundation. This program is
+ distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+ License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with this program; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+#include "stm32f4xx.h"
+#include "codec2_fifo.h"
+#include "stm32f4_dac.h"
+#include "debugblinky.h"
+
+/* write to these registers for 12 bit left aligned data, as per data sheet
+ make sure 4 least sig bits set to 0 */
+
+#define DAC_DHR12R1_ADDRESS 0x40007408
+#define DAC_DHR12R2_ADDRESS 0x40007414
+
+#define DAC_MAX 4096 /* maximum amplitude */
+
+/* y=mx+c mapping of samples16 bit shorts to DAC samples. Table: 74
+ of data sheet indicates With DAC buffer on, DAC range is limited to
+ 0x0E0 to 0xF1C at VREF+ = 3.6 V, we have Vref=3.3V which is close.
+ */
+
+#define M ((3868.0-224.0)/65536.0)
+#define C 2047.0
+
+static struct FIFO *dac1_fifo;
+static struct FIFO *dac2_fifo;
+
+static unsigned short dac1_buf[DAC_BUF_SZ];
+static unsigned short dac2_buf[DAC_BUF_SZ];
+
+static void tim6_config(void);
+static void dac1_config(void);
+static void dac2_config(void);
+
+int dac_underflow;
+
+void dac_open(int fifo_size) {
+
+ memset(dac1_buf, 32768, sizeof(short)*DAC_BUF_SZ);
+ memset(dac2_buf, 32768, sizeof(short)*DAC_BUF_SZ);
+
+ /* Create fifos */
+
+ dac1_fifo = fifo_create(fifo_size);
+ dac2_fifo = fifo_create(fifo_size);
+ assert(dac1_fifo != NULL);
+ assert(dac2_fifo != NULL);
+
+ /* Turn on the clocks we need -----------------------------------------------*/
+
+ /* DMA1 clock enable */
+ RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA1, ENABLE);
+ /* GPIOA clock enable (to be used with DAC) */
+ RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);
+ /* DAC Periph clock enable */
+ RCC_APB1PeriphClockCmd(RCC_APB1Periph_DAC, ENABLE);
+
+ /* GPIO Pin configuration DAC1->PA.4, DAC2->PA.5 configuration --------------*/
+
+ GPIO_InitTypeDef GPIO_InitStructure;
+ GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4 | GPIO_Pin_5;
+ GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;
+ GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
+ GPIO_Init(GPIOA, &GPIO_InitStructure);
+
+ /* Timer and DAC 1 & 2 Configuration ----------------------------------------*/
+
+ tim6_config();
+ dac1_config();
+ dac2_config();
+
+ init_debug_blinky();
+}
+
+/* Call these puppies to send samples to the DACs. For your
+ convenience they accept signed 16 bit samples. */
+
+int dac1_write(short buf[], int n) {
+ return fifo_write(dac1_fifo, buf, n);
+}
+
+int dac2_write(short buf[], int n) {
+ return fifo_write(dac2_fifo, buf, n);
+}
+
+int dac1_free() {
+ return fifo_free(dac1_fifo);
+}
+
+int dac2_free() {
+ return fifo_free(dac2_fifo);
+}
+
+static void tim6_config(void)
+{
+ TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
+
+ /* TIM6 Periph clock enable */
+ RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM6, ENABLE);
+
+ /* --------------------------------------------------------
+
+ TIM6 input clock (TIM6CLK) is set to 2 * APB1 clock (PCLK1), since
+ APB1 prescaler is different from 1 (see system_stm32f4xx.c and Fig
+ 13 clock tree figure in DM0031020.pdf).
+
+ Sample rate Fs = 2*PCLK1/TIM_ClockDivision
+ = (HCLK/2)/TIM_ClockDivision
+
+ ----------------------------------------------------------- */
+
+ /* Time base configuration */
+
+ TIM_TimeBaseStructInit(&TIM_TimeBaseStructure);
+ TIM_TimeBaseStructure.TIM_Period = 5250;
+ TIM_TimeBaseStructure.TIM_Prescaler = 0;
+ TIM_TimeBaseStructure.TIM_ClockDivision = 0;
+ TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
+ TIM_TimeBaseInit(TIM6, &TIM_TimeBaseStructure);
+
+ /* TIM6 TRGO selection */
+
+ TIM_SelectOutputTrigger(TIM6, TIM_TRGOSource_Update);
+
+ /* TIM6 enable counter */
+
+ TIM_Cmd(TIM6, ENABLE);
+}
+
+static void dac1_config(void)
+{
+ DAC_InitTypeDef DAC_InitStructure;
+ DMA_InitTypeDef DMA_InitStructure;
+ NVIC_InitTypeDef NVIC_InitStructure;
+
+ /* DAC channel 1 Configuration */
+
+ /*
+ This line fixed a bug that cost me 5 days, bad wave amplitude
+ value, and some STM32F4 periph library bugs caused triangle wave
+ geneartion to be enable resulting in a low level tone on the
+ SM1000, that we thought was caused by analog issues like layour
+ or power supply biasing
+ */
+ DAC_StructInit(&DAC_InitStructure);
+
+ DAC_InitStructure.DAC_Trigger = DAC_Trigger_T6_TRGO;
+ DAC_InitStructure.DAC_WaveGeneration = DAC_WaveGeneration_None;
+ DAC_InitStructure.DAC_OutputBuffer = DAC_OutputBuffer_Enable;
+ DAC_Init(DAC_Channel_1, &DAC_InitStructure);
+
+ /* DMA1_Stream5 channel7 configuration **************************************/
+ /* Table 35 page 219 of the monster data sheet */
+
+ DMA_DeInit(DMA1_Stream5);
+ DMA_InitStructure.DMA_Channel = DMA_Channel_7;
+ DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)DAC_DHR12R1_ADDRESS;
+ DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)dac1_buf;
+ DMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToPeripheral;
+ DMA_InitStructure.DMA_BufferSize = DAC_BUF_SZ;
+ DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
+ DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
+ DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
+ DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
+ DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
+ DMA_InitStructure.DMA_Priority = DMA_Priority_High;
+ DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable;
+ DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_HalfFull;
+ DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;
+ DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
+ DMA_Init(DMA1_Stream5, &DMA_InitStructure);
+
+ /* Enable DMA Half & Complete interrupts */
+
+ DMA_ITConfig(DMA1_Stream5, DMA_IT_TC | DMA_IT_HT, ENABLE);
+
+ /* Enable the DMA Stream IRQ Channel */
+
+ NVIC_InitStructure.NVIC_IRQChannel = DMA1_Stream5_IRQn;
+ NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
+ NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
+ NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
+ NVIC_Init(&NVIC_InitStructure);
+
+ /* Enable DMA1_Stream5 */
+
+ DMA_Cmd(DMA1_Stream5, ENABLE);
+
+ /* Enable DAC Channel 1 */
+
+ DAC_Cmd(DAC_Channel_1, ENABLE);
+
+ /* Enable DMA for DAC Channel 1 */
+
+ DAC_DMACmd(DAC_Channel_1, ENABLE);
+}
+
+static void dac2_config(void)
+{
+ DAC_InitTypeDef DAC_InitStructure;
+ DMA_InitTypeDef DMA_InitStructure;
+ NVIC_InitTypeDef NVIC_InitStructure;
+
+ /* DAC channel 2 Configuration (see notes in dac1_config() above) */
+
+ DAC_StructInit(&DAC_InitStructure);
+ DAC_InitStructure.DAC_Trigger = DAC_Trigger_T6_TRGO;
+ DAC_InitStructure.DAC_WaveGeneration = DAC_WaveGeneration_None;
+ DAC_InitStructure.DAC_OutputBuffer = DAC_OutputBuffer_Enable;
+ DAC_Init(DAC_Channel_2, &DAC_InitStructure);
+
+ /* DMA1_Stream6 channel7 configuration **************************************/
+
+ DMA_DeInit(DMA1_Stream6);
+ DMA_InitStructure.DMA_Channel = DMA_Channel_7;
+ DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)DAC_DHR12R2_ADDRESS;
+ DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)dac2_buf;
+ DMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToPeripheral;
+ DMA_InitStructure.DMA_BufferSize = DAC_BUF_SZ;
+ DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
+ DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
+ DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
+ DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
+ DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
+ DMA_InitStructure.DMA_Priority = DMA_Priority_High;
+ DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable;
+ DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_HalfFull;
+ DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;
+ DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
+ DMA_Init(DMA1_Stream6, &DMA_InitStructure);
+
+ /* Enable DMA Half & Complete interrupts */
+
+ DMA_ITConfig(DMA1_Stream6, DMA_IT_TC | DMA_IT_HT, ENABLE);
+
+ /* Enable the DMA Stream IRQ Channel */
+
+ NVIC_InitStructure.NVIC_IRQChannel = DMA1_Stream6_IRQn;
+ NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
+ NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
+ NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
+ NVIC_Init(&NVIC_InitStructure);
+
+ /* Enable DMA1_Stream6 */
+
+ DMA_Cmd(DMA1_Stream6, ENABLE);
+
+ /* Enable DAC Channel 2 */
+
+ DAC_Cmd(DAC_Channel_2, ENABLE);
+
+ /* Enable DMA for DAC Channel 2 */
+
+ DAC_DMACmd(DAC_Channel_2, ENABLE);
+
+}
+
+/******************************************************************************/
+/* STM32F4xx Peripherals Interrupt Handlers */
+/* Add here the Interrupt Handler for the used peripheral(s) (PPP), for the */
+/* available peripheral interrupt handler's name please refer to the startup */
+/* file (startup_stm32f40xx.s/startup_stm32f427x.s). */
+/******************************************************************************/
+
+/*
+ This function handles DMA1 Stream 5 interrupt request for DAC1.
+*/
+
+void DMA1_Stream5_IRQHandler(void) {
+ int i, j, sam;
+ short signed_buf[DAC_BUF_SZ/2];
+
+ GPIOE->ODR |= (1 << 1);
+
+ /* Transfer half empty interrupt - refill first half */
+
+ if(DMA_GetITStatus(DMA1_Stream5, DMA_IT_HTIF5) != RESET) {
+ /* fill first half from fifo */
+
+ if (fifo_read(dac1_fifo, signed_buf, DAC_BUF_SZ/2) == -1) {
+ memset(signed_buf, 0, sizeof(short)*DAC_BUF_SZ/2);
+ dac_underflow++;
+ }
+
+ /* convert to unsigned */
+
+ for(i=0; i<DAC_BUF_SZ/2; i++) {
+ sam = (int)(M*(float)signed_buf[i] + C);
+ dac1_buf[i] = (unsigned short)sam;
+ }
+
+ /* Clear DMA Stream Transfer Complete interrupt pending bit */
+
+ DMA_ClearITPendingBit(DMA1_Stream5, DMA_IT_HTIF5);
+ }
+
+ /* Transfer complete interrupt - refill 2nd half */
+
+ if(DMA_GetITStatus(DMA1_Stream5, DMA_IT_TCIF5) != RESET) {
+ /* fill second half from fifo */
+
+ if (fifo_read(dac1_fifo, signed_buf, DAC_BUF_SZ/2) == -1) {
+ memset(signed_buf, 0, sizeof(short)*DAC_BUF_SZ/2);
+ dac_underflow++;
+ }
+
+ /* convert to unsigned */
+
+ for(i=0, j=DAC_BUF_SZ/2; i<DAC_BUF_SZ/2; i++,j++) {
+ sam = (int)(M*(float)signed_buf[i] + C);
+ dac1_buf[j] = (unsigned short)sam;
+ }
+
+ /* Clear DMA Stream Transfer Complete interrupt pending bit */
+
+ DMA_ClearITPendingBit(DMA1_Stream5, DMA_IT_TCIF5);
+ }
+
+ GPIOE->ODR &= ~(1 << 1);
+}
+
+/*
+ This function handles DMA1 Stream 6 interrupt request for DAC2.
+*/
+
+void DMA1_Stream6_IRQHandler(void) {
+ int i, j, sam;
+ short signed_buf[DAC_BUF_SZ/2];
+
+ GPIOE->ODR |= (1 << 2);
+
+ /* Transfer half empty interrupt - refill first half */
+
+ if(DMA_GetITStatus(DMA1_Stream6, DMA_IT_HTIF6) != RESET) {
+ /* fill first half from fifo */
+
+ if (fifo_read(dac2_fifo, signed_buf, DAC_BUF_SZ/2) == -1) {
+ memset(signed_buf, 0, sizeof(short)*DAC_BUF_SZ/2);
+ dac_underflow++;
+ }
+
+ /* convert to unsigned */
+
+ for(i=0; i<DAC_BUF_SZ/2; i++) {
+ sam = (int)(M*(float)signed_buf[i] + C);
+ dac2_buf[i] = (unsigned short)sam;
+ }
+
+ /* Clear DMA Stream Transfer Complete interrupt pending bit */
+
+ DMA_ClearITPendingBit(DMA1_Stream6, DMA_IT_HTIF6);
+ }
+
+ /* Transfer complete interrupt - refill 2nd half */
+
+ if(DMA_GetITStatus(DMA1_Stream6, DMA_IT_TCIF6) != RESET) {
+ /* fill second half from fifo */
+
+ if (fifo_read(dac2_fifo, signed_buf, DAC_BUF_SZ/2) == -1) {
+ memset(signed_buf, 0, sizeof(short)*DAC_BUF_SZ/2);
+ dac_underflow++;
+ }
+
+ /* convert to unsigned */
+
+ for(i=0, j=DAC_BUF_SZ/2; i<DAC_BUF_SZ/2; i++,j++) {
+ sam = (int)(M*(float)signed_buf[i] + C);
+ dac2_buf[j] = (unsigned short)sam;
+ }
+
+ /* Clear DMA Stream Transfer Complete interrupt pending bit */
+
+ DMA_ClearITPendingBit(DMA1_Stream6, DMA_IT_TCIF6);
+ }
+
+ GPIOE->ODR &= ~(1 << 2);
+}
+
-/*---------------------------------------------------------------------------*\\r
-\r
- FILE........: stm32f4_dac.c\r
- AUTHOR......: David Rowe\r
- DATE CREATED: 1 June 2013\r
-\r
- DAC driver module for STM32F4. DAC1 if fixed at Fs of 2Mhz.\r
-\r
-\*---------------------------------------------------------------------------*/\r
-\r
-/*\r
- Copyright (C) 2013 David Rowe\r
-\r
- All rights reserved.\r
-\r
- This program is free software; you can redistribute it and/or modify\r
- it under the terms of the GNU Lesser General Public License version 2.1, as\r
- published by the Free Software Foundation. This program is\r
- distributed in the hope that it will be useful, but WITHOUT ANY\r
- WARRANTY; without even the implied warranty of MERCHANTABILITY or\r
- FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public\r
- License for more details.\r
-\r
- You should have received a copy of the GNU Lesser General Public License\r
- along with this program; if not, see <http://www.gnu.org/licenses/>.\r
-*/\r
-\r
-#include <assert.h>\r
-#include <stdlib.h>\r
-#include <string.h>\r
-#include "stm32f4xx.h"\r
-#include "codec2_fifo.h"\r
-#include "stm32f4_dacduc.h"\r
-#include "debugblinky.h"\r
- \r
-/* write to these registers for 12 bit left aligned data, as per data sheet \r
- make sure 4 least sig bits set to 0 */\r
-\r
-#define DAC_DHR12R1_ADDRESS 0x40007408\r
-#define DAC_DHR12R2_ADDRESS 0x40007414\r
-\r
-#define DAC_MAX 4096 /* maximum amplitude */\r
-\r
-/* y=mx+c mapping of samples16 bit shorts to DAC samples. Table: 74\r
- of data sheet indicates With DAC buffer on, DAC range is limited to\r
- 0x0E0 to 0xF1C at VREF+ = 3.6 V, we have Vref=3.3V which is close.\r
- */\r
-\r
-#define M ((3868.0-224.0)/65536.0)\r
-#define C 2047.0\r
-\r
-\r
-static struct FIFO *dac1_fifo;\r
-static struct FIFO *dac2_fifo;\r
-\r
-static unsigned short dac1_buf[DAC_DUC_BUF_SZ];\r
-static unsigned short dac2_buf[DAC_BUF_SZ];\r
-\r
-static void tim6_config(void);\r
-static void tim7_config(void);\r
-static void dac1_config(void);\r
-static void dac2_config(void);\r
-\r
-int dac_underflow;\r
-\r
-void fast_dac_open(int dac1_fifo_size,int dac2_fifo_size) {\r
-\r
- memset(dac1_buf, 32768, sizeof(short)*DAC_DUC_BUF_SZ);\r
- memset(dac2_buf, 32768, sizeof(short)*DAC_BUF_SZ);\r
-\r
- /* Create fifos */\r
-\r
- dac1_fifo = fifo_create(dac1_fifo_size);\r
- dac2_fifo = fifo_create(dac2_fifo_size);\r
- assert(dac1_fifo != NULL);\r
- assert(dac2_fifo != NULL);\r
-\r
- /* Turn on the clocks we need -----------------------------------------------*/\r
-\r
- /* DMA1 clock enable */\r
- RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA1, ENABLE);\r
- /* GPIOA clock enable (to be used with DAC) */\r
- RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE); \r
- /* DAC Periph clock enable */\r
- RCC_APB1PeriphClockCmd(RCC_APB1Periph_DAC, ENABLE);\r
-\r
- /* GPIO Pin configuration DAC1->PA.4, DAC2->PA.5 configuration --------------*/\r
-\r
- GPIO_InitTypeDef GPIO_InitStructure;\r
- GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4 | GPIO_Pin_5;\r
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;\r
- GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;\r
- GPIO_Init(GPIOA, &GPIO_InitStructure);\r
-\r
- /* Timer and DAC 1 & 2 Configuration ----------------------------------------*/\r
- tim7_config();\r
- tim6_config(); \r
- dac1_config();\r
- dac2_config();\r
-\r
- init_debug_blinky();\r
-}\r
-\r
-\r
-/* Call these puppies to send samples to the DACs. For your\r
- convenience they accept signed 16 bit samples. */\r
-\r
-int dac1_write(short buf[], int n) { \r
- return fifo_write(dac1_fifo, buf, n);\r
-}\r
-\r
-int dac2_write(short buf[], int n) { \r
- return fifo_write(dac2_fifo, buf, n);\r
-}\r
-\r
-static void tim6_config(void)\r
-{\r
- TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;\r
-\r
- /* TIM6 Periph clock enable */\r
- RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM6, ENABLE);\r
- \r
- /* --------------------------------------------------------\r
- \r
- TIM6 input clock (TIM6CLK) is set to 2 * APB1 clock (PCLK1), since\r
- APB1 prescaler is different from 1 (see system_stm32f4xx.c and Fig\r
- 13 clock tree figure in DM0031020.pdf).\r
-\r
- Sample rate Fs = 2*PCLK1/TIM_ClockDivision \r
- = (HCLK/2)/TIM_ClockDivision\r
- \r
- ----------------------------------------------------------- */\r
-\r
- /* Time base configuration */\r
-\r
- TIM_TimeBaseStructInit(&TIM_TimeBaseStructure); \r
- TIM_TimeBaseStructure.TIM_Period = 5250; \r
- TIM_TimeBaseStructure.TIM_Prescaler = 0; \r
- TIM_TimeBaseStructure.TIM_ClockDivision = 0; \r
- TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; \r
- TIM_TimeBaseInit(TIM6, &TIM_TimeBaseStructure);\r
-\r
- /* TIM6 TRGO selection */\r
-\r
- TIM_SelectOutputTrigger(TIM6, TIM_TRGOSource_Update);\r
- \r
- /* TIM6 enable counter */\r
-\r
- TIM_Cmd(TIM6, ENABLE);\r
-}\r
-\r
-/* Sets up tim7 to run at a high sample rate */\r
-void tim7_config(void)\r
-{\r
- /* Set up tim7 */\r
-\r
-\r
- TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;\r
-\r
- /* TIM7 Periph clock enable */\r
- RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM7, ENABLE);\r
- \r
- /* --------------------------------------------------------\r
-\r
- \r
- TIM7 input clock (TIM7CLK) is set to 2 * APB1 clock (PCLK1), since\r
- APB1 prescaler is different from 1 (see system_stm32f4xx.c and Fig\r
- 13 clock tree figure in DM0031020.pdf).\r
-\r
- Sample rate Fs = 2*PCLK1/TIM_ClockDivision \r
- = (HCLK/2)/TIM_ClockDivision\r
- \r
- ----------------------------------------------------------- */\r
-\r
- /* Time base configuration */\r
-\r
- TIM_TimeBaseStructInit(&TIM_TimeBaseStructure); \r
- TIM_TimeBaseStructure.TIM_Period = 41; \r
- TIM_TimeBaseStructure.TIM_Prescaler = 0; \r
- TIM_TimeBaseStructure.TIM_ClockDivision = 0; \r
- TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; \r
- TIM_TimeBaseInit(TIM7, &TIM_TimeBaseStructure);\r
-\r
- /* TIM7 TRGO selection */\r
-\r
- TIM_SelectOutputTrigger(TIM7, TIM_TRGOSource_Update);\r
- \r
- /* TIM7 enable counter */\r
-\r
- TIM_Cmd(TIM7, ENABLE);\r
-}\r
-\r
-static void dac1_config(void)\r
-{\r
- DAC_InitTypeDef DAC_InitStructure;\r
- DMA_InitTypeDef DMA_InitStructure;\r
- NVIC_InitTypeDef NVIC_InitStructure;\r
- \r
- /* DAC channel 1 Configuration */\r
-\r
- /* \r
- This line fixed a bug that cost me 5 days, bad wave amplitude\r
- value, and some STM32F4 periph library bugs caused triangle wave\r
- geneartion to be enable resulting in a low level tone on the\r
- SM1000, that we thought was caused by analog issues like layour\r
- or power supply biasing\r
- */\r
- DAC_StructInit(&DAC_InitStructure); \r
-\r
- DAC_InitStructure.DAC_Trigger = DAC_Trigger_T7_TRGO; \r
- DAC_InitStructure.DAC_WaveGeneration = DAC_WaveGeneration_None;\r
-\r
- /*External buffering is needed to get nice square samples at Fs=2Mhz. See DM00129215.pdf */\r
- DAC_InitStructure.DAC_OutputBuffer = DAC_OutputBuffer_Disable;\r
- DAC_Init(DAC_Channel_1, &DAC_InitStructure);\r
-\r
- /* DMA1_Stream5 channel7 configuration **************************************/\r
- /* Table 35 page 219 of the monster data sheet */\r
-\r
- DMA_DeInit(DMA1_Stream5);\r
- DMA_InitStructure.DMA_Channel = DMA_Channel_7; \r
- DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)DAC_DHR12R1_ADDRESS;\r
- DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)dac1_buf;\r
- DMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToPeripheral;\r
- DMA_InitStructure.DMA_BufferSize = DAC_DUC_BUF_SZ;\r
- DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;\r
- DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;\r
- DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;\r
- DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;\r
- DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;\r
- DMA_InitStructure.DMA_Priority = DMA_Priority_High;\r
- DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable; \r
- DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_HalfFull;\r
- DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;\r
- DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;\r
- DMA_Init(DMA1_Stream5, &DMA_InitStructure);\r
-\r
- /* Enable DMA Half & Complete interrupts */\r
-\r
- DMA_ITConfig(DMA1_Stream5, DMA_IT_TC | DMA_IT_HT, ENABLE);\r
-\r
- /* Enable the DMA Stream IRQ Channel */\r
-\r
- NVIC_InitStructure.NVIC_IRQChannel = DMA1_Stream5_IRQn;\r
- NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;\r
- NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;\r
- NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;\r
- NVIC_Init(&NVIC_InitStructure); \r
-\r
- /* Enable DMA1_Stream5 */\r
-\r
- DMA_Cmd(DMA1_Stream5, ENABLE);\r
-\r
- /* Enable DAC Channel 1 */\r
-\r
- DAC_Cmd(DAC_Channel_1, ENABLE);\r
-\r
- /* Enable DMA for DAC Channel 1 */\r
-\r
- DAC_DMACmd(DAC_Channel_1, ENABLE);\r
-}\r
-\r
-static void dac2_config(void)\r
-{\r
- DAC_InitTypeDef DAC_InitStructure;\r
- DMA_InitTypeDef DMA_InitStructure;\r
- NVIC_InitTypeDef NVIC_InitStructure;\r
- \r
- /* DAC channel 2 Configuration (see notes in dac1_config() above) */\r
-\r
- DAC_StructInit(&DAC_InitStructure);\r
- DAC_InitStructure.DAC_Trigger = DAC_Trigger_T6_TRGO;\r
- DAC_InitStructure.DAC_WaveGeneration = DAC_WaveGeneration_None;\r
- DAC_InitStructure.DAC_OutputBuffer = DAC_OutputBuffer_Enable;\r
- DAC_Init(DAC_Channel_2, &DAC_InitStructure);\r
-\r
- /* DMA1_Stream6 channel7 configuration **************************************/\r
-\r
- DMA_DeInit(DMA1_Stream6);\r
- DMA_InitStructure.DMA_Channel = DMA_Channel_7; \r
- DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)DAC_DHR12R2_ADDRESS;\r
- DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)dac2_buf;\r
- DMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToPeripheral;\r
- DMA_InitStructure.DMA_BufferSize = DAC_BUF_SZ;\r
- DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;\r
- DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;\r
- DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;\r
- DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;\r
- DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;\r
- DMA_InitStructure.DMA_Priority = DMA_Priority_High;\r
- DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable; \r
- DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_HalfFull;\r
- DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;\r
- DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;\r
- DMA_Init(DMA1_Stream6, &DMA_InitStructure);\r
-\r
- /* Enable DMA Half & Complete interrupts */\r
-\r
- DMA_ITConfig(DMA1_Stream6, DMA_IT_TC | DMA_IT_HT, ENABLE);\r
-\r
- /* Enable the DMA Stream IRQ Channel */\r
-\r
- NVIC_InitStructure.NVIC_IRQChannel = DMA1_Stream6_IRQn;\r
- NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;\r
- NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;\r
- NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;\r
- NVIC_Init(&NVIC_InitStructure); \r
-\r
- /* Enable DMA1_Stream6 */\r
-\r
- DMA_Cmd(DMA1_Stream6, ENABLE);\r
-\r
- /* Enable DAC Channel 2 */\r
-\r
- DAC_Cmd(DAC_Channel_2, ENABLE);\r
-\r
- /* Enable DMA for DAC Channel 2 */\r
-\r
- DAC_DMACmd(DAC_Channel_2, ENABLE);\r
-\r
-}\r
-\r
-/******************************************************************************/\r
-/* STM32F4xx Peripherals Interrupt Handlers */\r
-/* Add here the Interrupt Handler for the used peripheral(s) (PPP), for the */\r
-/* available peripheral interrupt handler's name please refer to the startup */\r
-/* file (startup_stm32f40xx.s/startup_stm32f427x.s). */\r
-/******************************************************************************/\r
-\r
-/*\r
- This function handles DMA1 Stream 5 interrupt request for DAC1.\r
-*/\r
-\r
-void DMA1_Stream5_IRQHandler(void) {\r
- GPIOE->ODR |= (1 << 1);\r
-\r
- /* Transfer half empty interrupt - refill first half */\r
-\r
- if(DMA_GetITStatus(DMA1_Stream5, DMA_IT_HTIF5) != RESET) {\r
- /* fill first half from fifo */\r
- fifo_read(dac1_fifo, (short*)dac1_buf, DAC_DUC_BUF_SZ/2);\r
-\r
- /* Clear DMA Stream Transfer Complete interrupt pending bit */\r
- DMA_ClearITPendingBit(DMA1_Stream5, DMA_IT_HTIF5); \r
- }\r
-\r
- /* Transfer complete interrupt - refill 2nd half */\r
-\r
- if(DMA_GetITStatus(DMA1_Stream5, DMA_IT_TCIF5) != RESET) {\r
- /* fill second half from fifo */\r
- fifo_read(dac1_fifo, (short*)(dac1_buf+DAC_DUC_BUF_SZ/2), DAC_DUC_BUF_SZ/2);\r
-\r
- /* Clear DMA Stream Transfer Complete interrupt pending bit */\r
- DMA_ClearITPendingBit(DMA1_Stream5, DMA_IT_TCIF5); \r
- }\r
-\r
- GPIOE->ODR &= ~(1 << 1);\r
-}\r
-\r
-/*\r
- This function handles DMA1 Stream 6 interrupt request for DAC2.\r
-*/\r
-\r
-void DMA1_Stream6_IRQHandler(void) {\r
- int i, j, sam;\r
- short signed_buf[DAC_BUF_SZ/2];\r
-\r
- GPIOE->ODR |= (1 << 2);\r
-\r
- /* Transfer half empty interrupt - refill first half */\r
-\r
- if(DMA_GetITStatus(DMA1_Stream6, DMA_IT_HTIF6) != RESET) {\r
- /* fill first half from fifo */\r
-\r
- if (fifo_read(dac2_fifo, signed_buf, DAC_BUF_SZ/2) == -1) {\r
- memset(signed_buf, 0, sizeof(short)*DAC_BUF_SZ/2);\r
- dac_underflow++;\r
- }\r
-\r
- /* convert to unsigned */\r
-\r
- for(i=0; i<DAC_BUF_SZ/2; i++) {\r
- sam = (int)(M*(float)signed_buf[i] + C);\r
- dac2_buf[i] = (unsigned short)sam;\r
- }\r
-\r
- /* Clear DMA Stream Transfer Complete interrupt pending bit */\r
-\r
- DMA_ClearITPendingBit(DMA1_Stream6, DMA_IT_HTIF6); \r
- }\r
-\r
- /* Transfer complete interrupt - refill 2nd half */\r
-\r
- if(DMA_GetITStatus(DMA1_Stream6, DMA_IT_TCIF6) != RESET) {\r
- /* fill second half from fifo */\r
-\r
- if (fifo_read(dac2_fifo, signed_buf, DAC_BUF_SZ/2) == -1) {\r
- memset(signed_buf, 0, sizeof(short)*DAC_BUF_SZ/2);\r
- dac_underflow++;\r
- }\r
-\r
- /* convert to unsigned */\r
-\r
- for(i=0, j=DAC_BUF_SZ/2; i<DAC_BUF_SZ/2; i++,j++) {\r
- sam = (int)(M*(float)signed_buf[i] + C);\r
- dac2_buf[j] = (unsigned short)sam;\r
- }\r
-\r
- /* Clear DMA Stream Transfer Complete interrupt pending bit */\r
-\r
- DMA_ClearITPendingBit(DMA1_Stream6, DMA_IT_TCIF6); \r
- }\r
-\r
- GPIOE->ODR &= ~(1 << 2);\r
-}\r
-\r
+/*---------------------------------------------------------------------------*\
+
+ FILE........: stm32f4_dac.c
+ AUTHOR......: David Rowe
+ DATE CREATED: 1 June 2013
+
+ DAC driver module for STM32F4. DAC1 if fixed at Fs of 2Mhz.
+
+\*---------------------------------------------------------------------------*/
+
+/*
+ Copyright (C) 2013 David Rowe
+
+ All rights reserved.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License version 2.1, as
+ published by the Free Software Foundation. This program is
+ distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+ License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with this program; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+#include "stm32f4xx.h"
+#include "codec2_fifo.h"
+#include "stm32f4_dacduc.h"
+#include "debugblinky.h"
+
+/* write to these registers for 12 bit left aligned data, as per data sheet
+ make sure 4 least sig bits set to 0 */
+
+#define DAC_DHR12R1_ADDRESS 0x40007408
+#define DAC_DHR12R2_ADDRESS 0x40007414
+
+#define DAC_MAX 4096 /* maximum amplitude */
+
+/* y=mx+c mapping of samples16 bit shorts to DAC samples. Table: 74
+ of data sheet indicates With DAC buffer on, DAC range is limited to
+ 0x0E0 to 0xF1C at VREF+ = 3.6 V, we have Vref=3.3V which is close.
+ */
+
+#define M ((3868.0-224.0)/65536.0)
+#define C 2047.0
+
+
+static struct FIFO *dac1_fifo;
+static struct FIFO *dac2_fifo;
+
+static unsigned short dac1_buf[DAC_DUC_BUF_SZ];
+static unsigned short dac2_buf[DAC_BUF_SZ];
+
+static void tim6_config(void);
+static void tim7_config(void);
+static void dac1_config(void);
+static void dac2_config(void);
+
+int dac_underflow;
+
+void fast_dac_open(int dac1_fifo_size,int dac2_fifo_size) {
+
+ memset(dac1_buf, 32768, sizeof(short)*DAC_DUC_BUF_SZ);
+ memset(dac2_buf, 32768, sizeof(short)*DAC_BUF_SZ);
+
+ /* Create fifos */
+
+ dac1_fifo = fifo_create(dac1_fifo_size);
+ dac2_fifo = fifo_create(dac2_fifo_size);
+ assert(dac1_fifo != NULL);
+ assert(dac2_fifo != NULL);
+
+ /* Turn on the clocks we need -----------------------------------------------*/
+
+ /* DMA1 clock enable */
+ RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA1, ENABLE);
+ /* GPIOA clock enable (to be used with DAC) */
+ RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);
+ /* DAC Periph clock enable */
+ RCC_APB1PeriphClockCmd(RCC_APB1Periph_DAC, ENABLE);
+
+ /* GPIO Pin configuration DAC1->PA.4, DAC2->PA.5 configuration --------------*/
+
+ GPIO_InitTypeDef GPIO_InitStructure;
+ GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4 | GPIO_Pin_5;
+ GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;
+ GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
+ GPIO_Init(GPIOA, &GPIO_InitStructure);
+
+ /* Timer and DAC 1 & 2 Configuration ----------------------------------------*/
+ tim7_config();
+ tim6_config();
+ dac1_config();
+ dac2_config();
+
+ init_debug_blinky();
+}
+
+
+/* Call these puppies to send samples to the DACs. For your
+ convenience they accept signed 16 bit samples. */
+
+int dac1_write(short buf[], int n) {
+ return fifo_write(dac1_fifo, buf, n);
+}
+
+int dac2_write(short buf[], int n) {
+ return fifo_write(dac2_fifo, buf, n);
+}
+
+static void tim6_config(void)
+{
+ TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
+
+ /* TIM6 Periph clock enable */
+ RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM6, ENABLE);
+
+ /* --------------------------------------------------------
+
+ TIM6 input clock (TIM6CLK) is set to 2 * APB1 clock (PCLK1), since
+ APB1 prescaler is different from 1 (see system_stm32f4xx.c and Fig
+ 13 clock tree figure in DM0031020.pdf).
+
+ Sample rate Fs = 2*PCLK1/TIM_ClockDivision
+ = (HCLK/2)/TIM_ClockDivision
+
+ ----------------------------------------------------------- */
+
+ /* Time base configuration */
+
+ TIM_TimeBaseStructInit(&TIM_TimeBaseStructure);
+ TIM_TimeBaseStructure.TIM_Period = 5250;
+ TIM_TimeBaseStructure.TIM_Prescaler = 0;
+ TIM_TimeBaseStructure.TIM_ClockDivision = 0;
+ TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
+ TIM_TimeBaseInit(TIM6, &TIM_TimeBaseStructure);
+
+ /* TIM6 TRGO selection */
+
+ TIM_SelectOutputTrigger(TIM6, TIM_TRGOSource_Update);
+
+ /* TIM6 enable counter */
+
+ TIM_Cmd(TIM6, ENABLE);
+}
+
+/* Sets up tim7 to run at a high sample rate */
+void tim7_config(void)
+{
+ /* Set up tim7 */
+
+
+ TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
+
+ /* TIM7 Periph clock enable */
+ RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM7, ENABLE);
+
+ /* --------------------------------------------------------
+
+
+ TIM7 input clock (TIM7CLK) is set to 2 * APB1 clock (PCLK1), since
+ APB1 prescaler is different from 1 (see system_stm32f4xx.c and Fig
+ 13 clock tree figure in DM0031020.pdf).
+
+ Sample rate Fs = 2*PCLK1/TIM_ClockDivision
+ = (HCLK/2)/TIM_ClockDivision
+
+ ----------------------------------------------------------- */
+
+ /* Time base configuration */
+
+ TIM_TimeBaseStructInit(&TIM_TimeBaseStructure);
+ TIM_TimeBaseStructure.TIM_Period = 41;
+ TIM_TimeBaseStructure.TIM_Prescaler = 0;
+ TIM_TimeBaseStructure.TIM_ClockDivision = 0;
+ TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
+ TIM_TimeBaseInit(TIM7, &TIM_TimeBaseStructure);
+
+ /* TIM7 TRGO selection */
+
+ TIM_SelectOutputTrigger(TIM7, TIM_TRGOSource_Update);
+
+ /* TIM7 enable counter */
+
+ TIM_Cmd(TIM7, ENABLE);
+}
+
+static void dac1_config(void)
+{
+ DAC_InitTypeDef DAC_InitStructure;
+ DMA_InitTypeDef DMA_InitStructure;
+ NVIC_InitTypeDef NVIC_InitStructure;
+
+ /* DAC channel 1 Configuration */
+
+ /*
+ This line fixed a bug that cost me 5 days, bad wave amplitude
+ value, and some STM32F4 periph library bugs caused triangle wave
+ geneartion to be enable resulting in a low level tone on the
+ SM1000, that we thought was caused by analog issues like layour
+ or power supply biasing
+ */
+ DAC_StructInit(&DAC_InitStructure);
+
+ DAC_InitStructure.DAC_Trigger = DAC_Trigger_T7_TRGO;
+ DAC_InitStructure.DAC_WaveGeneration = DAC_WaveGeneration_None;
+
+ /*External buffering is needed to get nice square samples at Fs=2Mhz. See DM00129215.pdf */
+ DAC_InitStructure.DAC_OutputBuffer = DAC_OutputBuffer_Disable;
+ DAC_Init(DAC_Channel_1, &DAC_InitStructure);
+
+ /* DMA1_Stream5 channel7 configuration **************************************/
+ /* Table 35 page 219 of the monster data sheet */
+
+ DMA_DeInit(DMA1_Stream5);
+ DMA_InitStructure.DMA_Channel = DMA_Channel_7;
+ DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)DAC_DHR12R1_ADDRESS;
+ DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)dac1_buf;
+ DMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToPeripheral;
+ DMA_InitStructure.DMA_BufferSize = DAC_DUC_BUF_SZ;
+ DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
+ DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
+ DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
+ DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
+ DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
+ DMA_InitStructure.DMA_Priority = DMA_Priority_High;
+ DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable;
+ DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_HalfFull;
+ DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;
+ DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
+ DMA_Init(DMA1_Stream5, &DMA_InitStructure);
+
+ /* Enable DMA Half & Complete interrupts */
+
+ DMA_ITConfig(DMA1_Stream5, DMA_IT_TC | DMA_IT_HT, ENABLE);
+
+ /* Enable the DMA Stream IRQ Channel */
+
+ NVIC_InitStructure.NVIC_IRQChannel = DMA1_Stream5_IRQn;
+ NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
+ NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
+ NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
+ NVIC_Init(&NVIC_InitStructure);
+
+ /* Enable DMA1_Stream5 */
+
+ DMA_Cmd(DMA1_Stream5, ENABLE);
+
+ /* Enable DAC Channel 1 */
+
+ DAC_Cmd(DAC_Channel_1, ENABLE);
+
+ /* Enable DMA for DAC Channel 1 */
+
+ DAC_DMACmd(DAC_Channel_1, ENABLE);
+}
+
+static void dac2_config(void)
+{
+ DAC_InitTypeDef DAC_InitStructure;
+ DMA_InitTypeDef DMA_InitStructure;
+ NVIC_InitTypeDef NVIC_InitStructure;
+
+ /* DAC channel 2 Configuration (see notes in dac1_config() above) */
+
+ DAC_StructInit(&DAC_InitStructure);
+ DAC_InitStructure.DAC_Trigger = DAC_Trigger_T6_TRGO;
+ DAC_InitStructure.DAC_WaveGeneration = DAC_WaveGeneration_None;
+ DAC_InitStructure.DAC_OutputBuffer = DAC_OutputBuffer_Enable;
+ DAC_Init(DAC_Channel_2, &DAC_InitStructure);
+
+ /* DMA1_Stream6 channel7 configuration **************************************/
+
+ DMA_DeInit(DMA1_Stream6);
+ DMA_InitStructure.DMA_Channel = DMA_Channel_7;
+ DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)DAC_DHR12R2_ADDRESS;
+ DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)dac2_buf;
+ DMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToPeripheral;
+ DMA_InitStructure.DMA_BufferSize = DAC_BUF_SZ;
+ DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
+ DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
+ DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
+ DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
+ DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
+ DMA_InitStructure.DMA_Priority = DMA_Priority_High;
+ DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable;
+ DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_HalfFull;
+ DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;
+ DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
+ DMA_Init(DMA1_Stream6, &DMA_InitStructure);
+
+ /* Enable DMA Half & Complete interrupts */
+
+ DMA_ITConfig(DMA1_Stream6, DMA_IT_TC | DMA_IT_HT, ENABLE);
+
+ /* Enable the DMA Stream IRQ Channel */
+
+ NVIC_InitStructure.NVIC_IRQChannel = DMA1_Stream6_IRQn;
+ NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
+ NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
+ NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
+ NVIC_Init(&NVIC_InitStructure);
+
+ /* Enable DMA1_Stream6 */
+
+ DMA_Cmd(DMA1_Stream6, ENABLE);
+
+ /* Enable DAC Channel 2 */
+
+ DAC_Cmd(DAC_Channel_2, ENABLE);
+
+ /* Enable DMA for DAC Channel 2 */
+
+ DAC_DMACmd(DAC_Channel_2, ENABLE);
+
+}
+
+/******************************************************************************/
+/* STM32F4xx Peripherals Interrupt Handlers */
+/* Add here the Interrupt Handler for the used peripheral(s) (PPP), for the */
+/* available peripheral interrupt handler's name please refer to the startup */
+/* file (startup_stm32f40xx.s/startup_stm32f427x.s). */
+/******************************************************************************/
+
+/*
+ This function handles DMA1 Stream 5 interrupt request for DAC1.
+*/
+
+void DMA1_Stream5_IRQHandler(void) {
+ GPIOE->ODR |= (1 << 1);
+
+ /* Transfer half empty interrupt - refill first half */
+
+ if(DMA_GetITStatus(DMA1_Stream5, DMA_IT_HTIF5) != RESET) {
+ /* fill first half from fifo */
+ fifo_read(dac1_fifo, (short*)dac1_buf, DAC_DUC_BUF_SZ/2);
+
+ /* Clear DMA Stream Transfer Complete interrupt pending bit */
+ DMA_ClearITPendingBit(DMA1_Stream5, DMA_IT_HTIF5);
+ }
+
+ /* Transfer complete interrupt - refill 2nd half */
+
+ if(DMA_GetITStatus(DMA1_Stream5, DMA_IT_TCIF5) != RESET) {
+ /* fill second half from fifo */
+ fifo_read(dac1_fifo, (short*)(dac1_buf+DAC_DUC_BUF_SZ/2), DAC_DUC_BUF_SZ/2);
+
+ /* Clear DMA Stream Transfer Complete interrupt pending bit */
+ DMA_ClearITPendingBit(DMA1_Stream5, DMA_IT_TCIF5);
+ }
+
+ GPIOE->ODR &= ~(1 << 1);
+}
+
+/*
+ This function handles DMA1 Stream 6 interrupt request for DAC2.
+*/
+
+void DMA1_Stream6_IRQHandler(void) {
+ int i, j, sam;
+ short signed_buf[DAC_BUF_SZ/2];
+
+ GPIOE->ODR |= (1 << 2);
+
+ /* Transfer half empty interrupt - refill first half */
+
+ if(DMA_GetITStatus(DMA1_Stream6, DMA_IT_HTIF6) != RESET) {
+ /* fill first half from fifo */
+
+ if (fifo_read(dac2_fifo, signed_buf, DAC_BUF_SZ/2) == -1) {
+ memset(signed_buf, 0, sizeof(short)*DAC_BUF_SZ/2);
+ dac_underflow++;
+ }
+
+ /* convert to unsigned */
+
+ for(i=0; i<DAC_BUF_SZ/2; i++) {
+ sam = (int)(M*(float)signed_buf[i] + C);
+ dac2_buf[i] = (unsigned short)sam;
+ }
+
+ /* Clear DMA Stream Transfer Complete interrupt pending bit */
+
+ DMA_ClearITPendingBit(DMA1_Stream6, DMA_IT_HTIF6);
+ }
+
+ /* Transfer complete interrupt - refill 2nd half */
+
+ if(DMA_GetITStatus(DMA1_Stream6, DMA_IT_TCIF6) != RESET) {
+ /* fill second half from fifo */
+
+ if (fifo_read(dac2_fifo, signed_buf, DAC_BUF_SZ/2) == -1) {
+ memset(signed_buf, 0, sizeof(short)*DAC_BUF_SZ/2);
+ dac_underflow++;
+ }
+
+ /* convert to unsigned */
+
+ for(i=0, j=DAC_BUF_SZ/2; i<DAC_BUF_SZ/2; i++,j++) {
+ sam = (int)(M*(float)signed_buf[i] + C);
+ dac2_buf[j] = (unsigned short)sam;
+ }
+
+ /* Clear DMA Stream Transfer Complete interrupt pending bit */
+
+ DMA_ClearITPendingBit(DMA1_Stream6, DMA_IT_TCIF6);
+ }
+
+ GPIOE->ODR &= ~(1 << 2);
+}
+
-/**\r
- ******************************************************************************\r
- * @file system_stm32f4xx.c\r
- * @author MCD Application Team\r
- * @version V1.0.1\r
- * @date 10-July-2012\r
- * @brief CMSIS Cortex-M4 Device Peripheral Access Layer System Source File.\r
- * This file contains the system clock configuration for STM32F4xx devices,\r
- * and is generated by the clock configuration tool\r
- * stm32f4xx_Clock_Configuration_V1.0.1.xls\r
- *\r
- * 1. This file provides two functions and one global variable to be called from\r
- * user application:\r
- * - SystemInit(): Setups the system clock (System clock source, PLL Multiplier\r
- * and Divider factors, AHB/APBx prescalers and Flash settings),\r
- * depending on the configuration made in the clock xls tool.\r
- * This function is called at startup just after reset and\r
- * before branch to main program. This call is made inside\r
- * the "startup_stm32f4xx.s" file.\r
- *\r
- * - SystemCoreClock variable: Contains the core clock (HCLK), it can be used\r
- * by the user application to setup the SysTick\r
- * timer or configure other parameters.\r
- *\r
- * - SystemCoreClockUpdate(): Updates the variable SystemCoreClock and must\r
- * be called whenever the core clock is changed\r
- * during program execution.\r
- *\r
- * 2. After each device reset the HSI (16 MHz) is used as system clock source.\r
- * Then SystemInit() function is called, in "startup_stm32f4xx.s" file, to\r
- * configure the system clock before to branch to main program.\r
- *\r
- * 3. If the system clock source selected by user fails to startup, the SystemInit()\r
- * function will do nothing and HSI still used as system clock source. User can\r
- * add some code to deal with this issue inside the SetSysClock() function.\r
- *\r
- * 4. The default value of HSE crystal is set to 25MHz, refer to "HSE_VALUE" define\r
- * in "stm32f4xx.h" file. When HSE is used as system clock source, directly or\r
- * through PLL, and you are using different crystal you have to adapt the HSE\r
- * value to your own configuration.\r
- *\r
- * 5. This file configures the system clock as follows:\r
- *=============================================================================\r
- *=============================================================================\r
- * Supported STM32F4xx device revision | Rev A\r
- *-----------------------------------------------------------------------------\r
- * System Clock source | PLL (HSE)\r
- *-----------------------------------------------------------------------------\r
- * SYSCLK(Hz) | 168000000\r
- *-----------------------------------------------------------------------------\r
- * HCLK(Hz) | 168000000\r
- *-----------------------------------------------------------------------------\r
- * AHB Prescaler | 1\r
- *-----------------------------------------------------------------------------\r
- * APB1 Prescaler | 4\r
- *-----------------------------------------------------------------------------\r
- * APB2 Prescaler | 2\r
- *-----------------------------------------------------------------------------\r
- * HSE Frequency(Hz) | 8000000\r
- *-----------------------------------------------------------------------------\r
- * PLL_M | 8\r
- *-----------------------------------------------------------------------------\r
- * PLL_N | 336\r
- *-----------------------------------------------------------------------------\r
- * PLL_P | 2\r
- *-----------------------------------------------------------------------------\r
- * PLL_Q | 7\r
- *-----------------------------------------------------------------------------\r
- * PLLI2S_N | 352\r
- *-----------------------------------------------------------------------------\r
- * PLLI2S_R | 2\r
- *-----------------------------------------------------------------------------\r
- * I2S input clock(Hz) | 176000000\r
- * |\r
- * To achieve the following I2S config: |\r
- * - Master clock output (MCKO): OFF |\r
- * - Frame wide : 16bit |\r
- * - Error % : 0,0000 |\r
- * - Prescaler Odd factor (ODD): 1 |\r
- * - Linear prescaler (DIV) : 14 |\r
- *-----------------------------------------------------------------------------\r
- * VDD(V) | 3,3\r
- *-----------------------------------------------------------------------------\r
- * Main regulator output voltage | Scale1 mode\r
- *-----------------------------------------------------------------------------\r
- * Flash Latency(WS) | 5\r
- *-----------------------------------------------------------------------------\r
- * Prefetch Buffer | OFF\r
- *-----------------------------------------------------------------------------\r
- * Instruction cache | ON\r
- *-----------------------------------------------------------------------------\r
- * Data cache | ON\r
- *-----------------------------------------------------------------------------\r
- * Require 48MHz for USB OTG FS, | Enabled\r
- * SDIO and RNG clock |\r
- *-----------------------------------------------------------------------------\r
- *=============================================================================\r
- ******************************************************************************\r
- * @attention\r
- *\r
- * THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS\r
- * WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE\r
- * TIME. AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY\r
- * DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING\r
- * FROM THE CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE\r
- * CODING INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.\r
- *\r
- * <h2><center>© COPYRIGHT 2011 STMicroelectronics</center></h2>\r
- ******************************************************************************\r
- */\r
-\r
-/** @addtogroup CMSIS\r
- * @{\r
- */\r
-\r
-/** @addtogroup stm32f4xx_system\r
- * @{\r
- */\r
-\r
-/** @addtogroup STM32F4xx_System_Private_Includes\r
- * @{\r
- */\r
-\r
-#include "stm32f4xx.h"\r
-\r
-/**\r
- * @}\r
- */\r
-\r
-/** @addtogroup STM32F4xx_System_Private_TypesDefinitions\r
- * @{\r
- */\r
-\r
-/**\r
- * @}\r
- */\r
-\r
-/** @addtogroup STM32F4xx_System_Private_Defines\r
- * @{\r
- */\r
-\r
-/************************* Miscellaneous Configuration ************************/\r
-/*!< Uncomment the following line if you need to use external SRAM mounted\r
- on STM324xG_EVAL board as data memory */\r
-/* #define DATA_IN_ExtSRAM */\r
-\r
-/*!< Uncomment the following line if you need to relocate your vector Table in\r
- Internal SRAM. */\r
-/* #define VECT_TAB_SRAM */\r
-#define VECT_TAB_OFFSET 0x00 /*!< Vector Table base offset field. \r
- This value must be a multiple of 0x200. */\r
-/******************************************************************************/\r
-\r
-/************************* PLL Parameters *************************************/\r
-/* PLL_VCO = (HSE_VALUE or HSI_VALUE / PLL_M) * PLL_N */\r
-#define PLL_M 8\r
-#define PLL_N 336\r
-\r
-/* SYSCLK = PLL_VCO / PLL_P */\r
-#define PLL_P 2\r
-\r
-/* USB OTG FS, SDIO and RNG Clock = PLL_VCO / PLLQ */\r
-#define PLL_Q 7\r
-\r
-/* PLLI2S_VCO = (HSE_VALUE Or HSI_VALUE / PLL_M) * PLLI2S_N\r
- I2SCLK = PLLI2S_VCO / PLLI2S_R */\r
-#define START_I2SCLOCK 0\r
-#define PLLI2S_N 352\r
-#define PLLI2S_R 2\r
-\r
-/******************************************************************************/\r
-\r
-/**\r
- * @}\r
- */\r
-\r
-/** @addtogroup STM32F4xx_System_Private_Macros\r
- * @{\r
- */\r
-\r
-/**\r
- * @}\r
- */\r
-\r
-/** @addtogroup STM32F4xx_System_Private_Variables\r
- * @{\r
- */\r
-\r
-uint32_t SystemCoreClock = 168000000;\r
-\r
-__I uint8_t AHBPrescTable[16] = {0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 6, 7, 8, 9};\r
-\r
-/**\r
- * @}\r
- */\r
-\r
-/** @addtogroup STM32F4xx_System_Private_FunctionPrototypes\r
- * @{\r
- */\r
-\r
-static void SetSysClock(void);\r
-#ifdef DATA_IN_ExtSRAM\r
-static void SystemInit_ExtMemCtl(void);\r
-#endif /* DATA_IN_ExtSRAM */\r
-\r
-/**\r
- * @}\r
- */\r
-\r
-/** @addtogroup STM32F4xx_System_Private_Functions\r
- * @{\r
- */\r
-\r
-/**\r
- * @brief Setup the microcontroller system\r
- * Initialize the Embedded Flash Interface, the PLL and update the\r
- * SystemFrequency variable.\r
- * @param None\r
- * @retval None\r
- */\r
-void SystemInit(void)\r
-{\r
- /* FPU settings ------------------------------------------------------------*/\r
-#if (__FPU_PRESENT == 1) && (__FPU_USED == 1)\r
- SCB->CPACR |= ((3UL << 10*2)|(3UL << 11*2)); /* set CP10 and CP11 Full Access */\r
-#endif\r
- /* Reset the RCC clock configuration to the default reset state ------------*/\r
- /* Set HSION bit */\r
- RCC->CR |= (uint32_t)0x00000001;\r
-\r
- /* Reset CFGR register */\r
- RCC->CFGR = 0x00000000;\r
-\r
- /* Reset HSEON, CSSON and PLLON bits */\r
- RCC->CR &= (uint32_t)0xFEF6FFFF;\r
-\r
- /* Reset PLLCFGR register */\r
- RCC->PLLCFGR = 0x24003010;\r
-\r
- /* Reset HSEBYP bit */\r
- RCC->CR &= (uint32_t)0xFFFBFFFF;\r
-\r
- /* Disable all interrupts */\r
- RCC->CIR = 0x00000000;\r
-\r
-#ifdef DATA_IN_ExtSRAM\r
- SystemInit_ExtMemCtl();\r
-#endif /* DATA_IN_ExtSRAM */\r
-\r
- /* Configure the System clock source, PLL Multiplier and Divider factors,\r
- AHB/APBx prescalers and Flash settings ----------------------------------*/\r
- SetSysClock();\r
-\r
- /* Configure the Vector Table location add offset address ------------------*/\r
-#ifdef VECT_TAB_SRAM\r
- SCB->VTOR = SRAM_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal SRAM */\r
-#else\r
- SCB->VTOR = FLASH_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal FLASH */\r
-#endif\r
-}\r
-\r
-/**\r
- * @brief Update SystemCoreClock variable according to Clock Register Values.\r
- * The SystemCoreClock variable contains the core clock (HCLK), it can\r
- * be used by the user application to setup the SysTick timer or configure\r
- * other parameters.\r
- *\r
- * @note Each time the core clock (HCLK) changes, this function must be called\r
- * to update SystemCoreClock variable value. Otherwise, any configuration\r
- * based on this variable will be incorrect.\r
- *\r
- * @note - The system frequency computed by this function is not the real\r
- * frequency in the chip. It is calculated based on the predefined\r
- * constant and the selected clock source:\r
- *\r
- * - If SYSCLK source is HSI, SystemCoreClock will contain the HSI_VALUE(*)\r
- *\r
- * - If SYSCLK source is HSE, SystemCoreClock will contain the HSE_VALUE(**)\r
- *\r
- * - If SYSCLK source is PLL, SystemCoreClock will contain the HSE_VALUE(**)\r
- * or HSI_VALUE(*) multiplied/divided by the PLL factors.\r
- *\r
- * (*) HSI_VALUE is a constant defined in stm32f4xx.h file (default value\r
- * 16 MHz) but the real value may vary depending on the variations\r
- * in voltage and temperature.\r
- *\r
- * (**) HSE_VALUE is a constant defined in stm32f4xx.h file (default value\r
- * 25 MHz), user has to ensure that HSE_VALUE is same as the real\r
- * frequency of the crystal used. Otherwise, this function may\r
- * have wrong result.\r
- *\r
- * - The result of this function could be not correct when using fractional\r
- * value for HSE crystal.\r
- *\r
- * @param None\r
- * @retval None\r
- */\r
-void SystemCoreClockUpdate(void)\r
-{\r
- uint32_t tmp = 0, pllvco = 0, pllp = 2, pllsource = 0, pllm = 2;\r
-\r
- /* Get SYSCLK source -------------------------------------------------------*/\r
- tmp = RCC->CFGR & RCC_CFGR_SWS;\r
-\r
- switch (tmp)\r
- {\r
- case 0x00: /* HSI used as system clock source */\r
- SystemCoreClock = HSI_VALUE;\r
- break;\r
- case 0x04: /* HSE used as system clock source */\r
- SystemCoreClock = HSE_VALUE;\r
- break;\r
- case 0x08: /* PLL used as system clock source */\r
-\r
- /* PLL_VCO = (HSE_VALUE or HSI_VALUE / PLL_M) * PLL_N\r
- SYSCLK = PLL_VCO / PLL_P\r
- */\r
- pllsource = (RCC->PLLCFGR & RCC_PLLCFGR_PLLSRC) >> 22;\r
- pllm = RCC->PLLCFGR & RCC_PLLCFGR_PLLM;\r
-\r
- if (pllsource != 0)\r
- {\r
- /* HSE used as PLL clock source */\r
- pllvco = (HSE_VALUE / pllm) * ((RCC->PLLCFGR & RCC_PLLCFGR_PLLN) >> 6);\r
- }\r
- else\r
- {\r
- /* HSI used as PLL clock source */\r
- pllvco = (HSI_VALUE / pllm) * ((RCC->PLLCFGR & RCC_PLLCFGR_PLLN) >> 6);\r
- }\r
-\r
- pllp = (((RCC->PLLCFGR & RCC_PLLCFGR_PLLP) >>16) + 1 ) *2;\r
- SystemCoreClock = pllvco/pllp;\r
- break;\r
- default:\r
- SystemCoreClock = HSI_VALUE;\r
- break;\r
- }\r
- /* Compute HCLK frequency --------------------------------------------------*/\r
- /* Get HCLK prescaler */\r
- tmp = AHBPrescTable[((RCC->CFGR & RCC_CFGR_HPRE) >> 4)];\r
- /* HCLK frequency */\r
- SystemCoreClock >>= tmp;\r
-}\r
-\r
-/**\r
- * @brief Configures the System clock source, PLL Multiplier and Divider factors,\r
- * AHB/APBx prescalers and Flash settings\r
- * @Note This function should be called only once the RCC clock configuration\r
- * is reset to the default reset state (done in SystemInit() function).\r
- * @param None\r
- * @retval None\r
- */\r
-static void SetSysClock(void)\r
-{\r
- /******************************************************************************/\r
- /* PLL (clocked by HSE) used as System clock source */\r
- /******************************************************************************/\r
- __IO uint32_t StartUpCounter = 0, HSEStatus = 0;\r
-\r
- /* Enable HSE */\r
- RCC->CR |= ((uint32_t)RCC_CR_HSEON);\r
-\r
- /* Wait till HSE is ready and if Time out is reached exit */\r
- do\r
- {\r
- HSEStatus = RCC->CR & RCC_CR_HSERDY;\r
- StartUpCounter++;\r
- } while((HSEStatus == 0) && (StartUpCounter != HSE_STARTUP_TIMEOUT));\r
-\r
- if ((RCC->CR & RCC_CR_HSERDY) != RESET)\r
- {\r
- HSEStatus = (uint32_t)0x01;\r
- }\r
- else\r
- {\r
- HSEStatus = (uint32_t)0x00;\r
- }\r
-\r
- if (HSEStatus == (uint32_t)0x01)\r
- {\r
- /* Select regulator voltage output Scale 1 mode, System frequency up to 168 MHz */\r
- RCC->APB1ENR |= RCC_APB1ENR_PWREN;\r
- PWR->CR |= PWR_CR_VOS;\r
-\r
- /* HCLK = SYSCLK / 1*/\r
- RCC->CFGR |= RCC_CFGR_HPRE_DIV1;\r
-\r
- /* PCLK2 = HCLK / 2*/\r
- RCC->CFGR |= RCC_CFGR_PPRE2_DIV2;\r
-\r
- /* PCLK1 = HCLK / 4*/\r
- RCC->CFGR |= RCC_CFGR_PPRE1_DIV4;\r
-\r
- /* Configure the main PLL */\r
- RCC->PLLCFGR = PLL_M | (PLL_N << 6) | (((PLL_P >> 1) -1) << 16) |\r
- (RCC_PLLCFGR_PLLSRC_HSE) | (PLL_Q << 24);\r
-\r
- /* Enable the main PLL */\r
- RCC->CR |= RCC_CR_PLLON;\r
-\r
- /* Wait till the main PLL is ready */\r
- while((RCC->CR & RCC_CR_PLLRDY) == 0)\r
- {\r
- }\r
-\r
- /* Configure Flash prefetch, Instruction cache, Data cache and wait state */\r
- FLASH->ACR = FLASH_ACR_ICEN |FLASH_ACR_DCEN |FLASH_ACR_LATENCY_5WS;\r
-\r
- /* Select the main PLL as system clock source */\r
- RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_SW));\r
- RCC->CFGR |= RCC_CFGR_SW_PLL;\r
-\r
- /* Wait till the main PLL is used as system clock source */\r
- while ((RCC->CFGR & (uint32_t)RCC_CFGR_SWS ) != RCC_CFGR_SWS_PLL);\r
- {\r
- }\r
- }\r
- else\r
- { /* If HSE fails to start-up, the application will have wrong clock\r
- configuration. User can add here some code to deal with this error */\r
- }\r
-\r
-\r
- /******************************************************************************/\r
- /* I2S clock configuration */\r
- /******************************************************************************/\r
-\r
-#if START_I2SCLOCK\r
- /* PLLI2S clock used as I2S clock source */\r
- RCC->CFGR &= ~RCC_CFGR_I2SSRC;\r
-\r
- /* Configure PLLI2S */\r
- RCC->PLLI2SCFGR = (PLLI2S_N << 6) | (PLLI2S_R << 28);\r
-\r
- /* Enable PLLI2S */\r
- RCC->CR |= ((uint32_t)RCC_CR_PLLI2SON);\r
-\r
- /* Wait till PLLI2S is ready */\r
- while((RCC->CR & RCC_CR_PLLI2SRDY) == 0)\r
- {\r
- }\r
-#endif\r
-}\r
-\r
-/**\r
- * @brief Setup the external memory controller. Called in startup_stm32f4xx.s\r
- * before jump to __main\r
- * @param None\r
- * @retval None\r
- */\r
-#ifdef DATA_IN_ExtSRAM\r
-/**\r
- * @brief Setup the external memory controller.\r
- * Called in startup_stm32f4xx.s before jump to main.\r
- * This function configures the external SRAM mounted on STM324xG_EVAL board\r
- * This SRAM will be used as program data memory (including heap and stack).\r
- * @param None\r
- * @retval None\r
- */\r
-void SystemInit_ExtMemCtl(void)\r
-{\r
- /*-- GPIOs Configuration -----------------------------------------------------*/\r
- /*\r
- +-------------------+--------------------+------------------+------------------+\r
- + SRAM pins assignment +\r
- +-------------------+--------------------+------------------+------------------+\r
- | PD0 <-> FSMC_D2 | PE0 <-> FSMC_NBL0 | PF0 <-> FSMC_A0 | PG0 <-> FSMC_A10 | \r
- | PD1 <-> FSMC_D3 | PE1 <-> FSMC_NBL1 | PF1 <-> FSMC_A1 | PG1 <-> FSMC_A11 | \r
- | PD4 <-> FSMC_NOE | PE3 <-> FSMC_A19 | PF2 <-> FSMC_A2 | PG2 <-> FSMC_A12 | \r
- | PD5 <-> FSMC_NWE | PE4 <-> FSMC_A20 | PF3 <-> FSMC_A3 | PG3 <-> FSMC_A13 | \r
- | PD8 <-> FSMC_D13 | PE7 <-> FSMC_D4 | PF4 <-> FSMC_A4 | PG4 <-> FSMC_A14 | \r
- | PD9 <-> FSMC_D14 | PE8 <-> FSMC_D5 | PF5 <-> FSMC_A5 | PG5 <-> FSMC_A15 | \r
- | PD10 <-> FSMC_D15 | PE9 <-> FSMC_D6 | PF12 <-> FSMC_A6 | PG9 <-> FSMC_NE2 | \r
- | PD11 <-> FSMC_A16 | PE10 <-> FSMC_D7 | PF13 <-> FSMC_A7 |------------------+\r
- | PD12 <-> FSMC_A17 | PE11 <-> FSMC_D8 | PF14 <-> FSMC_A8 | \r
- | PD13 <-> FSMC_A18 | PE12 <-> FSMC_D9 | PF15 <-> FSMC_A9 | \r
- | PD14 <-> FSMC_D0 | PE13 <-> FSMC_D10 |------------------+\r
- | PD15 <-> FSMC_D1 | PE14 <-> FSMC_D11 |\r
- | | PE15 <-> FSMC_D12 |\r
- +-------------------+--------------------+\r
- */\r
- /* Enable GPIOD, GPIOE, GPIOF and GPIOG interface clock */\r
- RCC->AHB1ENR = 0x00000078;\r
-\r
- /* Connect PDx pins to FSMC Alternate function */\r
- GPIOD->AFR[0] = 0x00cc00cc;\r
- GPIOD->AFR[1] = 0xcc0ccccc;\r
- /* Configure PDx pins in Alternate function mode */\r
- GPIOD->MODER = 0xaaaa0a0a;\r
- /* Configure PDx pins speed to 100 MHz */\r
- GPIOD->OSPEEDR = 0xffff0f0f;\r
- /* Configure PDx pins Output type to push-pull */\r
- GPIOD->OTYPER = 0x00000000;\r
- /* No pull-up, pull-down for PDx pins */\r
- GPIOD->PUPDR = 0x00000000;\r
-\r
- /* Connect PEx pins to FSMC Alternate function */\r
- GPIOE->AFR[0] = 0xc00cc0cc;\r
- GPIOE->AFR[1] = 0xcccccccc;\r
- /* Configure PEx pins in Alternate function mode */\r
- GPIOE->MODER = 0xaaaa828a;\r
- /* Configure PEx pins speed to 100 MHz */\r
- GPIOE->OSPEEDR = 0xffffc3cf;\r
- /* Configure PEx pins Output type to push-pull */\r
- GPIOE->OTYPER = 0x00000000;\r
- /* No pull-up, pull-down for PEx pins */\r
- GPIOE->PUPDR = 0x00000000;\r
-\r
- /* Connect PFx pins to FSMC Alternate function */\r
- GPIOF->AFR[0] = 0x00cccccc;\r
- GPIOF->AFR[1] = 0xcccc0000;\r
- /* Configure PFx pins in Alternate function mode */\r
- GPIOF->MODER = 0xaa000aaa;\r
- /* Configure PFx pins speed to 100 MHz */\r
- GPIOF->OSPEEDR = 0xff000fff;\r
- /* Configure PFx pins Output type to push-pull */\r
- GPIOF->OTYPER = 0x00000000;\r
- /* No pull-up, pull-down for PFx pins */\r
- GPIOF->PUPDR = 0x00000000;\r
-\r
- /* Connect PGx pins to FSMC Alternate function */\r
- GPIOG->AFR[0] = 0x00cccccc;\r
- GPIOG->AFR[1] = 0x000000c0;\r
- /* Configure PGx pins in Alternate function mode */\r
- GPIOG->MODER = 0x00080aaa;\r
- /* Configure PGx pins speed to 100 MHz */\r
- GPIOG->OSPEEDR = 0x000c0fff;\r
- /* Configure PGx pins Output type to push-pull */\r
- GPIOG->OTYPER = 0x00000000;\r
- /* No pull-up, pull-down for PGx pins */\r
- GPIOG->PUPDR = 0x00000000;\r
-\r
- /*-- FSMC Configuration ------------------------------------------------------*/\r
- /* Enable the FSMC interface clock */\r
- RCC->AHB3ENR = 0x00000001;\r
-\r
- /* Configure and enable Bank1_SRAM2 */\r
- FSMC_Bank1->BTCR[2] = 0x00001015;\r
- FSMC_Bank1->BTCR[3] = 0x00010603;\r
- FSMC_Bank1E->BWTR[2] = 0x0fffffff;\r
- /*\r
- Bank1_SRAM2 is configured as follow:\r
-\r
- p.FSMC_AddressSetupTime = 3;\r
- p.FSMC_AddressHoldTime = 0;\r
- p.FSMC_DataSetupTime = 6;\r
- p.FSMC_BusTurnAroundDuration = 1;\r
- p.FSMC_CLKDivision = 0;\r
- p.FSMC_DataLatency = 0;\r
- p.FSMC_AccessMode = FSMC_AccessMode_A;\r
-\r
- FSMC_NORSRAMInitStructure.FSMC_Bank = FSMC_Bank1_NORSRAM2;\r
- FSMC_NORSRAMInitStructure.FSMC_DataAddressMux = FSMC_DataAddressMux_Disable;\r
- FSMC_NORSRAMInitStructure.FSMC_MemoryType = FSMC_MemoryType_PSRAM;\r
- FSMC_NORSRAMInitStructure.FSMC_MemoryDataWidth = FSMC_MemoryDataWidth_16b;\r
- FSMC_NORSRAMInitStructure.FSMC_BurstAccessMode = FSMC_BurstAccessMode_Disable;\r
- FSMC_NORSRAMInitStructure.FSMC_AsynchronousWait = FSMC_AsynchronousWait_Disable; \r
- FSMC_NORSRAMInitStructure.FSMC_WaitSignalPolarity = FSMC_WaitSignalPolarity_Low;\r
- FSMC_NORSRAMInitStructure.FSMC_WrapMode = FSMC_WrapMode_Disable;\r
- FSMC_NORSRAMInitStructure.FSMC_WaitSignalActive = FSMC_WaitSignalActive_BeforeWaitState;\r
- FSMC_NORSRAMInitStructure.FSMC_WriteOperation = FSMC_WriteOperation_Enable;\r
- FSMC_NORSRAMInitStructure.FSMC_WaitSignal = FSMC_WaitSignal_Disable;\r
- FSMC_NORSRAMInitStructure.FSMC_ExtendedMode = FSMC_ExtendedMode_Disable;\r
- FSMC_NORSRAMInitStructure.FSMC_WriteBurst = FSMC_WriteBurst_Disable;\r
- FSMC_NORSRAMInitStructure.FSMC_ReadWriteTimingStruct = &p;\r
- FSMC_NORSRAMInitStructure.FSMC_WriteTimingStruct = &p;\r
- */\r
-}\r
-#endif /* DATA_IN_ExtSRAM */\r
-\r
-\r
-/**\r
- * @}\r
- */\r
-\r
-/**\r
- * @}\r
- */\r
-\r
-/**\r
- * @}\r
- */\r
-/******************* (C) COPYRIGHT 2011 STMicroelectronics *****END OF FILE****/\r
+/**
+ ******************************************************************************
+ * @file system_stm32f4xx.c
+ * @author MCD Application Team
+ * @version V1.0.1
+ * @date 10-July-2012
+ * @brief CMSIS Cortex-M4 Device Peripheral Access Layer System Source File.
+ * This file contains the system clock configuration for STM32F4xx devices,
+ * and is generated by the clock configuration tool
+ * stm32f4xx_Clock_Configuration_V1.0.1.xls
+ *
+ * 1. This file provides two functions and one global variable to be called from
+ * user application:
+ * - SystemInit(): Setups the system clock (System clock source, PLL Multiplier
+ * and Divider factors, AHB/APBx prescalers and Flash settings),
+ * depending on the configuration made in the clock xls tool.
+ * This function is called at startup just after reset and
+ * before branch to main program. This call is made inside
+ * the "startup_stm32f4xx.s" file.
+ *
+ * - SystemCoreClock variable: Contains the core clock (HCLK), it can be used
+ * by the user application to setup the SysTick
+ * timer or configure other parameters.
+ *
+ * - SystemCoreClockUpdate(): Updates the variable SystemCoreClock and must
+ * be called whenever the core clock is changed
+ * during program execution.
+ *
+ * 2. After each device reset the HSI (16 MHz) is used as system clock source.
+ * Then SystemInit() function is called, in "startup_stm32f4xx.s" file, to
+ * configure the system clock before to branch to main program.
+ *
+ * 3. If the system clock source selected by user fails to startup, the SystemInit()
+ * function will do nothing and HSI still used as system clock source. User can
+ * add some code to deal with this issue inside the SetSysClock() function.
+ *
+ * 4. The default value of HSE crystal is set to 25MHz, refer to "HSE_VALUE" define
+ * in "stm32f4xx.h" file. When HSE is used as system clock source, directly or
+ * through PLL, and you are using different crystal you have to adapt the HSE
+ * value to your own configuration.
+ *
+ * 5. This file configures the system clock as follows:
+ *=============================================================================
+ *=============================================================================
+ * Supported STM32F4xx device revision | Rev A
+ *-----------------------------------------------------------------------------
+ * System Clock source | PLL (HSE)
+ *-----------------------------------------------------------------------------
+ * SYSCLK(Hz) | 168000000
+ *-----------------------------------------------------------------------------
+ * HCLK(Hz) | 168000000
+ *-----------------------------------------------------------------------------
+ * AHB Prescaler | 1
+ *-----------------------------------------------------------------------------
+ * APB1 Prescaler | 4
+ *-----------------------------------------------------------------------------
+ * APB2 Prescaler | 2
+ *-----------------------------------------------------------------------------
+ * HSE Frequency(Hz) | 8000000
+ *-----------------------------------------------------------------------------
+ * PLL_M | 8
+ *-----------------------------------------------------------------------------
+ * PLL_N | 336
+ *-----------------------------------------------------------------------------
+ * PLL_P | 2
+ *-----------------------------------------------------------------------------
+ * PLL_Q | 7
+ *-----------------------------------------------------------------------------
+ * PLLI2S_N | 352
+ *-----------------------------------------------------------------------------
+ * PLLI2S_R | 2
+ *-----------------------------------------------------------------------------
+ * I2S input clock(Hz) | 176000000
+ * |
+ * To achieve the following I2S config: |
+ * - Master clock output (MCKO): OFF |
+ * - Frame wide : 16bit |
+ * - Error % : 0,0000 |
+ * - Prescaler Odd factor (ODD): 1 |
+ * - Linear prescaler (DIV) : 14 |
+ *-----------------------------------------------------------------------------
+ * VDD(V) | 3,3
+ *-----------------------------------------------------------------------------
+ * Main regulator output voltage | Scale1 mode
+ *-----------------------------------------------------------------------------
+ * Flash Latency(WS) | 5
+ *-----------------------------------------------------------------------------
+ * Prefetch Buffer | OFF
+ *-----------------------------------------------------------------------------
+ * Instruction cache | ON
+ *-----------------------------------------------------------------------------
+ * Data cache | ON
+ *-----------------------------------------------------------------------------
+ * Require 48MHz for USB OTG FS, | Enabled
+ * SDIO and RNG clock |
+ *-----------------------------------------------------------------------------
+ *=============================================================================
+ ******************************************************************************
+ * @attention
+ *
+ * THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS
+ * WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE
+ * TIME. AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY
+ * DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING
+ * FROM THE CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE
+ * CODING INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.
+ *
+ * <h2><center>© COPYRIGHT 2011 STMicroelectronics</center></h2>
+ ******************************************************************************
+ */
+
+/** @addtogroup CMSIS
+ * @{
+ */
+
+/** @addtogroup stm32f4xx_system
+ * @{
+ */
+
+/** @addtogroup STM32F4xx_System_Private_Includes
+ * @{
+ */
+
+#include "stm32f4xx.h"
+
+/**
+ * @}
+ */
+
+/** @addtogroup STM32F4xx_System_Private_TypesDefinitions
+ * @{
+ */
+
+/**
+ * @}
+ */
+
+/** @addtogroup STM32F4xx_System_Private_Defines
+ * @{
+ */
+
+/************************* Miscellaneous Configuration ************************/
+/*!< Uncomment the following line if you need to use external SRAM mounted
+ on STM324xG_EVAL board as data memory */
+/* #define DATA_IN_ExtSRAM */
+
+/*!< Uncomment the following line if you need to relocate your vector Table in
+ Internal SRAM. */
+/* #define VECT_TAB_SRAM */
+#define VECT_TAB_OFFSET 0x00 /*!< Vector Table base offset field.
+ This value must be a multiple of 0x200. */
+/******************************************************************************/
+
+/************************* PLL Parameters *************************************/
+/* PLL_VCO = (HSE_VALUE or HSI_VALUE / PLL_M) * PLL_N */
+#define PLL_M 8
+#define PLL_N 336
+
+/* SYSCLK = PLL_VCO / PLL_P */
+#define PLL_P 2
+
+/* USB OTG FS, SDIO and RNG Clock = PLL_VCO / PLLQ */
+#define PLL_Q 7
+
+/* PLLI2S_VCO = (HSE_VALUE Or HSI_VALUE / PLL_M) * PLLI2S_N
+ I2SCLK = PLLI2S_VCO / PLLI2S_R */
+#define START_I2SCLOCK 0
+#define PLLI2S_N 352
+#define PLLI2S_R 2
+
+/******************************************************************************/
+
+/**
+ * @}
+ */
+
+/** @addtogroup STM32F4xx_System_Private_Macros
+ * @{
+ */
+
+/**
+ * @}
+ */
+
+/** @addtogroup STM32F4xx_System_Private_Variables
+ * @{
+ */
+
+uint32_t SystemCoreClock = 168000000;
+
+__I uint8_t AHBPrescTable[16] = {0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 6, 7, 8, 9};
+
+/**
+ * @}
+ */
+
+/** @addtogroup STM32F4xx_System_Private_FunctionPrototypes
+ * @{
+ */
+
+static void SetSysClock(void);
+#ifdef DATA_IN_ExtSRAM
+static void SystemInit_ExtMemCtl(void);
+#endif /* DATA_IN_ExtSRAM */
+
+/**
+ * @}
+ */
+
+/** @addtogroup STM32F4xx_System_Private_Functions
+ * @{
+ */
+
+/**
+ * @brief Setup the microcontroller system
+ * Initialize the Embedded Flash Interface, the PLL and update the
+ * SystemFrequency variable.
+ * @param None
+ * @retval None
+ */
+void SystemInit(void)
+{
+ /* FPU settings ------------------------------------------------------------*/
+#if (__FPU_PRESENT == 1) && (__FPU_USED == 1)
+ SCB->CPACR |= ((3UL << 10*2)|(3UL << 11*2)); /* set CP10 and CP11 Full Access */
+#endif
+ /* Reset the RCC clock configuration to the default reset state ------------*/
+ /* Set HSION bit */
+ RCC->CR |= (uint32_t)0x00000001;
+
+ /* Reset CFGR register */
+ RCC->CFGR = 0x00000000;
+
+ /* Reset HSEON, CSSON and PLLON bits */
+ RCC->CR &= (uint32_t)0xFEF6FFFF;
+
+ /* Reset PLLCFGR register */
+ RCC->PLLCFGR = 0x24003010;
+
+ /* Reset HSEBYP bit */
+ RCC->CR &= (uint32_t)0xFFFBFFFF;
+
+ /* Disable all interrupts */
+ RCC->CIR = 0x00000000;
+
+#ifdef DATA_IN_ExtSRAM
+ SystemInit_ExtMemCtl();
+#endif /* DATA_IN_ExtSRAM */
+
+ /* Configure the System clock source, PLL Multiplier and Divider factors,
+ AHB/APBx prescalers and Flash settings ----------------------------------*/
+ SetSysClock();
+
+ /* Configure the Vector Table location add offset address ------------------*/
+#ifdef VECT_TAB_SRAM
+ SCB->VTOR = SRAM_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal SRAM */
+#else
+ SCB->VTOR = FLASH_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal FLASH */
+#endif
+}
+
+/**
+ * @brief Update SystemCoreClock variable according to Clock Register Values.
+ * The SystemCoreClock variable contains the core clock (HCLK), it can
+ * be used by the user application to setup the SysTick timer or configure
+ * other parameters.
+ *
+ * @note Each time the core clock (HCLK) changes, this function must be called
+ * to update SystemCoreClock variable value. Otherwise, any configuration
+ * based on this variable will be incorrect.
+ *
+ * @note - The system frequency computed by this function is not the real
+ * frequency in the chip. It is calculated based on the predefined
+ * constant and the selected clock source:
+ *
+ * - If SYSCLK source is HSI, SystemCoreClock will contain the HSI_VALUE(*)
+ *
+ * - If SYSCLK source is HSE, SystemCoreClock will contain the HSE_VALUE(**)
+ *
+ * - If SYSCLK source is PLL, SystemCoreClock will contain the HSE_VALUE(**)
+ * or HSI_VALUE(*) multiplied/divided by the PLL factors.
+ *
+ * (*) HSI_VALUE is a constant defined in stm32f4xx.h file (default value
+ * 16 MHz) but the real value may vary depending on the variations
+ * in voltage and temperature.
+ *
+ * (**) HSE_VALUE is a constant defined in stm32f4xx.h file (default value
+ * 25 MHz), user has to ensure that HSE_VALUE is same as the real
+ * frequency of the crystal used. Otherwise, this function may
+ * have wrong result.
+ *
+ * - The result of this function could be not correct when using fractional
+ * value for HSE crystal.
+ *
+ * @param None
+ * @retval None
+ */
+void SystemCoreClockUpdate(void)
+{
+ uint32_t tmp = 0, pllvco = 0, pllp = 2, pllsource = 0, pllm = 2;
+
+ /* Get SYSCLK source -------------------------------------------------------*/
+ tmp = RCC->CFGR & RCC_CFGR_SWS;
+
+ switch (tmp)
+ {
+ case 0x00: /* HSI used as system clock source */
+ SystemCoreClock = HSI_VALUE;
+ break;
+ case 0x04: /* HSE used as system clock source */
+ SystemCoreClock = HSE_VALUE;
+ break;
+ case 0x08: /* PLL used as system clock source */
+
+ /* PLL_VCO = (HSE_VALUE or HSI_VALUE / PLL_M) * PLL_N
+ SYSCLK = PLL_VCO / PLL_P
+ */
+ pllsource = (RCC->PLLCFGR & RCC_PLLCFGR_PLLSRC) >> 22;
+ pllm = RCC->PLLCFGR & RCC_PLLCFGR_PLLM;
+
+ if (pllsource != 0)
+ {
+ /* HSE used as PLL clock source */
+ pllvco = (HSE_VALUE / pllm) * ((RCC->PLLCFGR & RCC_PLLCFGR_PLLN) >> 6);
+ }
+ else
+ {
+ /* HSI used as PLL clock source */
+ pllvco = (HSI_VALUE / pllm) * ((RCC->PLLCFGR & RCC_PLLCFGR_PLLN) >> 6);
+ }
+
+ pllp = (((RCC->PLLCFGR & RCC_PLLCFGR_PLLP) >>16) + 1 ) *2;
+ SystemCoreClock = pllvco/pllp;
+ break;
+ default:
+ SystemCoreClock = HSI_VALUE;
+ break;
+ }
+ /* Compute HCLK frequency --------------------------------------------------*/
+ /* Get HCLK prescaler */
+ tmp = AHBPrescTable[((RCC->CFGR & RCC_CFGR_HPRE) >> 4)];
+ /* HCLK frequency */
+ SystemCoreClock >>= tmp;
+}
+
+/**
+ * @brief Configures the System clock source, PLL Multiplier and Divider factors,
+ * AHB/APBx prescalers and Flash settings
+ * @Note This function should be called only once the RCC clock configuration
+ * is reset to the default reset state (done in SystemInit() function).
+ * @param None
+ * @retval None
+ */
+static void SetSysClock(void)
+{
+ /******************************************************************************/
+ /* PLL (clocked by HSE) used as System clock source */
+ /******************************************************************************/
+ __IO uint32_t StartUpCounter = 0, HSEStatus = 0;
+
+ /* Enable HSE */
+ RCC->CR |= ((uint32_t)RCC_CR_HSEON);
+
+ /* Wait till HSE is ready and if Time out is reached exit */
+ do
+ {
+ HSEStatus = RCC->CR & RCC_CR_HSERDY;
+ StartUpCounter++;
+ } while((HSEStatus == 0) && (StartUpCounter != HSE_STARTUP_TIMEOUT));
+
+ if ((RCC->CR & RCC_CR_HSERDY) != RESET)
+ {
+ HSEStatus = (uint32_t)0x01;
+ }
+ else
+ {
+ HSEStatus = (uint32_t)0x00;
+ }
+
+ if (HSEStatus == (uint32_t)0x01)
+ {
+ /* Select regulator voltage output Scale 1 mode, System frequency up to 168 MHz */
+ RCC->APB1ENR |= RCC_APB1ENR_PWREN;
+ PWR->CR |= PWR_CR_VOS;
+
+ /* HCLK = SYSCLK / 1*/
+ RCC->CFGR |= RCC_CFGR_HPRE_DIV1;
+
+ /* PCLK2 = HCLK / 2*/
+ RCC->CFGR |= RCC_CFGR_PPRE2_DIV2;
+
+ /* PCLK1 = HCLK / 4*/
+ RCC->CFGR |= RCC_CFGR_PPRE1_DIV4;
+
+ /* Configure the main PLL */
+ RCC->PLLCFGR = PLL_M | (PLL_N << 6) | (((PLL_P >> 1) -1) << 16) |
+ (RCC_PLLCFGR_PLLSRC_HSE) | (PLL_Q << 24);
+
+ /* Enable the main PLL */
+ RCC->CR |= RCC_CR_PLLON;
+
+ /* Wait till the main PLL is ready */
+ while((RCC->CR & RCC_CR_PLLRDY) == 0)
+ {
+ }
+
+ /* Configure Flash prefetch, Instruction cache, Data cache and wait state */
+ FLASH->ACR = FLASH_ACR_ICEN |FLASH_ACR_DCEN |FLASH_ACR_LATENCY_5WS;
+
+ /* Select the main PLL as system clock source */
+ RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_SW));
+ RCC->CFGR |= RCC_CFGR_SW_PLL;
+
+ /* Wait till the main PLL is used as system clock source */
+ while ((RCC->CFGR & (uint32_t)RCC_CFGR_SWS ) != RCC_CFGR_SWS_PLL);
+ {
+ }
+ }
+ else
+ { /* If HSE fails to start-up, the application will have wrong clock
+ configuration. User can add here some code to deal with this error */
+ }
+
+
+ /******************************************************************************/
+ /* I2S clock configuration */
+ /******************************************************************************/
+
+#if START_I2SCLOCK
+ /* PLLI2S clock used as I2S clock source */
+ RCC->CFGR &= ~RCC_CFGR_I2SSRC;
+
+ /* Configure PLLI2S */
+ RCC->PLLI2SCFGR = (PLLI2S_N << 6) | (PLLI2S_R << 28);
+
+ /* Enable PLLI2S */
+ RCC->CR |= ((uint32_t)RCC_CR_PLLI2SON);
+
+ /* Wait till PLLI2S is ready */
+ while((RCC->CR & RCC_CR_PLLI2SRDY) == 0)
+ {
+ }
+#endif
+}
+
+/**
+ * @brief Setup the external memory controller. Called in startup_stm32f4xx.s
+ * before jump to __main
+ * @param None
+ * @retval None
+ */
+#ifdef DATA_IN_ExtSRAM
+/**
+ * @brief Setup the external memory controller.
+ * Called in startup_stm32f4xx.s before jump to main.
+ * This function configures the external SRAM mounted on STM324xG_EVAL board
+ * This SRAM will be used as program data memory (including heap and stack).
+ * @param None
+ * @retval None
+ */
+void SystemInit_ExtMemCtl(void)
+{
+ /*-- GPIOs Configuration -----------------------------------------------------*/
+ /*
+ +-------------------+--------------------+------------------+------------------+
+ + SRAM pins assignment +
+ +-------------------+--------------------+------------------+------------------+
+ | PD0 <-> FSMC_D2 | PE0 <-> FSMC_NBL0 | PF0 <-> FSMC_A0 | PG0 <-> FSMC_A10 |
+ | PD1 <-> FSMC_D3 | PE1 <-> FSMC_NBL1 | PF1 <-> FSMC_A1 | PG1 <-> FSMC_A11 |
+ | PD4 <-> FSMC_NOE | PE3 <-> FSMC_A19 | PF2 <-> FSMC_A2 | PG2 <-> FSMC_A12 |
+ | PD5 <-> FSMC_NWE | PE4 <-> FSMC_A20 | PF3 <-> FSMC_A3 | PG3 <-> FSMC_A13 |
+ | PD8 <-> FSMC_D13 | PE7 <-> FSMC_D4 | PF4 <-> FSMC_A4 | PG4 <-> FSMC_A14 |
+ | PD9 <-> FSMC_D14 | PE8 <-> FSMC_D5 | PF5 <-> FSMC_A5 | PG5 <-> FSMC_A15 |
+ | PD10 <-> FSMC_D15 | PE9 <-> FSMC_D6 | PF12 <-> FSMC_A6 | PG9 <-> FSMC_NE2 |
+ | PD11 <-> FSMC_A16 | PE10 <-> FSMC_D7 | PF13 <-> FSMC_A7 |------------------+
+ | PD12 <-> FSMC_A17 | PE11 <-> FSMC_D8 | PF14 <-> FSMC_A8 |
+ | PD13 <-> FSMC_A18 | PE12 <-> FSMC_D9 | PF15 <-> FSMC_A9 |
+ | PD14 <-> FSMC_D0 | PE13 <-> FSMC_D10 |------------------+
+ | PD15 <-> FSMC_D1 | PE14 <-> FSMC_D11 |
+ | | PE15 <-> FSMC_D12 |
+ +-------------------+--------------------+
+ */
+ /* Enable GPIOD, GPIOE, GPIOF and GPIOG interface clock */
+ RCC->AHB1ENR = 0x00000078;
+
+ /* Connect PDx pins to FSMC Alternate function */
+ GPIOD->AFR[0] = 0x00cc00cc;
+ GPIOD->AFR[1] = 0xcc0ccccc;
+ /* Configure PDx pins in Alternate function mode */
+ GPIOD->MODER = 0xaaaa0a0a;
+ /* Configure PDx pins speed to 100 MHz */
+ GPIOD->OSPEEDR = 0xffff0f0f;
+ /* Configure PDx pins Output type to push-pull */
+ GPIOD->OTYPER = 0x00000000;
+ /* No pull-up, pull-down for PDx pins */
+ GPIOD->PUPDR = 0x00000000;
+
+ /* Connect PEx pins to FSMC Alternate function */
+ GPIOE->AFR[0] = 0xc00cc0cc;
+ GPIOE->AFR[1] = 0xcccccccc;
+ /* Configure PEx pins in Alternate function mode */
+ GPIOE->MODER = 0xaaaa828a;
+ /* Configure PEx pins speed to 100 MHz */
+ GPIOE->OSPEEDR = 0xffffc3cf;
+ /* Configure PEx pins Output type to push-pull */
+ GPIOE->OTYPER = 0x00000000;
+ /* No pull-up, pull-down for PEx pins */
+ GPIOE->PUPDR = 0x00000000;
+
+ /* Connect PFx pins to FSMC Alternate function */
+ GPIOF->AFR[0] = 0x00cccccc;
+ GPIOF->AFR[1] = 0xcccc0000;
+ /* Configure PFx pins in Alternate function mode */
+ GPIOF->MODER = 0xaa000aaa;
+ /* Configure PFx pins speed to 100 MHz */
+ GPIOF->OSPEEDR = 0xff000fff;
+ /* Configure PFx pins Output type to push-pull */
+ GPIOF->OTYPER = 0x00000000;
+ /* No pull-up, pull-down for PFx pins */
+ GPIOF->PUPDR = 0x00000000;
+
+ /* Connect PGx pins to FSMC Alternate function */
+ GPIOG->AFR[0] = 0x00cccccc;
+ GPIOG->AFR[1] = 0x000000c0;
+ /* Configure PGx pins in Alternate function mode */
+ GPIOG->MODER = 0x00080aaa;
+ /* Configure PGx pins speed to 100 MHz */
+ GPIOG->OSPEEDR = 0x000c0fff;
+ /* Configure PGx pins Output type to push-pull */
+ GPIOG->OTYPER = 0x00000000;
+ /* No pull-up, pull-down for PGx pins */
+ GPIOG->PUPDR = 0x00000000;
+
+ /*-- FSMC Configuration ------------------------------------------------------*/
+ /* Enable the FSMC interface clock */
+ RCC->AHB3ENR = 0x00000001;
+
+ /* Configure and enable Bank1_SRAM2 */
+ FSMC_Bank1->BTCR[2] = 0x00001015;
+ FSMC_Bank1->BTCR[3] = 0x00010603;
+ FSMC_Bank1E->BWTR[2] = 0x0fffffff;
+ /*
+ Bank1_SRAM2 is configured as follow:
+
+ p.FSMC_AddressSetupTime = 3;
+ p.FSMC_AddressHoldTime = 0;
+ p.FSMC_DataSetupTime = 6;
+ p.FSMC_BusTurnAroundDuration = 1;
+ p.FSMC_CLKDivision = 0;
+ p.FSMC_DataLatency = 0;
+ p.FSMC_AccessMode = FSMC_AccessMode_A;
+
+ FSMC_NORSRAMInitStructure.FSMC_Bank = FSMC_Bank1_NORSRAM2;
+ FSMC_NORSRAMInitStructure.FSMC_DataAddressMux = FSMC_DataAddressMux_Disable;
+ FSMC_NORSRAMInitStructure.FSMC_MemoryType = FSMC_MemoryType_PSRAM;
+ FSMC_NORSRAMInitStructure.FSMC_MemoryDataWidth = FSMC_MemoryDataWidth_16b;
+ FSMC_NORSRAMInitStructure.FSMC_BurstAccessMode = FSMC_BurstAccessMode_Disable;
+ FSMC_NORSRAMInitStructure.FSMC_AsynchronousWait = FSMC_AsynchronousWait_Disable;
+ FSMC_NORSRAMInitStructure.FSMC_WaitSignalPolarity = FSMC_WaitSignalPolarity_Low;
+ FSMC_NORSRAMInitStructure.FSMC_WrapMode = FSMC_WrapMode_Disable;
+ FSMC_NORSRAMInitStructure.FSMC_WaitSignalActive = FSMC_WaitSignalActive_BeforeWaitState;
+ FSMC_NORSRAMInitStructure.FSMC_WriteOperation = FSMC_WriteOperation_Enable;
+ FSMC_NORSRAMInitStructure.FSMC_WaitSignal = FSMC_WaitSignal_Disable;
+ FSMC_NORSRAMInitStructure.FSMC_ExtendedMode = FSMC_ExtendedMode_Disable;
+ FSMC_NORSRAMInitStructure.FSMC_WriteBurst = FSMC_WriteBurst_Disable;
+ FSMC_NORSRAMInitStructure.FSMC_ReadWriteTimingStruct = &p;
+ FSMC_NORSRAMInitStructure.FSMC_WriteTimingStruct = &p;
+ */
+}
+#endif /* DATA_IN_ExtSRAM */
+
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+/******************* (C) COPYRIGHT 2011 STMicroelectronics *****END OF FILE****/
-/*---------------------------------------------------------------------------*\\r
-\r
- FILE........: tuner_ut.c\r
- AUTHOR......: David Rowe\r
- DATE CREATED: 20 Feb 2015\r
-\r
- Unit test for high speed ADC radio tuner, samples signal centred at\r
- 500kHz using Fs=2 MHz and uploads to host at Fs=10 kHz.\r
-\r
-\*---------------------------------------------------------------------------*/\r
-\r
-/*\r
- Copyright (C) 2015 David Rowe\r
-\r
- All rights reserved.\r
-\r
- This program is free software; you can redistribute it and/or modify\r
- it under the terms of the GNU Lesser General Public License version 2.1, as\r
- published by the Free Software Foundation. This program is\r
- distributed in the hope that it will be useful, but WITHOUT ANY\r
- WARRANTY; without even the implied warranty of MERCHANTABILITY or\r
- FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public\r
- License for more details.\r
-\r
- You should have received a copy of the GNU Lesser General Public License\r
- along with this program; if not, see <http://www.gnu.org/licenses/>.\r
-*/\r
-\r
-#include <assert.h>\r
-#include <stdlib.h>\r
-#include "gdb_stdio.h"\r
-#include "stm32f4_dac.h"\r
-#include "stm32f4_adc_tuner.h"\r
-#include "iir_tuner.h"\r
-#include "sm1000_leds_switches.h"\r
-#include "../src/codec2_fm.h"\r
-#include "stm32f4xx.h"\r
-\r
-#define REC_TIME_SECS 10\r
-#define FS 50000\r
-#define N 5000\r
-\r
-extern int adc_overflow1;\r
-\r
-int main(void) {\r
- float tuner_out[IIR_TUNER_DEC_50_10_FILT_MEM+N/2];\r
- float fm_out[N/2];\r
- //float dec_10[(N/2)/5];\r
- short dec_10_short[(N/2)];\r
- int bufs, i, j, k, fifo_sz, bn;\r
- FILE *ftuner;\r
- struct FM *fm;\r
-\r
- ftuner = fopen("tuner.raw", "wb");\r
- if (ftuner == NULL) {\r
- printf("Error opening input file: tuner.raw\n\nTerminating....\n");\r
- exit(1);\r
- }\r
- bufs = FS*REC_TIME_SECS/N;\r
- fifo_sz = ((4*N/ADC_TUNER_N)+1)*ADC_TUNER_N;\r
- printf("Starting! bufs: %d %d\n", bufs, fifo_sz);\r
- \r
- //dac_open(DAC_BUF_SZ);\r
- adc_open(fifo_sz);\r
- sm1000_leds_switches_init();\r
-\r
- fm = fm_create(N/2);\r
- fm->Fs = 44400.0;\r
- fm->fm_max = 3000.0;\r
- fm->fd = 5000.0;\r
- fm->fc = fm->Fs/4;\r
-\r
- i = 0; bn = 0;\r
- while(1) {\r
- /* wait for buffer of Fs=50kHz tuner output samples */\r
-\r
- while(adc1_read((short *)&tuner_out[IIR_TUNER_DEC_50_10_FILT_MEM], N) == -1);\r
-\r
- /* The semi-hosting system can only handle Fs=16kHz and below so resample down\r
- to Fs=10 kHz and convert to shorts */\r
-\r
- #ifdef SSB\r
- iir_tuner_dec_50_to_10(dec_10, &tuner_out[IIR_TUNER_DEC_50_10_FILT_MEM], N/2);\r
- for(j=0; j<IIR_TUNER_DEC_50_10_FILT_MEM; j++)\r
- tuner_out[j] = tuner_out[j+N/2];\r
- for(j=0; j<(N/2)/5; j++)\r
- dec_10_short[j] = dec_10[j]/ADC_TUNER_M;\r
- #else\r
- GPIOE->ODR |= (1 << 3);\r
- /*\r
- for(j=0; j<N/2; j++)\r
- tuner_out[IIR_TUNER_DEC_50_10_FILT_MEM+j] = 0;\r
- for(j=1; j<N/2; j+=4)\r
- tuner_out[IIR_TUNER_DEC_50_10_FILT_MEM+j] = 100;\r
- for(j=3; j<N/2; j+=4)\r
- tuner_out[IIR_TUNER_DEC_50_10_FILT_MEM+j] = -100;\r
- */\r
- fm_demod(fm, fm_out, &tuner_out[IIR_TUNER_DEC_50_10_FILT_MEM]);\r
- GPIOE->ODR &= ~(1 << 3);\r
-\r
- for(j=0,k=0; j<N/2; j+=5,k++)\r
- dec_10_short[k+bn] = 16384*fm_out[j];\r
- bn += (N/2)/5;\r
- #endif\r
-\r
- if ((bn == N/2) && (i < bufs)) {\r
- //for(j=0; j<N/2; j++)\r
- // dec_10_short[j] = tuner_out[IIR_TUNER_DEC_50_10_FILT_MEM+j];\r
- fwrite(dec_10_short, sizeof(short), (N/2), ftuner);\r
- bn = 0;\r
- i += 5;\r
- //fwrite(dec_10_short, sizeof(short), (N/2)/5, ftuner);\r
- //printf("%d %d\n", i, adc_overflow1);\r
- }\r
- if (i == bufs) {\r
- printf("finished! %d\n", adc_overflow1);\r
- fclose(ftuner);\r
- i++;\r
- }\r
- }\r
-}\r
-\r
+/*---------------------------------------------------------------------------*\
+
+ FILE........: tuner_ut.c
+ AUTHOR......: David Rowe
+ DATE CREATED: 20 Feb 2015
+
+ Unit test for high speed ADC radio tuner, samples signal centred at
+ 500kHz using Fs=2 MHz and uploads to host at Fs=10 kHz.
+
+\*---------------------------------------------------------------------------*/
+
+/*
+ Copyright (C) 2015 David Rowe
+
+ All rights reserved.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License version 2.1, as
+ published by the Free Software Foundation. This program is
+ distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+ License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with this program; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <assert.h>
+#include <stdlib.h>
+#include "gdb_stdio.h"
+#include "stm32f4_dac.h"
+#include "stm32f4_adc_tuner.h"
+#include "iir_tuner.h"
+#include "sm1000_leds_switches.h"
+#include "../src/codec2_fm.h"
+#include "stm32f4xx.h"
+
+#define REC_TIME_SECS 10
+#define FS 50000
+#define N 5000
+
+extern int adc_overflow1;
+
+int main(void) {
+ float tuner_out[IIR_TUNER_DEC_50_10_FILT_MEM+N/2];
+ float fm_out[N/2];
+ //float dec_10[(N/2)/5];
+ short dec_10_short[(N/2)];
+ int bufs, i, j, k, fifo_sz, bn;
+ FILE *ftuner;
+ struct FM *fm;
+
+ ftuner = fopen("tuner.raw", "wb");
+ if (ftuner == NULL) {
+ printf("Error opening input file: tuner.raw\n\nTerminating....\n");
+ exit(1);
+ }
+ bufs = FS*REC_TIME_SECS/N;
+ fifo_sz = ((4*N/ADC_TUNER_N)+1)*ADC_TUNER_N;
+ printf("Starting! bufs: %d %d\n", bufs, fifo_sz);
+
+ //dac_open(DAC_BUF_SZ);
+ adc_open(fifo_sz);
+ sm1000_leds_switches_init();
+
+ fm = fm_create(N/2);
+ fm->Fs = 44400.0;
+ fm->fm_max = 3000.0;
+ fm->fd = 5000.0;
+ fm->fc = fm->Fs/4;
+
+ i = 0; bn = 0;
+ while(1) {
+ /* wait for buffer of Fs=50kHz tuner output samples */
+
+ while(adc1_read((short *)&tuner_out[IIR_TUNER_DEC_50_10_FILT_MEM], N) == -1);
+
+ /* The semi-hosting system can only handle Fs=16kHz and below so resample down
+ to Fs=10 kHz and convert to shorts */
+
+ #ifdef SSB
+ iir_tuner_dec_50_to_10(dec_10, &tuner_out[IIR_TUNER_DEC_50_10_FILT_MEM], N/2);
+ for(j=0; j<IIR_TUNER_DEC_50_10_FILT_MEM; j++)
+ tuner_out[j] = tuner_out[j+N/2];
+ for(j=0; j<(N/2)/5; j++)
+ dec_10_short[j] = dec_10[j]/ADC_TUNER_M;
+ #else
+ GPIOE->ODR |= (1 << 3);
+ /*
+ for(j=0; j<N/2; j++)
+ tuner_out[IIR_TUNER_DEC_50_10_FILT_MEM+j] = 0;
+ for(j=1; j<N/2; j+=4)
+ tuner_out[IIR_TUNER_DEC_50_10_FILT_MEM+j] = 100;
+ for(j=3; j<N/2; j+=4)
+ tuner_out[IIR_TUNER_DEC_50_10_FILT_MEM+j] = -100;
+ */
+ fm_demod(fm, fm_out, &tuner_out[IIR_TUNER_DEC_50_10_FILT_MEM]);
+ GPIOE->ODR &= ~(1 << 3);
+
+ for(j=0,k=0; j<N/2; j+=5,k++)
+ dec_10_short[k+bn] = 16384*fm_out[j];
+ bn += (N/2)/5;
+ #endif
+
+ if ((bn == N/2) && (i < bufs)) {
+ //for(j=0; j<N/2; j++)
+ // dec_10_short[j] = tuner_out[IIR_TUNER_DEC_50_10_FILT_MEM+j];
+ fwrite(dec_10_short, sizeof(short), (N/2), ftuner);
+ bn = 0;
+ i += 5;
+ //fwrite(dec_10_short, sizeof(short), (N/2)/5, ftuner);
+ //printf("%d %d\n", i, adc_overflow1);
+ }
+ if (i == bufs) {
+ printf("finished! %d\n", adc_overflow1);
+ fclose(ftuner);
+ i++;
+ }
+ }
+}
+
perror("listen");
return 1;
}
--\r
+-
+
+ /* init for file I/O */
+