mirror of
https://github.com/zjs81/meshcore-open.git
synced 2026-07-26 13:36:39 +10:00
updated ui added new features
This commit is contained in:
+365
@@ -0,0 +1,365 @@
|
||||
% fdmdv_demod.m
|
||||
%
|
||||
% Demodulator function for FDMDV modem (Octave version). Requires
|
||||
% 8kHz sample rate raw files as input
|
||||
%
|
||||
% Copyright David Rowe 2012
|
||||
% This program is distributed under the terms of the GNU General Public License
|
||||
% Version 2
|
||||
%
|
||||
|
||||
function fdmdv_demod(rawfilename, nbits, NumCarriers=14, errorpatternfilename, symbolfilename)
|
||||
pkg load signal;
|
||||
fdmdv; % include modem code
|
||||
f = fdmdv_init(NumCarriers);
|
||||
Nc = f.Nc; Nb = f.Nb; Rs = f.Rs; M = f.M; Fs = f.Fs; Nsync_mem = f.Nsync_mem;
|
||||
test_bits = f.test_bits; Q = f.Q; P = f.P;
|
||||
|
||||
modulation = 'dqpsk';
|
||||
|
||||
fin = fopen(rawfilename, "rb");
|
||||
gain = 1000;
|
||||
frames = nbits/(Nc*Nb);
|
||||
|
||||
prev_rx_symbols = ones(Nc+1,1);
|
||||
foff_phase_rect = 1;
|
||||
|
||||
% BER stats
|
||||
|
||||
total_bit_errors = 0;
|
||||
total_bits = 0;
|
||||
bit_errors_log = [];
|
||||
sync_log = [];
|
||||
test_frame_sync_log = [];
|
||||
test_frame_sync_state = 0;
|
||||
error_pattern_log = [];
|
||||
|
||||
% SNR states
|
||||
|
||||
sig_est = zeros(Nc+1,1);
|
||||
noise_est = zeros(Nc+1,1);
|
||||
|
||||
% logs of various states for plotting
|
||||
|
||||
rx_symbols_log = [];
|
||||
rx_timing_log = [];
|
||||
foff_coarse_log = [];
|
||||
foff_log = [];
|
||||
rx_fdm_log = [];
|
||||
snr_est_log = [];
|
||||
|
||||
% misc states
|
||||
|
||||
nin = M; % timing correction for sample rate differences
|
||||
foff = 0;
|
||||
|
||||
fest_state = 0;
|
||||
fest_timer = 0;
|
||||
sync_mem = zeros(1,Nsync_mem);
|
||||
sync = 0;
|
||||
sync_log = [];
|
||||
|
||||
% spectrum states
|
||||
|
||||
Nspec=1024;
|
||||
spec_mem=zeros(1,Nspec);
|
||||
SdB = zeros(1,Nspec);
|
||||
|
||||
% optionally save output symbols
|
||||
|
||||
if nargin == 5
|
||||
fm = fopen(symbolfilename,"wb");
|
||||
dual_rx_symbols = zeros(1, 2*Nc);
|
||||
dual_rx_bits = zeros(1,2*Nc*Nb);
|
||||
end
|
||||
|
||||
atimer = 0;
|
||||
|
||||
% Main loop ----------------------------------------------------
|
||||
|
||||
for fr=1:frames
|
||||
|
||||
% obtain nin samples of the test input signal
|
||||
|
||||
for i=1:nin
|
||||
rx_fdm(i) = fread(fin, 1, "short")/gain;
|
||||
end
|
||||
|
||||
rx_fdm_log = [rx_fdm_log rx_fdm(1:nin)];
|
||||
|
||||
% update spectrum
|
||||
|
||||
l=length(rx_fdm);
|
||||
spec_mem(1:Nspec-l) = spec_mem(l+1:Nspec);
|
||||
spec_mem(Nspec-l+1:Nspec) = rx_fdm;
|
||||
S=fft(spec_mem.*hanning(Nspec)',Nspec);
|
||||
SdB = 0.9*SdB + 0.1*20*log10(abs(S));
|
||||
|
||||
% shift down to complex baseband
|
||||
|
||||
for i=1:nin
|
||||
f.fbb_phase_rx = f.fbb_phase_rx*f.fbb_rect';
|
||||
rx_fdm(i) = rx_fdm(i)*f.fbb_phase_rx;
|
||||
end
|
||||
mag = abs(f.fbb_phase_rx);
|
||||
f.fbb_phase_rx /= mag;
|
||||
|
||||
% frequency offset estimation and correction
|
||||
|
||||
[pilot prev_pilot f.pilot_lut_index f.prev_pilot_lut_index] = get_pilot(f, f.pilot_lut_index, f.prev_pilot_lut_index, nin);
|
||||
[foff_coarse S1 S2 f] = rx_est_freq_offset(f, rx_fdm, pilot, prev_pilot, nin, !sync );
|
||||
|
||||
if sync == 0
|
||||
foff = foff_coarse;
|
||||
end
|
||||
foff_coarse_log = [foff_coarse_log foff_coarse];
|
||||
|
||||
foff_rect = exp(j*2*pi*foff/Fs);
|
||||
|
||||
for i=1:nin
|
||||
foff_phase_rect *= foff_rect';
|
||||
rx_fdm_fcorr(i) = rx_fdm(i)*foff_phase_rect;
|
||||
end
|
||||
|
||||
% baseband processing
|
||||
|
||||
if 0
|
||||
% easier to understand, but more memory and CPU hungry filtering and down conversion
|
||||
|
||||
[rx_baseband f] = fdm_downconvert(f, rx_fdm_fcorr, nin);
|
||||
[rx_filt f] = rx_filter(f, rx_baseband, nin);
|
||||
else
|
||||
% more efficient filtering and down conversion
|
||||
|
||||
[rx_fdm_filter f] = rxdec_filter(f, rx_fdm_fcorr, nin);
|
||||
[rx_filt f] = down_convert_and_rx_filter(f, rx_fdm_filter, nin, M/Q);
|
||||
end
|
||||
|
||||
[rx_symbols rx_timing env f] = rx_est_timing(f, rx_filt, nin);
|
||||
rx_timing_log = [rx_timing_log rx_timing];
|
||||
|
||||
nin = M;
|
||||
if rx_timing > M/P
|
||||
nin += M/P;
|
||||
end
|
||||
if rx_timing < -M/P;
|
||||
nin -= M/P;
|
||||
end
|
||||
%printf("fr: %d rx_timing: %d nin = %d\n", fr, rx_timing, nin);
|
||||
|
||||
rx_symbols_log = [rx_symbols_log rx_symbols.*conj(prev_rx_symbols./abs(prev_rx_symbols))*exp(j*pi/4)];
|
||||
[rx_bits sync_bit f_err pd] = psk_to_bits(f, prev_rx_symbols, rx_symbols, modulation);
|
||||
|
||||
% optionally save output symbols
|
||||
|
||||
if (nargin == 5)
|
||||
|
||||
% this free runs, and is reset by an "entered sync" state
|
||||
|
||||
if (sync_track == 0)
|
||||
sync_track = 1;
|
||||
else
|
||||
sync_track = 0;
|
||||
end
|
||||
|
||||
if (track == 1) && (sync_track == 1)
|
||||
dual_rx_symbols(Nc+1:2*Nc) = rx_symbols(1:Nc).*conj(prev_rx_symbols(1:Nc)./abs(prev_rx_symbols(1:Nc)));
|
||||
dual_rx_symbols_float32 = []; k = 1;
|
||||
for i=1:2*Nc
|
||||
dual_rx_symbols_float32(k++) = real(dual_rx_symbols(i));
|
||||
dual_rx_symbols_float32(k++) = imag(dual_rx_symbols(i));
|
||||
end
|
||||
fwrite(fm, dual_rx_symbols_float32, "float32");
|
||||
dual_rx_bits(Nc*Nb+1:2*Nc*Nb) = rx_bits;
|
||||
%dump_bits(dual_rx_bits);
|
||||
else
|
||||
dual_rx_symbols(1:Nc) = rx_symbols(1:Nc).*conj(prev_rx_symbols(1:Nc)./abs(prev_rx_symbols(1:Nc)));
|
||||
dual_rx_bits(1:Nc*Nb) = rx_bits;
|
||||
end
|
||||
end
|
||||
|
||||
% update some states
|
||||
|
||||
prev_rx_symbols = rx_symbols;
|
||||
[sig_est noise_est] = snr_update(f, sig_est, noise_est, pd);
|
||||
snr_est = calc_snr(f, sig_est, noise_est);
|
||||
snr_est_log = [snr_est_log snr_est];
|
||||
foff -= 0.5*f_err;
|
||||
foff_log = [foff_log foff];
|
||||
|
||||
% freq est state machine
|
||||
|
||||
[sync reliable_sync_bit fest_state fest_timer sync_mem] = freq_state(f, sync_bit, fest_state, fest_timer, sync_mem);
|
||||
sync_log = [sync_log sync];
|
||||
|
||||
% count bit errors if we find a test frame
|
||||
|
||||
[test_frame_sync bit_errors error_pattern f] = put_test_bits(f, rx_bits);
|
||||
if (test_frame_sync == 1)
|
||||
if (bit_errors)
|
||||
printf("fr: %d bit_errors: %d\n", fr, bit_errors);
|
||||
end
|
||||
total_bit_errors = total_bit_errors + bit_errors;
|
||||
total_bits = total_bits + f.Ntest_bits;
|
||||
bit_errors_log = [bit_errors_log bit_errors/f.Ntest_bits];
|
||||
else
|
||||
bit_errors_log = [bit_errors_log 0];
|
||||
end
|
||||
|
||||
% test frame sync state machine, just for more informative plots
|
||||
|
||||
next_test_frame_sync_state = test_frame_sync_state;
|
||||
if (test_frame_sync_state == 0)
|
||||
if (test_frame_sync == 1)
|
||||
next_test_frame_sync_state = 1;
|
||||
test_frame_count = 0;
|
||||
end
|
||||
end
|
||||
|
||||
if (test_frame_sync_state == 1)
|
||||
% we only expect another test_frame_sync pulse every 4 symbols
|
||||
test_frame_count++;
|
||||
if (test_frame_count == 4)
|
||||
test_frame_count = 0;
|
||||
if ((test_frame_sync == 0))
|
||||
next_test_frame_sync_state = 0;
|
||||
else
|
||||
error_pattern_log = [error_pattern_log error_pattern];
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
test_frame_sync_state = next_test_frame_sync_state;
|
||||
test_frame_sync_log = [test_frame_sync_log test_frame_sync_state];
|
||||
end
|
||||
|
||||
if nargin == 5
|
||||
fclose(fm);
|
||||
etfilename = strcat(strtok(symbolfilename,"."),"_et.bin");
|
||||
fet = fopen(etfilename, "wb");
|
||||
fwrite(fet, entered_track_log, "short");
|
||||
fclose(fet);
|
||||
end
|
||||
|
||||
% ---------------------------------------------------------------------
|
||||
% Print Stats
|
||||
% ---------------------------------------------------------------------
|
||||
|
||||
% Peak to Average Power Ratio calcs from http://www.dsplog.com
|
||||
|
||||
papr = max(rx_fdm_log.*conj(rx_fdm_log)) / mean(rx_fdm_log.*conj(rx_fdm_log));
|
||||
papr_dB = 10*log10(papr);
|
||||
|
||||
ber = total_bit_errors / total_bits;
|
||||
printf("%d bits %d errors BER: %1.4f PAPR(rx): %1.2f dB\n",total_bits, total_bit_errors, ber, papr_dB);
|
||||
|
||||
% ---------------------------------------------------------------------
|
||||
% Plots
|
||||
% ---------------------------------------------------------------------
|
||||
|
||||
xt = (1:frames)/Rs;
|
||||
secs = frames/Rs;
|
||||
|
||||
figure(1); clf;
|
||||
[n m] = size(rx_symbols_log);
|
||||
plot(real(rx_symbols_log(1:Nc+1,15:m)),imag(rx_symbols_log(1:Nc+1,15:m)),'+')
|
||||
axis([-2 2 -2 2]);
|
||||
title('Scatter Diagram');
|
||||
|
||||
figure(2); clf;
|
||||
plot(xt, rx_timing_log)
|
||||
title('timing offset (samples)');
|
||||
|
||||
figure(3);
|
||||
plot(xt, foff_log, '-;freq offset;')
|
||||
%hold on;
|
||||
%plot(xt, sync_log*75, 'r;course-fine;');
|
||||
%hold off;
|
||||
title('Freq offset (Hz)');
|
||||
grid;
|
||||
|
||||
figure(4); clf;
|
||||
plot_specgram(rx_fdm_log, Fs);
|
||||
|
||||
figure(5); clf;
|
||||
subplot(311)
|
||||
stem(xt, sync_log)
|
||||
axis([0 secs 0 1.5]);
|
||||
title('BPSK Sync')
|
||||
subplot(312)
|
||||
stem(xt, bit_errors_log);
|
||||
title('Bit Errors for test frames')
|
||||
subplot(313)
|
||||
plot(xt, test_frame_sync_log);
|
||||
axis([0 secs 0 1.5]);
|
||||
title('Test Frame Sync')
|
||||
|
||||
figure(6); clf;
|
||||
subplot(211);
|
||||
plot(xt, snr_est_log);
|
||||
title('SNR Estimates')
|
||||
subplot(212)
|
||||
snrdB_pc = 20*log10(sig_est(1:Nc+1)) - 20*log10(noise_est(1:Nc+1));
|
||||
bar(snrdB_pc(1:Nc) - mean(snrdB_pc(1:Nc)))
|
||||
axis([0 Nc+1 -3 3]);
|
||||
|
||||
figure(7); clf;
|
||||
hold on;
|
||||
lep = length(error_pattern_log);
|
||||
if lep != 0
|
||||
for p=1:Nc
|
||||
plot(p + 0.25*error_pattern_log((p-1)*2+1:Nc*Nb:lep));
|
||||
plot(0.30 + p + 0.25*error_pattern_log(p*2:Nc*Nb:lep),'r')
|
||||
end
|
||||
hold off;
|
||||
axis([1 lep/(Nc*Nb) 0 Nc])
|
||||
end
|
||||
|
||||
figure(8); clf;
|
||||
subplot(211)
|
||||
[a b] = size(rx_fdm_log);
|
||||
xt1 = (1:b)/Fs;
|
||||
plot(xt1, rx_fdm_log);
|
||||
title('Rx FDM Signal');
|
||||
subplot(212)
|
||||
plot((0:Nspec/2-1)*Fs/Nspec, SdB(1:Nspec/2) - 20*log10(Nspec/2))
|
||||
axis([0 Fs/2 -40 0])
|
||||
grid
|
||||
title('FDM Rx Spectrum');
|
||||
|
||||
if 0
|
||||
% interleaving tests
|
||||
|
||||
load ../unittest/inter560.txt
|
||||
lep = length(error_pattern_log);
|
||||
lep = floor(lep/560)*560;
|
||||
error_pattern_log_inter = zeros(1,lep);
|
||||
for i=1:560:lep
|
||||
for j=1:560
|
||||
%printf("i: %4d j: %4d inter560(j): %4d\n", i,j,inter560(j));
|
||||
index = inter560(j);
|
||||
error_pattern_log_inter(i-1+index+1) = error_pattern_log(i-1+j);
|
||||
end
|
||||
end
|
||||
|
||||
figure(8)
|
||||
clf;
|
||||
hold on;
|
||||
for p=1:Nc
|
||||
plot(p + 0.25*error_pattern_log_inter((p-1)*2+1:Nc*Nb:lep));
|
||||
plot(0.30 + p + 0.25*error_pattern_log_inter(p*2:Nc*Nb:lep),'r')
|
||||
end
|
||||
hold off;
|
||||
axis([1 lep/(Nc*Nb) 0 Nc])
|
||||
end
|
||||
|
||||
% optionally save error pattern file
|
||||
|
||||
if nargin == 4
|
||||
fout = fopen(errorpatternfilename, "wb");
|
||||
fwrite(fout, error_pattern_log, "short");
|
||||
fclose(fout);
|
||||
end
|
||||
|
||||
|
||||
endfunction
|
||||
Reference in New Issue
Block a user