mirror of
https://github.com/drowe67/codec2
synced 2026-08-14 19:31:34 -04:00
some more Octave files rm-ed
This commit is contained in:
parent
87025ac7d2
commit
a291cfaf4c
41 changed files with 0 additions and 5552 deletions
|
|
@ -1,26 +0,0 @@
|
|||
% hackrf_dc.m
|
||||
%
|
||||
% David Rowe Nov 2015
|
||||
%
|
||||
% Downconverts a HackRF IQ sample file to a lower sample rate
|
||||
%
|
||||
% To sample a -60dB signal:
|
||||
% $ hackrf_transfer -r df1.iq -f 439200000 -n 10000000 -l 20 -g 40play file at 10.7MHz used:
|
||||
% octave:25> d = hackrf_dc("df1.iq")
|
||||
|
||||
function d = hackrf_dc(infilename)
|
||||
Fs1 = 10E6; % input sample rate to HackRF
|
||||
Fs2 = 96E3; % output sample rate
|
||||
fc = 700E3; % offset to shift input by, HackRF doesn't like signals in the centre
|
||||
|
||||
s1 = load_hackrf(infilename);
|
||||
ls1 = length(s1);
|
||||
ls1 = 20*Fs1;
|
||||
t = 0:ls1-1;
|
||||
|
||||
% shift down to baseband from Fc, not sure of rot90 rather than trasnpose operator '
|
||||
% to avoid unwanted complex conj
|
||||
|
||||
s2 = rot90(s1(1:ls1)) .* exp(-j*2*pi*t*fc/Fs1);
|
||||
d = resample(s2, Fs2, Fs1);
|
||||
end
|
||||
|
|
@ -1,24 +0,0 @@
|
|||
% hackrf_twotone.m
|
||||
%
|
||||
% David Rowe Nov 2015
|
||||
%
|
||||
% Generates a two tone test signal that can be played out of HackRF
|
||||
%
|
||||
% To play file at 10.7MHz used:
|
||||
% $ hackrf_transfer -t ../octave/twotone.iq -f 10000000 -a 0 -x 47
|
||||
%
|
||||
% However 2nd harmonic at 21.4 was only -32dBC so not really useful for my application
|
||||
% in testing an ADC
|
||||
|
||||
Fs = 8E6;
|
||||
fc = 2E6;
|
||||
f1 = fc;
|
||||
f2 = fc+1E3;
|
||||
A = 127;
|
||||
T = 2;
|
||||
|
||||
N = T*Fs;
|
||||
t = 0:N-1;
|
||||
%s = A*exp(j*2*pi*t*f1/Fs) + A*exp(j*2*pi*t*f2/Fs);
|
||||
s = A*exp(j*2*pi*t*f2/Fs);
|
||||
save_hackrf("twotone.iq",s);
|
||||
|
|
@ -1,47 +0,0 @@
|
|||
% hackrf_uc.m
|
||||
%
|
||||
% David Rowe Nov 2015
|
||||
%
|
||||
% Upconverts a real baseband sample file to a file suitable for input into a HackRF
|
||||
%
|
||||
% To play file at 10.7MHz used:
|
||||
% octave:25> hackrf_uc("fsk_10M.iq","fsk_horus_rx_1200_96k.raw")
|
||||
% $ hackrf_transfer -t ../octave/fsk_10M.iq -f 10000000 -a 1 -x 40
|
||||
|
||||
function hackrf_uc(outfilename, infilename)
|
||||
pkg load signal;
|
||||
Fs1 = 48E3; % input sample rate
|
||||
Fs2 = 10E6; % output sample rate to HackRF
|
||||
fc = 700E3-24E3; % offset to shift to, HackRF doesn't like signals in the centre
|
||||
A = 100; % amplitude of signal after upc-nversion (max 127)
|
||||
N = Fs1*20;
|
||||
|
||||
fin = fopen(infilename,"rb");
|
||||
printf("1\n");
|
||||
s1 = fread(fin,"short");
|
||||
printf("1\n");
|
||||
fclose(fin);
|
||||
printf("1\n");
|
||||
ls1 = length(s1);
|
||||
printf("1\n");
|
||||
N = ls1;
|
||||
% single sided freq shifts, we don't want DSB
|
||||
printf("1\n");
|
||||
s1 = hilbert(s1(1:N));
|
||||
|
||||
% upsample to Fs2
|
||||
|
||||
M = Fs2/Fs1;
|
||||
s2 = resample(s1(1:N),Fs2,Fs1);
|
||||
ls2 = length(s2);
|
||||
mx = max(abs(s2));
|
||||
t = 0:ls2-1;
|
||||
printf("2\n");
|
||||
% shift up to Fc, note use of rot90 rather than trasnpose operator '
|
||||
% as we don't want complex conj, that would shift down in freq
|
||||
|
||||
sout = rot90((A/mx)*s2) .* exp(j*2*pi*t*fc/Fs2);
|
||||
|
||||
save_hackrf(outfilename,sout);
|
||||
|
||||
end
|
||||
File diff suppressed because one or more lines are too long
|
|
@ -1,122 +0,0 @@
|
|||
% impulse_noise
|
||||
% David Rowe May 2017
|
||||
%
|
||||
% Experiments with impulsive noise and HF radio
|
||||
|
||||
format;
|
||||
more off;
|
||||
rand('seed',1)
|
||||
|
||||
% DFT function ------------------------------------------------
|
||||
% note k is on 0..K-1 format, unlike Octave fft() which is 1..K
|
||||
|
||||
function H = calc_H(k, K, a, d)
|
||||
L = length(d);
|
||||
H = 0;
|
||||
for i=1:L
|
||||
H += a(i)*exp(-j*2*pi*k*d(i)/K);
|
||||
end
|
||||
endfunction
|
||||
|
||||
% -----------------------------------------
|
||||
% PWM noise simulation
|
||||
% -----------------------------------------
|
||||
|
||||
function pwm_noise
|
||||
|
||||
Fs = 10E6; % sample rate of simulation
|
||||
Fsig = 1E6; % frequency of our wanted signal
|
||||
Fpwm = 255E3; % switcher PWM frequency
|
||||
T = 1; % length of simulations in seconds
|
||||
Nsam = T*Fs;
|
||||
Nsamplot = 200;
|
||||
Apwm = 0.1;
|
||||
Asig = -40; % attenuation of wanted signal in dB
|
||||
|
||||
% generate an impulse train with jitter to simulate switcher noise
|
||||
|
||||
pwm = zeros(1,Fs);
|
||||
Tpwm = floor(Fs/Fpwm);
|
||||
pulse_positions_pwm = Tpwm*(1:T*Fpwm) + round(rand(1,T*Fpwm));
|
||||
|
||||
h_pwm = zeros(1,Nsam);
|
||||
h_pwm(pulse_positions_pwm) = Apwm;
|
||||
h_pwm = h_pwm(1:Nsam);
|
||||
|
||||
% add in wanted signal and computer amplitude spectrum
|
||||
|
||||
s = 10^(Asig/20)*cos(2*pi*Fsig*(1:Nsam)/Fs);
|
||||
|
||||
h = h_pwm+s;
|
||||
H = fft(h);
|
||||
Hdb = 20*log10(abs(H)) - 20*log10(Nsam/2);
|
||||
|
||||
figure(1); clf;
|
||||
subplot(211)
|
||||
plot(h(1:Nsamplot));
|
||||
subplot(212)
|
||||
plot(Hdb(1:Nsam/2));
|
||||
axis([0 T*2E6 -120 0]); xlabel('Frequency Hz'); ylabel('Amplityude dBV'); grid;
|
||||
|
||||
printf("pwm rms: %f signal rms: %f noise rms\n", std(h_pwm), std(s));
|
||||
endfunction
|
||||
|
||||
% -----------------------------------------
|
||||
% Single pulse noise simulation
|
||||
% -----------------------------------------
|
||||
|
||||
function pulse_noise
|
||||
|
||||
% set up short pulse in wide window, consisting of two samples next
|
||||
% to each other
|
||||
|
||||
K = 1024;
|
||||
a(1) = a(2) = 1; d(1) = 10; d(2) = d(1)+1;
|
||||
h = zeros(1,K);
|
||||
h(d(1)) = a(1);
|
||||
h(d(2)) = a(2);
|
||||
|
||||
% mag and phase spectrum, mag spectrum changes slowly
|
||||
|
||||
figure(2); clf;
|
||||
Hfft = fft(h);
|
||||
subplot(311)
|
||||
stem(h(1:100));
|
||||
axis([1 100 -0.2 1.2]);
|
||||
subplot(312)
|
||||
plot(abs(Hfft(1:K/2)),'+');
|
||||
title('Magnitude');
|
||||
subplot(313)
|
||||
plot(angle(Hfft(1:K/2)),'+');
|
||||
title('Phase');
|
||||
|
||||
% simple test to estimate H(k+1) from H(k) --------------------
|
||||
|
||||
% brute force calculation
|
||||
|
||||
k = 300;
|
||||
H = zeros(1,K);
|
||||
H(k-1) = calc_H(k-1, K, a, d);
|
||||
H(k) = calc_H(k, K, a, d);
|
||||
H(k+1) = calc_H(k+1, K, a, d);
|
||||
|
||||
% calculation of k+1 from k using approximation that {d(i)} are
|
||||
% close together compared to M, i.e it's a narrow pulse (assumes we
|
||||
% can estimate d using other means)
|
||||
|
||||
Hk1_ = exp(-j*2*pi*d(1)/K)*H(k);
|
||||
|
||||
% plot zoomed in version around k to compare
|
||||
|
||||
figure(3); clf;
|
||||
plot(H(k-1:k+1),'b+','markersize', 10, 'linewidth', 2);
|
||||
hold on; plot(Hk1_,'g+','markersize', 10, 'linewidth', 2); hold off;
|
||||
title('H(k-1) .... H(k+1)');
|
||||
printf("H(k+1) match: %f dB\n", 20*log10(abs(H(k+1) - Hk1_)));
|
||||
endfunction
|
||||
|
||||
% Run various simulations here ---------------------------------------------
|
||||
|
||||
%pwm_noise
|
||||
pulse_noise
|
||||
|
||||
|
|
@ -1,9 +0,0 @@
|
|||
% load_comp.m
|
||||
% David Rowe Sep 2015
|
||||
|
||||
function s = load_comp(fn)
|
||||
fs=fopen(fn,"rb");
|
||||
s = fread(fs,Inf,"float32");
|
||||
ls = length(s);
|
||||
s = s(1:2:ls) + j*s(2:2:ls);
|
||||
endfunction
|
||||
|
|
@ -1,11 +0,0 @@
|
|||
% load_hackrf.m
|
||||
%
|
||||
% David Rowe Oct 2015
|
||||
|
||||
function s = load_hackrf(fn)
|
||||
fs = fopen(fn,"rb");
|
||||
iq = fread(fs,Inf,"schar");
|
||||
fclose(fs);
|
||||
l = length(iq);
|
||||
s = iq(1:2:l) + j*iq(2:2:l);
|
||||
endfunction
|
||||
|
|
@ -1,11 +0,0 @@
|
|||
% load_rtlsdr.m
|
||||
%
|
||||
% David Rowe Oct 2015
|
||||
|
||||
function s = load_rtlsdr(fn)
|
||||
fs = fopen(fn,"rb");
|
||||
iq = fread(fs,Inf,"uchar");
|
||||
fclose(fs);
|
||||
l = length(iq);
|
||||
s = iq(1:2:l) + j*iq(2:2:l);
|
||||
endfunction
|
||||
|
|
@ -1,500 +0,0 @@
|
|||
% mancyfsk.m
|
||||
% David Rowe October 2015
|
||||
%
|
||||
% Manchester encoded 2FSK & 4FSK simulation.
|
||||
%
|
||||
% Attempt to design a FSK waveform that can pass through legacy FM
|
||||
% radios but still be optimally demodulated by SDRs. It doesn't have
|
||||
% to be optimally demodulated by legacy radios. Trick is getting it
|
||||
% to pass through 300-3000Hz audio filters in legacy radios.
|
||||
%
|
||||
% [X] code up modulator
|
||||
% [X] manchester two bit symbols
|
||||
% [X] plot spectrum
|
||||
% [X] demodulate using analog FM and ideal demods
|
||||
% [X] measure BER compared to ideal coherent FSK
|
||||
|
||||
1;
|
||||
|
||||
fm; % analog FM library
|
||||
|
||||
|
||||
function states = legacyfsk_init(M,Rs)
|
||||
Fs = states.Fs = 96000;
|
||||
states.Rs = Rs; % symbol rate over channel
|
||||
Ts = states.Ts = Fs/Rs; % symbol period in samples
|
||||
states.M = M; % mFSK, either 2 or 4
|
||||
bpsym = state.Rb = log2(M); % bits per symbol over channel
|
||||
rate = states.rate = 0.5; % Manchester code rate
|
||||
nbits = 100;
|
||||
nbits = states.nbits = 100; % number of payload data symbols/frame
|
||||
nbits2 = states.nbits2 = nbits/rate; % number of symbols/frame over channel after manchester encoding
|
||||
nsym = states.nsym = nbits2/log2(M); % number of symbols per frame
|
||||
nsam = states.nsam = nsym*Ts;
|
||||
|
||||
%printf(" Rs: %d M: %d bpsym: %d nbits: %d nbits2: %d nsym: %d nsam: %d\n", Rs, M, bpsym, nbits, nbits2, nsym, nsam);
|
||||
|
||||
states.fc = states.Fs/4;
|
||||
if states.M == 2
|
||||
states.f(1) = states.fc - Rs/2;
|
||||
states.f(2) = states.fc + Rs/2;
|
||||
else
|
||||
states.f(1) = states.fc - 3*Rs/2;
|
||||
states.f(2) = states.fc - Rs/2;
|
||||
states.f(3) = states.fc + Rs/2;
|
||||
states.f(4) = states.fc + 3*Rs/2;
|
||||
end
|
||||
endfunction
|
||||
|
||||
|
||||
% test modulator function
|
||||
|
||||
function tx = legacyfsk_mod(states, tx_bits)
|
||||
Fs = states.Fs;
|
||||
Ts = states.Ts;
|
||||
Rs = states.Rs;
|
||||
f = states.f;
|
||||
M = states.M;
|
||||
nsym = states.nsym;
|
||||
|
||||
tx = zeros(Ts*length(tx_bits)/log2(M),1);
|
||||
tx_phase = 0;
|
||||
|
||||
step = log2(M);
|
||||
k = 1;
|
||||
for i=1:step:length(tx_bits)
|
||||
if M == 2
|
||||
tone = tx_bits(i) + 1;
|
||||
else
|
||||
tone = (tx_bits(i:i+1) * [2 1]') + 1;
|
||||
end
|
||||
tx_phase_vec = tx_phase + (1:Ts)*2*pi*f(tone)/Fs;
|
||||
tx((k-1)*Ts+1:k*Ts) = 2.0*cos(tx_phase_vec); k++;
|
||||
tx_phase = tx_phase_vec(Ts) - floor(tx_phase_vec(Ts)/(2*pi))*2*pi;
|
||||
end
|
||||
|
||||
endfunction
|
||||
|
||||
|
||||
function run_sim(sim_in)
|
||||
|
||||
frames = sim_in.frames;
|
||||
test_frame_mode = sim_in.test_frame_mode;
|
||||
M = sim_in.M;
|
||||
Rs = sim_in.Rs;
|
||||
demod = sim_in.demod;
|
||||
EbNodB = sim_in.EbNodB;
|
||||
timing_offset = sim_in.timing_offset;
|
||||
|
||||
% rx timing has been adjusted experimentally
|
||||
|
||||
if Rs == 4800
|
||||
if demod == 1
|
||||
rx_timing = 4;
|
||||
else
|
||||
rx_timing = 0;
|
||||
end
|
||||
end
|
||||
if Rs == 2400
|
||||
if demod == 1
|
||||
rx_timing = 40;
|
||||
else
|
||||
rx_timing = 0;
|
||||
end
|
||||
end
|
||||
|
||||
% init fsk modem
|
||||
|
||||
more off
|
||||
rand('state',1);
|
||||
randn('state',1);
|
||||
states = legacyfsk_init(M,Rs);
|
||||
Fs = states.Fs;
|
||||
nbits = states.nbits;
|
||||
nbits2 = states.nbits2;
|
||||
Ts = states.Ts;
|
||||
nsam = states.nsam;
|
||||
rate = states.rate;
|
||||
|
||||
% init analog FM modem
|
||||
|
||||
fm_states.Fs = Fs;
|
||||
fm_max = fm_states.fm_max = 3E3;
|
||||
fd = fm_states.fd = 5E3;
|
||||
fm_states.fc = states.fc;
|
||||
|
||||
fm_states.pre_emp = 0;
|
||||
fm_states.de_emp = 1;
|
||||
fm_states.Ts = 1;
|
||||
fm_states.output_filter = 1;
|
||||
fm_states = analog_fm_init(fm_states);
|
||||
[b, a] = cheby1(4, 1, 300/Fs, 'high'); % 300Hz HPF to simulate FM radios
|
||||
|
||||
% init sim states
|
||||
|
||||
rx_bits_buf = zeros(1,2*nbits2);
|
||||
Terrs = Tbits = 0;
|
||||
state = 0;
|
||||
nerr_log = [];
|
||||
|
||||
% set up the channel noise. We have log(M)*rate payload bits/symbol
|
||||
% we have log2(M) bits/symbol, and rate bits per payload symbol
|
||||
% TODO: explain this better as Im confused!
|
||||
|
||||
EbNo = 10^(EbNodB/10);
|
||||
EsNo = EbNo*rate*log2(M);
|
||||
variance = states.Fs/((states.Rs)*EsNo);
|
||||
%printf("EbNodB: %3.1f EbNo: %3.2f EsNo: %3.2f\n", EbNodB, EbNo, EsNo);
|
||||
|
||||
% set up the input bits
|
||||
|
||||
if test_frame_mode == 1
|
||||
% test frame of bits, which we repeat for convenience when BER testing
|
||||
test_frame = round(rand(1, nbits));
|
||||
tx_bits = [];
|
||||
for i=1:frames+1
|
||||
tx_bits = [tx_bits test_frame];
|
||||
end
|
||||
end
|
||||
if test_frame_mode == 2
|
||||
% random bits, just to make sure sync algs work on random data
|
||||
tx_bits = round(rand(1, nbits*(frames+1)));
|
||||
end
|
||||
if test_frame_mode == 3
|
||||
% ...10101... sequence
|
||||
tx_bits = zeros(1, nbits*(frames+1));
|
||||
tx_bits(1:2:length(tx_bits)) = 1;
|
||||
end
|
||||
|
||||
% Manchester Encoding -----------------------------------------------------------
|
||||
|
||||
% Manchester encoding, which removes DC term in baseband signal,
|
||||
% making the waveform friendly to old-school legacy FM radios with
|
||||
% voiceband filtering. The "code rate" is 0.5, which means we have
|
||||
% encode one input bit into 2 output bits. The 2FSK encoder takes
|
||||
% one input bit, the 4FSK encoder two input bits.
|
||||
|
||||
tx_bits_encoded = zeros(1,length(tx_bits)*2);
|
||||
fsk2_enc = [[1 0]; [0 1]];
|
||||
% -1.5 1.5 1.5 -1.5 -0.5 0.5 0.5 -0.5
|
||||
% 0 3 3 0 1 2 2 1
|
||||
fsk4_enc = [[0 0 1 1]; [1 1 0 0]; [0 1 1 0]; [1 0 0 1]];
|
||||
k=1;
|
||||
if M == 2
|
||||
for i=1:2:length(tx_bits_encoded)
|
||||
input_bit = tx_bits(k); k++;
|
||||
tx_bits_encoded(i:i+1) = fsk2_enc(input_bit+1,:);
|
||||
end
|
||||
else
|
||||
for i=1:4:length(tx_bits_encoded)
|
||||
input_bits = tx_bits(k:k+1) * [2 1]'; k+=2;
|
||||
tx_bits_encoded(i:i+3) = fsk4_enc(input_bits+1,:);
|
||||
end
|
||||
end
|
||||
|
||||
% FSK Modulator --------------------------------------------------------------
|
||||
|
||||
% use ideal FSK modulator (note: need to try using analog FM modulator)
|
||||
|
||||
tx = legacyfsk_mod(states, tx_bits_encoded);
|
||||
noise = sqrt(variance)*randn(length(tx),1);
|
||||
rx = tx + noise;
|
||||
timing_offset_samples = round(timing_offset*Ts);
|
||||
rx = [zeros(timing_offset_samples,1); rx];
|
||||
|
||||
% Demodulator ----------------------------------------------------------------------------
|
||||
|
||||
if demod == 1
|
||||
% use analog FM demodulator, aka a $40 Baofeng
|
||||
|
||||
[rx_out rx_bb] = analog_fm_demod(fm_states, rx');
|
||||
if sim_in.hpf
|
||||
rx_out_hp = filter(b,a,rx_out);
|
||||
else
|
||||
rx_out_hp = rx_out;
|
||||
end
|
||||
rx_filt = filter(ones(1,Ts),1,rx_out_hp);
|
||||
rx_timing_sig = rx_filt;
|
||||
|
||||
% TODO: for 4FSK determine amplitude/decn boundaries, choose closest to demod each symbol
|
||||
|
||||
end
|
||||
|
||||
if demod == 2
|
||||
|
||||
% optimal non-coherent demod at Rs
|
||||
|
||||
rx_timing_sig = zeros(1,length(rx));
|
||||
for m=1:M
|
||||
phi_vec = (1:length(rx))*2*pi*states.f(m)/Fs;
|
||||
dc = rx' .* exp(-j*phi_vec);
|
||||
rx_filt(m,:) = abs(filter(ones(1,Ts),1,dc));
|
||||
rx_timing_sig = rx_timing_sig + rx_filt(m,1:length(rx));
|
||||
end
|
||||
end
|
||||
|
||||
% Fine timing estimation ------------------------------------------------------
|
||||
|
||||
% Estimate fine timing using line at Rs/2 that Manchester encoding provides
|
||||
% We need this to sync up to Manchester codewords. TODO plot signal and
|
||||
% timing "line" we extract
|
||||
|
||||
Np = length(rx_timing_sig);
|
||||
w = 2*pi*(Rs)/Fs;
|
||||
x = (rx_timing_sig .^ 2) * exp(-j*w*(0:Np-1))';
|
||||
norm_rx_timing = angle(x)/(2*pi) - 0.42;
|
||||
%rx_timing = round(norm_rx_timing*Ts);
|
||||
%printf("norm_rx_timing: %4.4f rx_timing: %d\n", norm_rx_timing, rx_timing);
|
||||
|
||||
% Max likelihood decoding of Manchester encoded symbols. Search
|
||||
% through all ML possibilities to extract bits. Use energy (filter
|
||||
% output sq)
|
||||
|
||||
% Manchester Decoding --------------------------------------------------------
|
||||
|
||||
if M == 2
|
||||
if demod == 1
|
||||
|
||||
% sample at optimum instant
|
||||
|
||||
[tmp l] = size(rx_filt);
|
||||
rx_filt_dec = rx_filt(:, Ts+rx_timing:Ts:l);
|
||||
|
||||
[tmp l] = size(rx_filt_dec);
|
||||
rx_bits = zeros(1,l);
|
||||
k = 1;
|
||||
for i=1:2:l-1
|
||||
ml = [rx_filt_dec(i)-rx_filt_dec(i+1) -rx_filt_dec(i)+rx_filt_dec(i+1)];
|
||||
[mx mx_ind] = max(ml);
|
||||
rx_bits(k) = mx_ind-1; k++;
|
||||
end
|
||||
end
|
||||
|
||||
if demod == 2
|
||||
|
||||
% sample at optimum instant
|
||||
|
||||
[tmp l] = size(rx_filt);
|
||||
rx_filt_dec = rx_filt(:, Ts+rx_timing:Ts:l);
|
||||
|
||||
[tmp l] = size(rx_filt_dec);
|
||||
rx_bits = zeros(1,l);
|
||||
k = 1;
|
||||
for i=1:2:l-1
|
||||
%ml = [rx_filt_dec(2,i)*rx_filt_dec(1,i+1) rx_filt_dec(1,i)*rx_filt_dec(2,i+1)];
|
||||
ml = [rx_filt_dec(2,i)+rx_filt_dec(1,i+1) rx_filt_dec(1,i)+rx_filt_dec(2,i+1)];
|
||||
[mx mx_ind] = max(ml);
|
||||
rx_bits(k) = mx_ind-1; k++;
|
||||
end
|
||||
end
|
||||
else % M == 4
|
||||
if demod == 1
|
||||
% TODO: 4FSK version of demod
|
||||
rx_bits=tx_bits;
|
||||
end
|
||||
if demod == 2
|
||||
% sample at optimal instant
|
||||
|
||||
[tmp l] = size(rx_filt);
|
||||
rx_filt_dec = rx_filt(:, Ts+rx_timing:Ts:l);
|
||||
[tmp l] = size(rx_filt_dec);
|
||||
rx_bits = zeros(1,l);
|
||||
|
||||
k = 1;
|
||||
fsk4_dec = [[0 0]; [0 1]; [1 0]; [1 1]];
|
||||
for i=1:2:l-1
|
||||
%ml = [rx_filt_dec(1,i)*rx_filt_dec(4,i+1) rx_filt_dec(4,i)*rx_filt_dec(1,i+1) rx_filt_dec(2,i)*rx_filt_dec(3,i+1) rx_filt_dec(3,i)*rx_filt_dec(2,i+1)];
|
||||
ml = [(rx_filt_dec(1,i)+rx_filt_dec(4,i+1)) (rx_filt_dec(4,i)+rx_filt_dec(1,i+1)) (rx_filt_dec(2,i)+rx_filt_dec(3,i+1)) (rx_filt_dec(3,i)+rx_filt_dec(2,i+1))];
|
||||
[mx mx_ind] = max(ml);
|
||||
rx_bits(k:k+1) = fsk4_dec(mx_ind,:); k+=2;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
% useful for getting decoding right
|
||||
%tx_bits(1:20)
|
||||
%rx_bits(1:20)
|
||||
|
||||
% Frame sync and BER logic -------------------------------------------------------------
|
||||
|
||||
st = 1;
|
||||
for f=1:frames
|
||||
|
||||
% extract nin bits
|
||||
|
||||
nin = nbits;
|
||||
en = st + nin - 1;
|
||||
|
||||
rx_bits_buf(1:nbits) = rx_bits_buf(nbits+1:2*nbits);
|
||||
rx_bits_buf(nbits+1:2*nbits) = rx_bits(st:en);
|
||||
|
||||
st += nin;
|
||||
|
||||
% frame sync based on min BER
|
||||
|
||||
if test_frame_mode == 1
|
||||
nerrs_min = nbits;
|
||||
next_state = state;
|
||||
if state == 0
|
||||
for i=1:nbits
|
||||
error_positions = xor(rx_bits_buf(i:nbits+i-1), test_frame);
|
||||
nerrs = sum(error_positions);
|
||||
%printf("i: %d nerrs: %d nerrs_min: %d \n", i, nerrs, nerrs_min);
|
||||
if nerrs < nerrs_min
|
||||
nerrs_min = nerrs;
|
||||
coarse_offset = i;
|
||||
end
|
||||
end
|
||||
if nerrs_min < 3
|
||||
next_state = 1;
|
||||
%printf("%d %d\n", coarse_offset, nerrs_min);
|
||||
end
|
||||
end
|
||||
|
||||
if state == 1
|
||||
error_positions = xor(rx_bits_buf(coarse_offset:coarse_offset+nbits-1), test_frame);
|
||||
nerrs = sum(error_positions);
|
||||
Terrs += nerrs;
|
||||
Tbits += nbits;
|
||||
nerr_log = [nerr_log nerrs];
|
||||
end
|
||||
|
||||
state = next_state;
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
if test_frame_mode == 1
|
||||
if sim_in.verbose
|
||||
printf(" demod: %d frames: %d EbNodB: %3.1f Tbits: %d Terrs: %d BER %4.3f\n", demod, frames, EbNodB, Tbits, Terrs, Terrs/Tbits);
|
||||
else
|
||||
printf(" EbNodB: %3.1f BER %4.3f\n", EbNodB, Terrs/Tbits);
|
||||
end
|
||||
end
|
||||
|
||||
% Bunch O'plots --------------------------------------------------------------
|
||||
|
||||
close all;
|
||||
|
||||
st = 1; en=20;
|
||||
|
||||
Tx=fft(tx, Fs);
|
||||
TxdB = 20*log10(abs(Tx(1:Fs/2)));
|
||||
figure(1)
|
||||
clf;
|
||||
plot(TxdB)
|
||||
axis([1 Fs/2 (max(TxdB)-100) max(TxdB)])
|
||||
title('Tx Spectrum');
|
||||
|
||||
figure(2)
|
||||
clf
|
||||
if demod == 1
|
||||
subplot(211)
|
||||
plot(rx_filt(st*Ts:en*Ts));
|
||||
title('After integrator');
|
||||
subplot(212)
|
||||
plot(rx_filt_dec(st:en),'+');
|
||||
title('Decimated output');
|
||||
end
|
||||
if demod == 2
|
||||
subplot(211);
|
||||
plot(rx_filt(1,st*Ts:en*Ts));
|
||||
hold on;
|
||||
plot(rx_filt(2,st*Ts:en*Ts),'g');
|
||||
if M == 4
|
||||
plot(rx_filt(3,st*Ts:en*Ts),'c');
|
||||
plot(rx_filt(4,st*Ts:en*Ts),'r');
|
||||
end
|
||||
hold off;
|
||||
title('Output of each filter');
|
||||
subplot(212);
|
||||
plot(rx_filt_dec(1,st:en),'+');
|
||||
hold on;
|
||||
plot(rx_filt_dec(2,st:en),'g+');
|
||||
if M == 4
|
||||
plot(rx_filt_dec(3,st:en),'c+');
|
||||
plot(rx_filt_dec(4,st:en),'r+');
|
||||
end
|
||||
hold off;
|
||||
title('Decimated output of each filter');
|
||||
end
|
||||
|
||||
figure(3)
|
||||
clf;
|
||||
subplot(211)
|
||||
plot(rx_timing_sig(st*Ts:en*Ts).^2)
|
||||
title('rx-timing-sig')
|
||||
subplot(212)
|
||||
F = abs(fft(rx_timing_sig(1:Fs)));
|
||||
plot(F(100:8000))
|
||||
title('FFT of rx-timing-sig')
|
||||
|
||||
if demod == 1
|
||||
figure(4);
|
||||
clf;
|
||||
h = fft(rx_out, Fs);
|
||||
hdB = 20*log10(abs(h));
|
||||
plot(hdB(1:4000))
|
||||
title('Spectrum of baseband modem signal after analog FM demod');
|
||||
axis([1 4000 (max(hdB)-40) max(hdB)])
|
||||
end
|
||||
|
||||
if demod == 1
|
||||
figure(5)
|
||||
clf;
|
||||
subplot(211)
|
||||
plot(rx_out(st*Ts:en*Ts));
|
||||
title('baseband modem signal after analog FM demod');
|
||||
subplot(212)
|
||||
plot(rx_out_hp(st*Ts:en*Ts));
|
||||
title('baseband modem signal after 300Hz filter');
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
% Run various permutations of simulation here ---------------------------------------
|
||||
|
||||
function run_single
|
||||
|
||||
sim_in.frames = 100;
|
||||
sim_in.test_frame_mode = 1;
|
||||
sim_in.M = 2;
|
||||
sim_in.Rs = 2400;
|
||||
sim_in.demod = 1;
|
||||
sim_in.EbNodB = 15;
|
||||
sim_in.timing_offset = 0.0;
|
||||
sim_in.hpf = 1;
|
||||
sim_in.verbose = 1;
|
||||
|
||||
run_sim(sim_in);
|
||||
endfunction
|
||||
|
||||
|
||||
function run_lots
|
||||
|
||||
% adjusted a few scenarios for about 2% BER so we can compare
|
||||
|
||||
sim_in.frames = 100;
|
||||
sim_in.test_frame_mode = 1;
|
||||
sim_in.M = 2;
|
||||
sim_in.Rs = 4800;
|
||||
sim_in.demod = 1;
|
||||
sim_in.EbNodB = 12;
|
||||
sim_in.timing_offset = 0.0;
|
||||
sim_in.hpf = 1;
|
||||
sim_in.verbose = 0;
|
||||
|
||||
printf("Rs=4800 2FSK ideal demod\n");
|
||||
sim_in.EbNodB = 8.5; sim_in.demod = 2; run_sim(sim_in);
|
||||
printf("Rs=4800 2FSK analog FM demod, not too shabby and pushes 2400bit/s thru a $40 HT!\n");
|
||||
sim_in.EbNodB = 12; sim_in.demod = 1; run_sim(sim_in);
|
||||
printf("Rs=2400 2FSK analog FM demod, needs more power for same BER! Che?\n");
|
||||
sim_in.Rs = 2400; sim_in.EbNodB = 15; run_sim(sim_in);
|
||||
printf("Hmm, doesn't improve with no 300Hz HPF, maybe due to less deviation?\n");
|
||||
sim_in.hpf = 0; run_sim(sim_in);
|
||||
printf("Rs=2400 4FSK ideal demod, nice low Eb/No!\n");
|
||||
sim_in.demod = 2; sim_in.M = 4; sim_in.Rs = 2400; sim_in.EbNodB = 6; run_sim(sim_in);
|
||||
endfunction
|
||||
|
||||
%run_single;
|
||||
run_lots;
|
||||
199
octave/mfsk.m
199
octave/mfsk.m
|
|
@ -1,199 +0,0 @@
|
|||
% mfsk.m
|
||||
% David Rowe Nov 2015
|
||||
|
||||
% Simulation to test m=2 and m=4 FSK demod
|
||||
|
||||
|
||||
1;
|
||||
|
||||
function sim_out = fsk_ber_test(sim_in)
|
||||
Fs = 96000;
|
||||
M = sim_in.M;
|
||||
Rs = sim_in.Rs;
|
||||
Ts = Fs/Rs;
|
||||
verbose = sim_in.verbose;
|
||||
|
||||
nbits = sim_in.nbits;
|
||||
nsym = sim_in.nbits*2/M;
|
||||
nsam = nsym*Ts;
|
||||
EsNodB = sim_in.EbNodB + 10*log10(M/2);
|
||||
|
||||
% printf("M: %d nbits: %d nsym: %d\n", M, nbits, nsym);
|
||||
|
||||
if M == 2
|
||||
f(1) = -Rs/2;
|
||||
f(2) = Rs/2;
|
||||
end
|
||||
if M == 4
|
||||
f(1) = -3*Rs/2;
|
||||
f(2) = -Rs/2;
|
||||
f(3) = Rs/2;
|
||||
f(4) = 3*Rs/2;
|
||||
end
|
||||
|
||||
% simulate over a range of Eb/No values
|
||||
|
||||
for ne = 1:length(EsNodB)
|
||||
Nerrs = Terrs = Tbits = 0;
|
||||
|
||||
aEsNodB = EsNodB(ne);
|
||||
EsNo = 10^(aEsNodB/10);
|
||||
variance = Fs/(Rs*EsNo);
|
||||
|
||||
% Modulator -------------------------------
|
||||
|
||||
tx_bits = round(rand(1, nbits));
|
||||
tx = zeros(1,nsam);
|
||||
tx_phase = 0;
|
||||
|
||||
for i=1:nsym
|
||||
if M == 2
|
||||
tone = tx_bits(i) + 1;
|
||||
else
|
||||
tone = (tx_bits(2*(i-1)+1:2*i) * [2 1]') + 1;
|
||||
end
|
||||
|
||||
tx_phase_vec = tx_phase + (1:Ts)*2*pi*f(tone)/Fs;
|
||||
tx((i-1)*Ts+1:i*Ts) = exp(j*tx_phase_vec);
|
||||
tx_phase = tx_phase_vec(Ts) - floor(tx_phase_vec(Ts)/(2*pi))*2*pi;
|
||||
end
|
||||
|
||||
% Channel ---------------------------------
|
||||
|
||||
% We use complex (single sided) channel simulation, as it's convenient
|
||||
% for the FM simulation.
|
||||
|
||||
noise = sqrt(variance/2)*(randn(1,nsam) + j*randn(1,nsam));
|
||||
rx = tx + noise;
|
||||
if verbose > 1
|
||||
printf("EbNo: %f Eb: %f var No: %f EbNo (meas): %f\n",
|
||||
EbNo, var(tx)*Ts/Fs, var(noise)/Fs, (var(tx)*Ts/Fs)/(var(noise)/Fs));
|
||||
end
|
||||
|
||||
% Demodulator -----------------------------
|
||||
|
||||
% non-coherent FSK demod
|
||||
|
||||
rx_bb = rx;
|
||||
dc = zeros(M,nsam);
|
||||
for m=1:M
|
||||
dc(m,:) = rx_bb .* exp(-j*(0:nsam-1)*2*pi*f(m)/Fs);
|
||||
end
|
||||
|
||||
rx_bits = zeros(1, nsym);
|
||||
for i=1:nsym
|
||||
st = (i-1)*Ts+1;
|
||||
en = st+Ts-1;
|
||||
for m=1:M
|
||||
int(m,i) = abs(sum(dc(m,st:en)));
|
||||
end
|
||||
if m == 2
|
||||
rx_bits(i) = int(1,i) < int(2,i);
|
||||
else
|
||||
[max_amp tone] = max([int(1,i) int(2,i) int(3,i) int(4,i)]);
|
||||
if tone == 1
|
||||
rx_bits(2*(i-1)+1:2*i) = [0 0];
|
||||
end
|
||||
if tone == 2
|
||||
rx_bits(2*(i-1)+1:2*i) = [0 1];
|
||||
end
|
||||
if tone == 3
|
||||
rx_bits(2*(i-1)+1:2*i) = [1 0];
|
||||
end
|
||||
if tone == 4
|
||||
rx_bits(2*(i-1)+1:2*i) = [1 1];
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
error_positions = xor(rx_bits, tx_bits);
|
||||
Nerrs = sum(error_positions);
|
||||
Terrs += Nerrs;
|
||||
Tbits += length(error_positions);
|
||||
|
||||
TERvec(ne) = Terrs;
|
||||
BERvec(ne) = Terrs/Tbits;
|
||||
|
||||
if verbose > 1
|
||||
figure(2)
|
||||
clf
|
||||
Rx = 10*log10(abs(fft(rx)));
|
||||
plot(Rx(1:Fs/2));
|
||||
axis([1 Fs/2 0 50]);
|
||||
|
||||
figure(3)
|
||||
clf;
|
||||
subplot(211)
|
||||
plot(real(rx_bb(1:Ts*20)))
|
||||
subplot(212)
|
||||
Rx_bb = 10*log10(abs(fft(rx_bb)));
|
||||
plot(Rx_bb(1:3000));
|
||||
axis([1 3000 0 50]);
|
||||
|
||||
figure(4);
|
||||
subplot(211)
|
||||
stem(abs(mark_int(1:100)));
|
||||
subplot(212)
|
||||
stem(abs(space_int(1:100)));
|
||||
end
|
||||
|
||||
if verbose
|
||||
printf("EbNo (db): %3.2f Terrs: %d BER: %4.3f \n", aEsNodB - 10*log10(M/2), Terrs, Terrs/Tbits);
|
||||
end
|
||||
end
|
||||
|
||||
sim_out.TERvec = TERvec;
|
||||
sim_out.BERvec = BERvec;
|
||||
endfunction
|
||||
|
||||
|
||||
function run_fsk_curves
|
||||
sim_in.M = 2;
|
||||
sim_in.Rs = 1200;
|
||||
sim_in.nbits = 12000;
|
||||
sim_in.EbNodB = 0:2:20;
|
||||
sim_in.verbose = 1;
|
||||
|
||||
EbNo = 10 .^ (sim_in.EbNodB/10);
|
||||
fsk_theory.BERvec = 0.5*exp(-EbNo/2); % non-coherent BFSK demod
|
||||
fsk2_sim = fsk_ber_test(sim_in);
|
||||
|
||||
sim_in.M = 4;
|
||||
fsk4_sim = fsk_ber_test(sim_in);
|
||||
|
||||
% BER v Eb/No curves
|
||||
|
||||
figure(1);
|
||||
clf;
|
||||
semilogy(sim_in.EbNodB, fsk_theory.BERvec,'r;2FSK theory;')
|
||||
hold on;
|
||||
semilogy(sim_in.EbNodB, fsk2_sim.BERvec,'g;2FSK sim;')
|
||||
semilogy(sim_in.EbNodB, fsk4_sim.BERvec,'b;4FSK sim;')
|
||||
hold off;
|
||||
grid("minor");
|
||||
axis([min(sim_in.EbNodB) max(sim_in.EbNodB) 1E-4 1])
|
||||
legend("boxoff");
|
||||
xlabel("Eb/No (dB)");
|
||||
ylabel("Bit Error Rate (BER)")
|
||||
|
||||
end
|
||||
|
||||
|
||||
function run_fsk_single
|
||||
sim_in.M = 4;
|
||||
sim_in.Rs = 1200;
|
||||
sim_in.nbits = 5000;
|
||||
sim_in.EbNodB = 8;
|
||||
sim_in.verbose = 1;
|
||||
|
||||
fsk_sim = fsk_ber_test(sim_in);
|
||||
endfunction
|
||||
|
||||
|
||||
rand('state',1);
|
||||
randn('state',1);
|
||||
graphics_toolkit ("gnuplot");
|
||||
|
||||
run_fsk_curves
|
||||
%run_fsk_single
|
||||
|
||||
|
|
@ -1,144 +0,0 @@
|
|||
% newamp1_fbf.m
|
||||
%
|
||||
% Copyright David Rowe 2016
|
||||
% This program is distributed under the terms of the GNU General Public License
|
||||
% Version 2
|
||||
%
|
||||
% Interactive Octave script to explore frame by frame operation of newamp1
|
||||
% spectral amplitude modelling.
|
||||
%
|
||||
% Usage:
|
||||
% Make sure codec2-dev is compiled with the -DDUMP option - see README for
|
||||
% instructions.
|
||||
% ~/codec2-dev/build_linux/src$ ./c2sim ../../raw/hts1a.raw --dump hts1a
|
||||
% $ cd ~/codec2-dev/octave
|
||||
% octave:14> newamp1_fbf("../build_linux/src/hts1a",50)
|
||||
|
||||
|
||||
function newamp1_fbf(samname, f=73, varargin)
|
||||
more off;
|
||||
|
||||
newamp_700c; melvq;
|
||||
load train_120_1.txt; load train_120_2.txt;
|
||||
train_120_vq(:,:,1)= train_120_1; train_120_vq(:,:,2)= train_120_2; m=5;
|
||||
|
||||
Fs = 8000; K = 20;
|
||||
|
||||
vq = 0; eq_en = 0; pf = 0;
|
||||
|
||||
% load up text files dumped from c2sim ---------------------------------------
|
||||
|
||||
sn_name = strcat(samname,"_sn.txt");
|
||||
Sn = load(sn_name);
|
||||
sw_name = strcat(samname,"_sw.txt");
|
||||
Sw = load(sw_name);
|
||||
model_name = strcat(samname,"_model.txt");
|
||||
model = load(model_name);
|
||||
[frames tmp] = size(model);
|
||||
|
||||
% pre-process
|
||||
[rate_K_surface sample_freqs_kHz] = resample_const_rate_f_mel(model(1:frames,:), K);
|
||||
|
||||
% we need to know eq states on each frame
|
||||
eq = zeros(frames,K); an_eq = zeros(1,K);
|
||||
for ff=1:frames
|
||||
mean_f = mean(rate_K_surface(ff,:));
|
||||
rate_K_vec_no_mean = rate_K_surface(ff,:) - mean_f;
|
||||
[tmp an_eq] = front_eq(rate_K_vec_no_mean, an_eq);
|
||||
eq(ff,:) = an_eq;
|
||||
end
|
||||
|
||||
% Keyboard loop --------------------------------------------------------------
|
||||
|
||||
k = ' ';
|
||||
do
|
||||
fg = 1;
|
||||
s = [ Sn(2*f-1,:) Sn(2*f,:) ];
|
||||
figure(fg++); clf; plot(s); axis([1 length(s) -20000 20000]);
|
||||
|
||||
Wo = model(f,1); L = model(f,2); Am = model(f,3:(L+2)); AmdB = 20*log10(Am);
|
||||
Am_freqs_kHz = (1:L)*Wo*4/pi;
|
||||
|
||||
% plots ----------------------------------
|
||||
|
||||
figure(fg++); clf;
|
||||
l = sprintf(";rate %d AmdB;g+-", L);
|
||||
plot((1:L)*Wo*4000/pi, AmdB, l);
|
||||
axis([1 4000 -20 80]);
|
||||
hold on;
|
||||
stem(sample_freqs_kHz*1000, rate_K_surface(f,:), ";rate K;b+-");
|
||||
|
||||
% default
|
||||
rate_K_vec_ = rate_K_surface(f,:);
|
||||
|
||||
mean_f = mean(rate_K_surface(f,:));
|
||||
rate_K_vec_no_mean = rate_K_surface(f,:) - mean_f;
|
||||
if eq_en
|
||||
rate_K_vec_no_mean -= eq(f,:);
|
||||
end
|
||||
rate_K_vec_no_mean_ = rate_K_vec_no_mean;
|
||||
if vq
|
||||
[res rate_K_vec_no_mean_ ind] = mbest(train_120_vq, rate_K_vec_no_mean, m);
|
||||
if pf
|
||||
rate_K_vec_no_mean_ = post_filter(rate_K_vec_no_mean_, sample_freqs_kHz, 1.5);
|
||||
end
|
||||
rate_K_vec_ = rate_K_vec_no_mean_ + mean_f;
|
||||
end
|
||||
|
||||
% back to rate L
|
||||
model_(f,:) = resample_rate_L(model(f,:), rate_K_vec_, sample_freqs_kHz);
|
||||
Am_ = model_(f,3:(L+2)); AmdB_ = 20*log10(Am_);
|
||||
varL = var(AmdB - AmdB_);
|
||||
|
||||
plot((1:L)*Wo*4000/pi, AmdB_,";AmdB bar;r+-");
|
||||
l = sprintf(";error var %3.2f dB;bk+-", varL);
|
||||
plot((1:L)*Wo*4000/pi, (AmdB - AmdB_), l);
|
||||
hold off;
|
||||
|
||||
figure(3); clf;
|
||||
plot(sample_freqs_kHz*1000, 40+ rate_K_vec_no_mean, ";rate K no mean;g+-");
|
||||
axis([1 4000 -20 80]); hold on;
|
||||
plot(sample_freqs_kHz*1000, 40 + rate_K_vec_no_mean_, ";rate K no mean bar;r+-");
|
||||
varK = var(rate_K_vec_no_mean - rate_K_vec_no_mean_);
|
||||
l = sprintf(";error var %3.2f dB;bk+-", varK);
|
||||
plot(sample_freqs_kHz*1000, rate_K_vec_no_mean - rate_K_vec_no_mean_, l);
|
||||
|
||||
plot(sample_freqs_kHz*1000, eq(f,:), ";eq;b+-");
|
||||
hold off;
|
||||
|
||||
% interactive menu ------------------------------------------
|
||||
|
||||
printf("\rframe: %d menu: n-next b-back q-quit v-vq[%d] p-pf[%d] e-eq[%d]", f, vq, pf, eq_en);
|
||||
fflush(stdout);
|
||||
k = kbhit();
|
||||
|
||||
if k == 'v'
|
||||
if vq == 0; vq = 1; else vq = 0; end
|
||||
endif
|
||||
if k == 'p'
|
||||
if pf == 0; pf = 1; else pf = 0; end
|
||||
endif
|
||||
if k == 'e'
|
||||
if eq_en == 0; eq_en = 1; else eq_en = 0; end
|
||||
endif
|
||||
if k == 'n'
|
||||
f = f + 1;
|
||||
endif
|
||||
if k == 'b'
|
||||
f = f - 1;
|
||||
endif
|
||||
|
||||
until (k == 'q')
|
||||
printf("\n");
|
||||
|
||||
endfunction
|
||||
|
||||
|
||||
function ind = arg_exists(v, str)
|
||||
ind = 0;
|
||||
for i=1:length(v)
|
||||
if !ind && strcmp(v{i}, str)
|
||||
ind = i;
|
||||
end
|
||||
end
|
||||
endfunction
|
||||
|
|
@ -1,129 +0,0 @@
|
|||
% nf_from_gr.m
|
||||
% David Rowe Mar 2016
|
||||
|
||||
#{
|
||||
Calculate NF from GNU Radio output samples in
|
||||
...IQIQ... (32 bit float) sample files
|
||||
|
||||
1/ Take one sample with a -100dBm input carrier
|
||||
2/ Take another sample with no signal (just rx noise)
|
||||
3/ Set Fs, adjust st and en to use a chunk of spectrum without too
|
||||
many birdies.
|
||||
|
||||
Gotchas:
|
||||
|
||||
1/ Inspect Figure(1), the time domain plots.
|
||||
2/ Make sure plenty of ADC bits are being used with the noise-only sample,
|
||||
we don't want ADC quantisation noise to dominate. Aim for about half
|
||||
full scale.
|
||||
3/ Also watch out for clipping on either sample.
|
||||
|
||||
#}
|
||||
|
||||
1;
|
||||
|
||||
function det_nf(p_filename, n_filename, title, Fs, st, en, Pin_dB, real_file=0)
|
||||
|
||||
if real_file
|
||||
% real samples files of 16 bit shorts
|
||||
fs=fopen(p_filename,"rb");
|
||||
p = fread(fs,Inf,"short");
|
||||
fclose(fs);
|
||||
fs=fopen(n_filename,"rb");
|
||||
pn = fread(fs,Inf,"short");
|
||||
fclose(fs);
|
||||
else
|
||||
% GNU radio complex file input
|
||||
p = load_comp(p_filename);
|
||||
pn = load_comp(n_filename);
|
||||
end
|
||||
|
||||
% skip any start up transients
|
||||
|
||||
tst = floor(0.1*Fs); ten = st + Fs - 1;
|
||||
P = fft(p(tst:ten));
|
||||
N = fft(pn(tst:ten));
|
||||
|
||||
PdB = 20*log10(abs(P));
|
||||
NdB = 20*log10(abs(N));
|
||||
|
||||
figure(1); clf;
|
||||
subplot(211); plot(real(p(tst:tst+floor(Fs*0.1))));
|
||||
subplot(212); plot(real(pn(tst:tst+floor(Fs*0.1))));
|
||||
|
||||
figure(2); clf;
|
||||
subplot(211); plot(st:en, PdB(st:en));
|
||||
subplot(212); plot(st:en, NdB(st:en));
|
||||
|
||||
#{
|
||||
------------------------------------------------------------------------
|
||||
|
||||
From Wikipedia: The Noise Figure is the difference in decibels
|
||||
(dB) between the noise output of the actual receiver to the noise
|
||||
output of an “ideal” receiver
|
||||
|
||||
An ideal receiver would have an output noise power of:
|
||||
|
||||
Nout_dB = 10log10(B) -174 + G_dB
|
||||
|
||||
The -174 dBm/Hz figure is the thermal noise density at 25C, for
|
||||
every 1Hz of bandwidth your will get -174dBm of noise power. It's
|
||||
the lower limit set by the laws of physics. G_dB is the Rx gain. The
|
||||
10log10(B) term takes into account the bandwidth of the Rx. A wider
|
||||
bandwidth means more total noise power.
|
||||
|
||||
So if you have a 1Hz bandwidth, and a gain of 100dB, you would
|
||||
expect Nout_NdB = 0 -174 + 100 = -74dBm at the rx output with no
|
||||
signal. If you have a 1000Hz bandwidth receiver you would have NdB_out
|
||||
= 20 -174 + 100 = -44dBm of noise power at the output.
|
||||
|
||||
To determine Noise Figure:
|
||||
1) Sample the Rx output first with a test signal and then with noise only.
|
||||
2) Find the Rx gain using the test signal.
|
||||
3) Find the noise output power, then using the gain we can find the noise
|
||||
input power.
|
||||
4) Normalise the noise input power to 1Hz noise bandwidth and
|
||||
compare to the thermal noise floor.
|
||||
|
||||
----------------------------------------------------------------------------
|
||||
#}
|
||||
|
||||
% variance is the power of a sampled signal
|
||||
|
||||
Pout_dB = 10*log10(var(P(st:en))); % Rx output power with test signal
|
||||
G_dB = Pout_dB - Pin_dB; % Gain of Rx
|
||||
Nout_dB = 10*log10(var(N(st:en))); % Rx output power with noise
|
||||
Nin_dB = Nout_dB - G_dB; % Rx input power with noise
|
||||
No_dB = Nin_dB - 10*log10(en-st); % Rx input power with noise in 1Hz bandwidth
|
||||
NF_dB = No_dB + 174; % compare to thermal noise to get NF
|
||||
printf("%10s: Pin: %4.1f Pout: %4.1f G: %4.1f NF: %3.1f dB\n", title, Pin_dB, Pout_dB, G_dB, NF_dB);
|
||||
endfunction
|
||||
|
||||
|
||||
% HackRF --------------------------
|
||||
|
||||
%p_filename = "~/Desktop/blogs/nf/hackrf_100dbm_4MHz.bin";
|
||||
%n_filename = "~/Desktop/blogs/nf/hackrf_nosignal_4MHz.bin";
|
||||
p_filename = "~/codec2-dev/build_linux/unittest/hackrf_100dbm_4MHz.bin";
|
||||
n_filename = "~/codec2-dev/build_linux/unittest/hackrf_nosignal_4MHz.bin";
|
||||
det_nf(p_filename, n_filename, "HackRF", 4E6, 180E3, 600E3, -100);
|
||||
|
||||
#{
|
||||
% RTL-SDR --------------------------
|
||||
|
||||
p_filename = "~/Desktop/nf/neg100dBm_2MHz.bin";
|
||||
n_filename = "~/Desktop/nf/nosignal_2MHz.bin";
|
||||
det_nf(p_filename, n_filename, "RTL-SDR", 2E6, 100E3, 300E3, -100);
|
||||
|
||||
% AirSpy -------------------------
|
||||
|
||||
p_filename = "~/Desktop/nf/airspy_100dbm_2.5MSPS.bin";
|
||||
n_filename = "~/Desktop/nf/airspy_nosig_2.5MSPS.bin";
|
||||
det_nf(p_filename, n_filename, "AirSpy", 2.5E6, 100E3, 300E3, -100);
|
||||
|
||||
% Fun Cube Dongle Pro Plus -------------------------
|
||||
|
||||
p_filename = "~/Desktop/nf/fcdpp_100dbm_192khz.bin";
|
||||
n_filename = "~/Desktop/nf/fcdpp_nosig_192khz.bin";
|
||||
det_nf(p_filename, n_filename, "FunCube PP", 192E3, 25E3, 125E3, -100);
|
||||
#}
|
||||
|
|
@ -1,133 +0,0 @@
|
|||
% nf_from_gr.m
|
||||
% David Rowe Mar 2018
|
||||
|
||||
#{
|
||||
|
||||
Calculate NF in real time from 16 bit real samples from stdin
|
||||
|
||||
1/ Using gqrx:
|
||||
|
||||
gqrx setup:
|
||||
Configure I/O devices:
|
||||
To switch on LNA bias for HackRF, in Configure I/O devices menu set:
|
||||
Device String: hackrf,bias=1
|
||||
To switch on LNA bias for airspy run for a few seconds this before starting gqrx:
|
||||
$ airspy_rx -r /dev/null -f 435 -b 1
|
||||
I used a sample rate of 250000 for Airspy R2, 3000000 for Airspy Mini
|
||||
Input options...: start with set all gain sliders set to maximum
|
||||
FFT Setting.....: freq Zoom to max
|
||||
Receiver Options: On spectrum display, drag filter width until it's about 12k
|
||||
Filter Shape Normal
|
||||
Mode USB
|
||||
Tune until tone is between 2 and 4 k
|
||||
Press UDP button
|
||||
|
||||
Then in a Linux Term:
|
||||
|
||||
$ nc -ul 7355 | octave --no-gui -qf nf_from_stdio.m 48000
|
||||
|
||||
2/ Using command line tools. Compile airspy tools and csdr from source:
|
||||
|
||||
a) Airspy:
|
||||
|
||||
$ airspy_rx -a 6000000 -l 14 -m 15 -v 15 -r - -f 434.998 -b 1 | \
|
||||
csdr convert_s16_f | csdr fir_decimate_cc 50 | csdr convert_f_s16 | \
|
||||
octave --no-gui -qf ~/codec2-dev/octave/nf_from_stdio.m 120000 complex
|
||||
|
||||
Note: we tuned a few kHz down to put the test tone in the 2000 to 4000 Hz range.
|
||||
|
||||
b) HackRF:
|
||||
|
||||
Term 1:
|
||||
|
||||
$ ~/codec2-dev/octave$ nc -ul 7355 | octave --no-gui -qf nf_from_stdio.m 80000 complex
|
||||
|
||||
Term 2:
|
||||
|
||||
$ hackrf_transfer -r - -f 434995000 -s 4000000 -a 1 -p 1 -l 40 -g 32 | \
|
||||
csdr convert_s8_f | csdr fir_decimate_cc 50 | csdr convert_f_s16 | \
|
||||
nc localhost -u 7355
|
||||
|
||||
Note: HackRF needed a bit of tuning to get test tone in 2000 to 4000 Hz range. This
|
||||
can be tricky with the command line method, easier with gqrx.
|
||||
|
||||
c) rtlsdr (assuming sig gen set to 144.5MHz, -100dBm)
|
||||
|
||||
Term 1:
|
||||
|
||||
$ ./rtl_sdr -g 50 -s 2400000 -f 144.498E6 - | csdr convert_u8_f | csdr fir_decimate_cc 50 | \
|
||||
csdr convert_f_s16 | octave --no-gui -qf ~/codec2/octave/nf_from_stdio.m 48000 complex
|
||||
|
||||
TODO:
|
||||
[ ] work out why noise power st bounces around so much, signal power seems stable
|
||||
[ ] reduce CPU load, in particular of plotting
|
||||
#}
|
||||
|
||||
graphics_toolkit ("gnuplot")
|
||||
|
||||
% command line arguments
|
||||
|
||||
arg_list = argv ();
|
||||
if nargin == 0
|
||||
printf("\nusage: %s FsHz [real|complex] [testToneLeveldBm]\n\n", program_name());
|
||||
exit(0);
|
||||
end
|
||||
|
||||
Fs = str2num(arg_list{1});
|
||||
shorts_per_sample = 1;
|
||||
|
||||
if nargin == 2
|
||||
if strcmp(arg_list{2}, "real")
|
||||
shorts_per_sample = 1;
|
||||
end
|
||||
if strcmp(arg_list{2}, "complex")
|
||||
shorts_per_sample = 2;
|
||||
end
|
||||
end
|
||||
|
||||
Pin_dB = -100; % level of input test tone
|
||||
if nargin == 3
|
||||
Pin_dB = str2num(arg_list{3});
|
||||
end
|
||||
|
||||
printf("Fs: %d shorts_per_sample: %d Pin_dB: %f\n", Fs, shorts_per_sample, Pin_dB);
|
||||
|
||||
[s,c] = fread(stdin, shorts_per_sample*Fs, "short");
|
||||
|
||||
while c
|
||||
if shorts_per_sample == 2
|
||||
s = s(1:2:end)+j*s(2:2:end);
|
||||
end
|
||||
S = fft(s.*hanning(Fs));
|
||||
SdB = 20*log10(abs(S));
|
||||
figure(1); plot(real(s)); axis([0 Fs -4E4 4E4]);
|
||||
figure(2); plot(SdB); axis([0 12000 40 180]);
|
||||
|
||||
% assume sine wave is between 2000 and 4000 Hz, and dominates energy in that
|
||||
% region. Noise is between 5000 - 10000 Hz
|
||||
|
||||
sig_st = 2000; sig_en = 5000;
|
||||
noise_st = 6000; noise_en = 10000;
|
||||
|
||||
% find peak and sum power a few bins either side, this ensure we don't capture
|
||||
% too much noise as well
|
||||
|
||||
[pk pk_pos] = max(abs(S));
|
||||
if pk_pos > 5
|
||||
Pout_dB1 = 10*log10(sum(abs(S(pk_pos-5:pk_pos+5)).^2)); % Rx output power with test signal
|
||||
else
|
||||
Pout_dB1 = 0;
|
||||
end
|
||||
|
||||
Pout_dB = 10*log10(sum(abs(S(sig_st:sig_en)).^2)); % Rx output power with test signal
|
||||
G_dB = Pout_dB - Pin_dB; % Gain of Rx
|
||||
Nout_dB = 10*log10(sum(abs(S(noise_st:noise_en)).^2)/(noise_en-noise_st)); % Rx output power with noise
|
||||
Nin_dB = Nout_dB - G_dB; % Rx input power with noise
|
||||
No_dB = Nin_dB; %- 10*log10(noise_en-noise_st); % Rx input power with noise in 1Hz bandwidth
|
||||
NF_dB = No_dB + 174; % compare to thermal noise to get NF
|
||||
printf("Pout: %4.1f %d %4.1f Nout: %4.1f G: %4.1f No: %4.1f NF: %3.1f dB\n", Pout_dB, pk_pos, Pout_dB1, Nout_dB, G_dB, No_dB, NF_dB);
|
||||
|
||||
pause(2);
|
||||
[s,c] = fread(stdin, shorts_per_sample*Fs, "short");
|
||||
endwhile
|
||||
|
||||
521
octave/oqpsk.m
521
octave/oqpsk.m
|
|
@ -1,521 +0,0 @@
|
|||
% oqpsk.m
|
||||
% David Rowe Jan 2017
|
||||
%
|
||||
% Unfiltered OQPSK modem implementation and simulations to test,
|
||||
% derived from GMSK modem in gmsk.m
|
||||
%
|
||||
% Usage: see "choose one of these to run" at the end of this file.
|
||||
|
||||
rand('state',1);
|
||||
randn('state',1);
|
||||
graphics_toolkit ("gnuplot");
|
||||
format
|
||||
more off;
|
||||
|
||||
% init modem states
|
||||
|
||||
function oqpsk_states = oqpsk_init(oqpsk_states, Rs)
|
||||
|
||||
% general
|
||||
|
||||
verbose = oqpsk_states.verbose;
|
||||
oqpsk_states.Fs = 4*Rs;
|
||||
oqpsk_states.Rs = Rs;
|
||||
oqpsk_states.bps = 2; % two bit/symbol for QPSK
|
||||
|
||||
M = oqpsk_states.M = oqpsk_states.Fs/oqpsk_states.Rs;
|
||||
assert(floor(M) == M, "oversampling factor M must be an integer");
|
||||
assert(floor(M/2) == M/2, "(oversampling factor M)/2 must be an integer to offset QPSK");
|
||||
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
|
||||
|
||||
|
||||
% Unfiltered OQPSK modulator
|
||||
|
||||
function [tx tx_symb] = oqpsk_mod(oqpsk_states, tx_bits)
|
||||
M = oqpsk_states.M;
|
||||
bps = oqpsk_states.bps;
|
||||
nsym = length(tx_bits)/bps;
|
||||
nsam = nsym*M;
|
||||
verbose = oqpsk_states.verbose;
|
||||
|
||||
% Map bits to Gray coded QPSK symbols
|
||||
|
||||
tx_symb = zeros(1,nsym);
|
||||
|
||||
for i=1:nsym
|
||||
tx_symb(i) = qpsk_mod(tx_bits(2*i-1:2*i))*exp(j*pi/4);
|
||||
end
|
||||
|
||||
% Oversample by M (sample and hold) to create unfiltered QPSK
|
||||
|
||||
tx = zeros(1, nsam);
|
||||
for i=1:nsym
|
||||
tx((i-1)*M+1:(i*M)) = tx_symb(i);
|
||||
end
|
||||
|
||||
% delay Q arm by half of a symbol to make OQPSK
|
||||
|
||||
tx = [real(tx) zeros(1,M/2)] + j*[zeros(1,M/2) imag(tx)];
|
||||
endfunction
|
||||
|
||||
|
||||
#{
|
||||
|
||||
Unfiltered OQPSK demodulator function, with (optional) phase and
|
||||
timing estimation. Adapted from Fig 8 of [1]. See also gmsk.m and
|
||||
[2].
|
||||
|
||||
Note demodulator returns phase corrected symbols sampled at ideal
|
||||
timing instant. These symbols may have a m*pi/2 phase ambiguity due
|
||||
to properties of phase tracking loop. The caller is responsible for
|
||||
determining this ambiguity and recovering the actual bits.
|
||||
|
||||
[1] GMSK demodulator in IEEE Trans on Comms, Muroyta et al, 1981,
|
||||
"GSM Modulation for Digital Radio Telephony".
|
||||
|
||||
[2] GMSK Modem Simulation, http://www.rowetel.com/?p=3824
|
||||
|
||||
#}
|
||||
|
||||
|
||||
function [rx_symb rx_int filt_log dco_log timing_adj Toff] = oqpsk_demod(oqpsk_states, rx)
|
||||
M = oqpsk_states.M;
|
||||
Rs = oqpsk_states.Rs;
|
||||
Fs = oqpsk_states.Fs;
|
||||
nsam = length(rx);
|
||||
nsym = floor(nsam/M);
|
||||
verbose = oqpsk_states.verbose;
|
||||
|
||||
timing_angle_log = zeros(1,length(rx));
|
||||
rx_int = zeros(1,length(rx));
|
||||
dco_log = filt_log = zeros(1,nsam);
|
||||
|
||||
% Unfiltered PSK - integrate energy in symbols M long in re and im arms
|
||||
|
||||
rx_int = conv(rx,ones(1,M))/M;
|
||||
|
||||
% phase and fine frequency tracking and correction ------------------------
|
||||
|
||||
if oqpsk_states.phase_est
|
||||
|
||||
% DCO design from "Introduction To Phase-Lock Loop System Modeling", Wen Li
|
||||
% http://www.ece.ualberta.ca/~ee401/parts/data/PLLIntro.pdf
|
||||
|
||||
eta = 0.707;
|
||||
wn = 2*pi*10*(Rs/4800); % (Rs/4800) -> found reducing the BW beneficial with falling Rs
|
||||
Ts = 1/Fs;
|
||||
g1 = 1 - exp(-2*eta*wn*Ts);
|
||||
g2 = 1 + exp(-2*eta*wn*Ts) - 2*exp(-eta*wn*Ts)*cos(wn*Ts*sqrt(1-eta*eta));
|
||||
Gpd = 2/pi;
|
||||
Gvco = 1;
|
||||
G1 = g1/(Gpd*Gvco); G2 = g2/(Gpd*Gvco);
|
||||
%printf("g1: %e g2: %e G1: %e G2: %e\n", g1, g2, G1, G2);
|
||||
|
||||
filt_prev = dco = lower = ph_err_filt = ph_err = 0;
|
||||
end
|
||||
|
||||
if oqpsk_states.timing_est
|
||||
% w is the ref sine wave at the timing clock frequency
|
||||
% tw is the length of the window used to estimate timing
|
||||
|
||||
tw = 200*M;
|
||||
k = 1;
|
||||
xr_log = []; xi_log = [];
|
||||
w_log = [];
|
||||
timing_clock_phase = 0;
|
||||
timing_angle = 0;
|
||||
timing_angle_log = zeros(1,nsam);
|
||||
end
|
||||
|
||||
% Sample by sample processing loop for timing and phase est. Note
|
||||
% this operates at sample rate Fs, unlike many PSK modems that
|
||||
% operate at the symbol rate Rs
|
||||
|
||||
for i=1:nsam
|
||||
|
||||
if oqpsk_states.timing_est
|
||||
|
||||
% update sample timing estimate every tw samples, free wheel
|
||||
% rest of the time
|
||||
|
||||
if mod(i,tw) == 0
|
||||
l = i - tw+1;
|
||||
xr = abs(real(rx_int(l:l+tw-1)));
|
||||
xi = abs(imag(rx_int(l:l+tw-1)));
|
||||
w = exp(j*(l:l+tw-1)*2*pi*Rs/Fs);
|
||||
X = xr * w';
|
||||
timing_clock_phase = timing_angle = angle(X);
|
||||
k++;
|
||||
xr_log = [xr_log xr];
|
||||
xi_log = [xi_log xi];
|
||||
w_log = [w_log w];
|
||||
else
|
||||
timing_clock_phase += (2*pi)/M;
|
||||
end
|
||||
timing_angle_log(i) = timing_angle;
|
||||
end
|
||||
|
||||
if oqpsk_states.phase_est
|
||||
|
||||
% PLL per-sample processing
|
||||
|
||||
rx_int(i) *= exp(-j*dco);
|
||||
ph_err = sign(real(rx_int(i))*imag(rx_int(i)))*cos(timing_clock_phase);
|
||||
lower = ph_err*G2 + lower;
|
||||
filt = ph_err*G1 + lower;
|
||||
dco_log(i) = dco;
|
||||
dco = dco + filt;
|
||||
filt_log(i) = filt;
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
% final adjustment of timing output to take into account slowly
|
||||
% moving estimates due to sample clock offset. Unwrap ensures that
|
||||
% when timing angle jumps from -pi to pi we move to the next symbol
|
||||
% and frame sync isn't broken
|
||||
|
||||
timing_adj = timing_angle_log*M/(2*pi);
|
||||
timing_adj_uw = unwrap(timing_angle_log)*M/(2*pi);
|
||||
% Toff = floor(2*M+timing_adj);
|
||||
Toff = floor(timing_adj_uw+0.5);
|
||||
|
||||
% sample integrator output at correct timing instant
|
||||
|
||||
k = 1;
|
||||
re_syms = im_syms = zeros(1,nsym);
|
||||
rx_symb = [];
|
||||
for i=M:M:nsam
|
||||
if i-Toff(i)+M/2 <= nsam
|
||||
re_syms(k) = real(rx_int(i-Toff(i)));
|
||||
im_syms(k) = imag(rx_int(i-Toff(i)+M/2));
|
||||
%re_syms(k) = real(rx_int(i));
|
||||
%im_syms(k) = imag(rx_int(i));
|
||||
rx_symb = [rx_symb re_syms(k) + j*im_syms(k)];
|
||||
k++;
|
||||
end
|
||||
end
|
||||
|
||||
endfunction
|
||||
|
||||
|
||||
% Test modem over a range Eb/No points in an AWGN channel. Can
|
||||
% simulate a variety of channel impairments and performs ambiguity
|
||||
% resolution.
|
||||
|
||||
function sim_out = oqpsk_test(sim_in)
|
||||
bitspertestframe = sim_in.bitspertestframe;
|
||||
nbits = sim_in.nbits;
|
||||
EbNodB = sim_in.EbNodB;
|
||||
verbose = sim_in.verbose;
|
||||
Rs = 4800;
|
||||
|
||||
oqpsk_states.verbose = verbose;
|
||||
oqpsk_states.coherent_demod = sim_in.coherent_demod;
|
||||
oqpsk_states.phase_est = sim_in.phase_est;
|
||||
oqpsk_states.timing_est = sim_in.timing_est;
|
||||
oqpsk_states = oqpsk_init(oqpsk_states, Rs);
|
||||
M = oqpsk_states.M;
|
||||
Fs = oqpsk_states.Fs;
|
||||
Rs = oqpsk_states.Rs;
|
||||
sample_clock_offset_ppm = sim_in.sample_clock_offset_ppm;
|
||||
|
||||
tx_testframe = round(rand(1, bitspertestframe));
|
||||
ntestframes = floor(nbits/bitspertestframe);
|
||||
tx_bits = [];
|
||||
for i=1:ntestframes
|
||||
tx_bits = [tx_bits tx_testframe];
|
||||
end
|
||||
|
||||
for ne = 1:length(EbNodB)
|
||||
aEbNodB = EbNodB(ne);
|
||||
EbNo = 10^(aEbNodB/10);
|
||||
variance = Fs/(Rs*EbNo*oqpsk_states.bps);
|
||||
|
||||
[tx tx_symb] = oqpsk_mod(oqpsk_states, tx_bits);
|
||||
if sample_clock_offset_ppm
|
||||
tx = resample(tx, 1E6, 1E6-sample_clock_offset_ppm);
|
||||
end
|
||||
nsam = length(tx);
|
||||
|
||||
phi = sim_in.phase_offset + 2*pi*sim_in.freq_offset*(1:nsam)/M;
|
||||
|
||||
noise = sqrt(variance/2)*(randn(1,nsam) + j*randn(1,nsam));
|
||||
st = 1+sim_in.timing_offset; en = length(tx);
|
||||
rx = tx(st:en).*exp(j*phi(st:en)) + noise(st:en);
|
||||
|
||||
[rx_symb rx_int filt_log dco_log timing_adj Toff] = oqpsk_demod(oqpsk_states, rx);
|
||||
|
||||
% OK so the phase and timing estimators get us close (e.g. a good
|
||||
% scatter diagram), but no banana just yet. One problem is the
|
||||
% PLL can lock up on mulitples of pi/2. Combinations of phase
|
||||
% offsets can confuse the timing estimator. One tricky example is a
|
||||
% phase offset of pi/2 which swaps I & Q, and with OQPSK (unlike
|
||||
% MSK and friends) we can't easily tell which is I and which is Q
|
||||
% after a phase rotation, e.g. could be IQIQIQI or QIQIQIQ
|
||||
|
||||
% So we need to determine the ambiguities:
|
||||
% a) could be m*pi/2 rotations of phase
|
||||
% b) could be I and Q swapped by timing est
|
||||
% c) time alignment of test frame
|
||||
|
||||
nsymb = bitspertestframe/oqpsk_states.bps;
|
||||
nrx_symb = length(rx_symb);
|
||||
rx_bits = zeros(1, bitspertestframe);
|
||||
atx_symb = tx_symb(1:nsymb);
|
||||
|
||||
% Treat I and Q as separate sequences, each with their own unique
|
||||
% word. In our case the UW is the whole test frame. Correlate rx
|
||||
% sequence with tx sequence at each possible offset through the
|
||||
% received symbols to find the test frames. Note we also
|
||||
% correlate I of tx with Q of rx to trap any IQ swaps.
|
||||
|
||||
% The sign of the I and Q correlation lets us sort out the pi/2
|
||||
% phase rotation issue.
|
||||
|
||||
nerrs_tot = 0; nbits_tot = 0;
|
||||
|
||||
max_corr = real(atx_symb) * real(atx_symb)';
|
||||
for offset=2:nrx_symb-nsymb+1
|
||||
corr_ii(offset) = real(atx_symb) * real(rx_symb(offset:offset+nsymb-1))'/max_corr;
|
||||
corr_qq(offset) = imag(atx_symb) * imag(rx_symb(offset:offset+nsymb-1))'/max_corr;
|
||||
corr_iq(offset) = real(atx_symb) * imag(rx_symb(offset:offset+nsymb-1))'/max_corr;
|
||||
corr_qi(offset) = imag(atx_symb) * real(rx_symb(offset:offset+nsymb-1))'/max_corr;
|
||||
%printf("offset: %2d ii: % 5f qq: % 5f iq: % 5f qi: % 5f\n",
|
||||
%offset, corr_ii(offset), corr_qq(offset), corr_iq(offset), corr_qi(offset));
|
||||
|
||||
if abs(corr_ii(offset)) > 0.8
|
||||
|
||||
% no IQ swap, or time offset
|
||||
|
||||
i_sign = sign(corr_ii(offset));
|
||||
q_sign = sign(corr_qq(offset));
|
||||
arx_symb = i_sign*real(rx_symb(offset:offset+nsymb-1)) + j*q_sign*imag(rx_symb(offset:offset+nsymb-1));
|
||||
|
||||
for i=1:nsymb
|
||||
rx_bits(2*i-1:2*i) = qpsk_demod(arx_symb(i)*exp(-j*pi/4));
|
||||
end
|
||||
nerrs = sum(xor(tx_testframe, rx_bits));
|
||||
if verbose > 2
|
||||
printf("offset: %5d swap: %d i_sign: % 2.1f q_sign: % 2.1f nerr: %d\n",
|
||||
offset, 0, i_sign, q_sign, nerrs);
|
||||
end
|
||||
nerrs_tot += nerrs;
|
||||
nbits_tot += bitspertestframe;
|
||||
end
|
||||
|
||||
if abs(corr_qi(offset)) > 0.8
|
||||
|
||||
% IQ swap, I part in Q part of symbol before
|
||||
|
||||
i_sign = sign(corr_iq(offset-1));
|
||||
q_sign = sign(corr_qi(offset));
|
||||
arx_symb = i_sign*imag(rx_symb(offset-1:offset+nsymb-2)) + j*q_sign*real(rx_symb(offset:offset+nsymb-1));
|
||||
|
||||
for i=1:nsymb
|
||||
rx_bits(2*i-1:2*i) = qpsk_demod(arx_symb(i)*exp(-j*pi/4));
|
||||
end
|
||||
nerrs = sum(xor(tx_testframe, rx_bits));
|
||||
if verbose > 1
|
||||
printf("offset: %5d swap: %d i_sign: % 2.1f q_sign: % 2.1f nerr: %d\n",
|
||||
offset, 1, i_sign, q_sign, nerrs);
|
||||
end
|
||||
nerrs_tot += nerrs;
|
||||
nbits_tot += bitspertestframe;
|
||||
end
|
||||
end
|
||||
|
||||
TERvec(ne) = nerrs_tot;
|
||||
BERvec(ne) = nerrs_tot/nbits_tot;
|
||||
|
||||
if verbose > 0
|
||||
printf("EbNo dB: %3.1f Nbits: %d Nerrs: %d BER: %4.3f BER Theory: %4.3f\n",
|
||||
aEbNodB, nbits_tot, nerrs_tot, BERvec(ne), 0.5*erfc(sqrt(EbNo)));
|
||||
end
|
||||
|
||||
if find(sim_in.plots == 1)
|
||||
figure(1); clf;
|
||||
subplot(211)
|
||||
stem(real(tx))
|
||||
title('Tx samples');
|
||||
ylabel('Inphase');
|
||||
subplot(212)
|
||||
stem(imag(tx))
|
||||
ylabel('Quadrature');
|
||||
end
|
||||
|
||||
if find(sim_in.plots == 2)
|
||||
figure(2); clf;
|
||||
f = fftshift(fft(rx));
|
||||
Tx = 20*log10(abs(f));
|
||||
plot((1:length(f))*Fs/length(f) - Fs/2, Tx)
|
||||
grid;
|
||||
title('OQPSK Demodulator Input Spectrum');
|
||||
end
|
||||
|
||||
if find(sim_in.plots == 3)
|
||||
figure(3); clf;
|
||||
nplot = min(16, nbits/oqpsk_states.bps);
|
||||
title('Rx Integrator');
|
||||
subplot(211)
|
||||
stem(real(rx_int(1:nplot*M)))
|
||||
axis([1 nplot*M -1 1])
|
||||
subplot(212)
|
||||
stem(imag(rx_int(1:nplot*M)))
|
||||
axis([1 nplot*M -1 1])
|
||||
end
|
||||
|
||||
if find(sim_in.plots == 4)
|
||||
figure(4); clf;
|
||||
subplot(211);
|
||||
plot(filt_log);
|
||||
title('PLL filter')
|
||||
subplot(212);
|
||||
plot(dco_log);
|
||||
title('PLL DCO phase');
|
||||
end
|
||||
|
||||
if find(sim_in.plots == 5)
|
||||
figure(5); clf;
|
||||
subplot(211)
|
||||
plot(timing_adj);
|
||||
title('Timing est');
|
||||
subplot(212)
|
||||
plot(Toff);
|
||||
title('Timing est unwrap');
|
||||
end
|
||||
|
||||
if find(sim_in.plots == 6)
|
||||
figure(6); clf;
|
||||
st = floor(0.5*nrx_symb);
|
||||
plot(rx_symb(st:nrx_symb), '+');
|
||||
title('Scatter Diagram');
|
||||
axis([-1.5 1.5 -1.5 1.5])
|
||||
end
|
||||
|
||||
if find(sim_in.plots == 7)
|
||||
figure(7); clf;
|
||||
subplot(211)
|
||||
plot(corr_ii);
|
||||
axis([1 length(corr_ii) -1.2 1.2]);
|
||||
title('corr ii');
|
||||
subplot(212)
|
||||
plot(corr_qi);
|
||||
axis([1 length(corr_ii) -1.2 1.2]);
|
||||
title('corr qi');
|
||||
end
|
||||
|
||||
if find(sim_in.plots == 8)
|
||||
figure(8); clf;
|
||||
subplot(211);
|
||||
stem(real(arx_symb));
|
||||
title('Rx symbols')
|
||||
subplot(212);
|
||||
stem(imag(arx_symb));
|
||||
end
|
||||
|
||||
if find(sim_in.plots == 9)
|
||||
figure(9); clf;
|
||||
subplot(211)
|
||||
stem(tx_testframe(1:min(20,length(rx_bits))))
|
||||
title('Tx Bits')
|
||||
subplot(212)
|
||||
stem(rx_bits(1:min(20,length(rx_bits))))
|
||||
title('Rx Bits')
|
||||
end
|
||||
end
|
||||
|
||||
sim_out.TERvec = TERvec;
|
||||
sim_out.BERvec = BERvec;
|
||||
sim_out.Rs = oqpsk_states.Rs;
|
||||
endfunction
|
||||
|
||||
|
||||
function run_oqpsk_single
|
||||
sim_in.coherent_demod = 1;
|
||||
sim_in.phase_est = 1;
|
||||
sim_in.timing_est = 1;
|
||||
sim_in.bitspertestframe = 100;
|
||||
sim_in.nbits = 10000;
|
||||
sim_in.EbNodB = 4;
|
||||
sim_in.verbose = 1;
|
||||
sim_in.phase_offset = 3*pi/4; % in radians
|
||||
sim_in.timing_offset = 4; % in samples 0..M-1
|
||||
sim_in.freq_offset = 0.001; % fraction of Symbol Rate
|
||||
sim_in.plots = [1 2 4 5 6 7];
|
||||
sim_in.sample_clock_offset_ppm = 100;
|
||||
|
||||
sim_out = oqpsk_test(sim_in);
|
||||
endfunction
|
||||
|
||||
|
||||
% Generate a bunch of BER versus Eb/No curves for various demods
|
||||
|
||||
function run_oqpsk_curves
|
||||
sim_in.coherent_demod = 1;
|
||||
sim_in.EbNodB = 2:8;
|
||||
sim_in.verbose = 1;
|
||||
sim_in.phase_est = 1;
|
||||
sim_in.timing_est = 1;
|
||||
sim_in.bitspertestframe = 100;
|
||||
sim_in.nbits = 50000;
|
||||
sim_in.phase_offset = 3*pi/4; % in radians
|
||||
sim_in.timing_offset = 4; % in samples 0..M-1
|
||||
sim_in.freq_offset = 0.001; % fraction of Symbol Rate
|
||||
sim_in.plots = [];
|
||||
sim_in.sample_clock_offset_ppm = 0;
|
||||
|
||||
oqpsk_coh = oqpsk_test(sim_in);
|
||||
|
||||
Rs = oqpsk_coh.Rs;
|
||||
EbNo = 10 .^ (sim_in.EbNodB/10);
|
||||
oqpsk_theory.BERvec = 0.5*erfc(sqrt(EbNo));
|
||||
|
||||
% BER v Eb/No curves
|
||||
|
||||
figure;
|
||||
clf;
|
||||
semilogy(sim_in.EbNodB, oqpsk_theory.BERvec,'r+-;OQPSK theory;')
|
||||
hold on;
|
||||
semilogy(sim_in.EbNodB, oqpsk_coh.BERvec,'g+-;OQPSK sim;')
|
||||
hold off;
|
||||
grid("minor");
|
||||
axis([min(sim_in.EbNodB) max(sim_in.EbNodB) 1E-4 1])
|
||||
legend("boxoff");
|
||||
xlabel("Eb/No (dB)");
|
||||
ylabel("Bit Error Rate (BER)")
|
||||
endfunction
|
||||
|
||||
|
||||
% Choose one of these to run ------------------------------------------
|
||||
|
||||
run_oqpsk_single
|
||||
%run_oqpsk_curves
|
||||
|
||||
|
|
@ -1,407 +0,0 @@
|
|||
% papr_test.m
|
||||
%
|
||||
% Experiments with PAPR reduction using clipping/compression
|
||||
%
|
||||
% OFDM Tx -> compress -> filter -> normalise power -> channel -> OFDM Rx
|
||||
|
||||
#{
|
||||
TODO:
|
||||
[ ] option for normalised power after clipper
|
||||
[ ] experiment to plot those curves
|
||||
#}
|
||||
|
||||
1;
|
||||
|
||||
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
|
||||
|
||||
function two_bits = qpsk_demod(symbol)
|
||||
bit0 = real(symbol*exp(j*pi/4)) < 0;
|
||||
bit1 = imag(symbol*exp(j*pi/4)) < 0;
|
||||
two_bits = [bit1 bit0];
|
||||
endfunction
|
||||
|
||||
function papr = calc_papr(tx)
|
||||
papr = 10*log10(max(abs(tx).^2)/mean(abs(tx).^2));
|
||||
end
|
||||
|
||||
% test PAPR calculation with a two tone signal of known PAPR (3dB)
|
||||
function test_papr
|
||||
f1=800; f2=1200; Fs=8000; n=(0:Fs-1);
|
||||
tx=exp(j*2*pi*n*f1/Fs) + exp(j*2*pi*n*f2/Fs);
|
||||
papr = calc_papr(tx);
|
||||
assert(abs(papr-3.0) < 0.05, 'test_papr() failed!')
|
||||
end
|
||||
|
||||
% "Genie" OFDM modem simulation that assumes ideal sync
|
||||
|
||||
function [ber papr] = run_sim(Nc, Nsym, EbNodB, channel='awgn', plot_en=0, filt_en=0, method="", threshold=1, norm_ebno=0)
|
||||
rand('seed',1);
|
||||
randn('seed',1);
|
||||
|
||||
M = 160; % number of samples in each symbol
|
||||
bps = 2; % two bits per symbol for QPSK
|
||||
Ncp = 16; % cyclic prefix samples
|
||||
Fs = 8000;
|
||||
|
||||
phase_est = 1; % perform phase estimation/correction
|
||||
timing = Ncp;
|
||||
|
||||
if strcmp(method,"diversity")
|
||||
% total power of tx symbol after combination the same. Scatter plot positions
|
||||
% different but also twice as much noise (bandwidth)
|
||||
Nd = 2; gain = 1/sqrt(2);
|
||||
else
|
||||
Nd = 1; gain = 1.0;
|
||||
end
|
||||
|
||||
if strcmp(channel,'multipath')
|
||||
dopplerSpreadHz = 1; path_delay = Ncp/2;
|
||||
Nsam = floor(Nsym*(M+Ncp)*1.1);
|
||||
spread1 = doppler_spread(dopplerSpreadHz, Fs, Nsam);
|
||||
spread2 = doppler_spread(dopplerSpreadHz, Fs, Nsam);
|
||||
end
|
||||
|
||||
papr_log = [];
|
||||
for e=1:length(EbNodB)
|
||||
% generate a 2D array of QPSK symbols
|
||||
|
||||
Nphases = 2^bps;
|
||||
tx_phases = pi/2*floor((rand(Nsym,Nc)*Nphases));
|
||||
if strcmp(method,"diversity")
|
||||
% duplicate carriers but with opposite phase
|
||||
tx_phases = [tx_phases (tx_phases-pi/2)];
|
||||
end
|
||||
tx_sym = gain*exp(j*tx_phases);
|
||||
|
||||
% carrier frequencies, centre about 0
|
||||
st = floor(Nc*Nd/2);
|
||||
w = 2*pi/M*(-st:-st+Nc*Nd-1);
|
||||
|
||||
% generate OFDM signal
|
||||
|
||||
tx = [];
|
||||
for s=1:Nsym
|
||||
atx = zeros(1,M);
|
||||
for c=1:Nc*Nd
|
||||
atx += exp(j*(0:M-1)*w(c))*tx_sym(s,c);
|
||||
end
|
||||
% insert cyclic prefix and build up stream of time domain symbols
|
||||
% note CP costs us 10*log10((Ncp+M)/M) in Eb, as energy in CP isn't used for demodulation
|
||||
tx = [tx atx(end-Ncp+1:end) atx];
|
||||
end
|
||||
Nsam = length(tx);
|
||||
|
||||
if strcmp(channel,'multipath')
|
||||
assert(length(spread1) >= Nsam);
|
||||
assert(length(spread2) >= Nsam);
|
||||
end
|
||||
|
||||
% bunch of PAPR reduction options
|
||||
tx_ = tx;
|
||||
|
||||
% determine threshold based on CDF
|
||||
cdf = empirical_cdf((1:Nc),abs(tx));
|
||||
if strcmp(method, "clip") || strcmp(method, "diversity") || strcmp(method, "compand")
|
||||
if threshold < 1
|
||||
threshold_level = find(cdf >= threshold)(1);
|
||||
else
|
||||
threshold_level = 10*Nc;
|
||||
end
|
||||
|
||||
% printf("threshold: %f threshold_level: %f\n", threshold, threshold_level);
|
||||
end
|
||||
|
||||
if strcmp(method, "clip") || strcmp(method, "diversity")
|
||||
ind = find(abs(tx) > threshold_level);
|
||||
tx_(ind) = threshold_level*exp(j*angle(tx(ind)));
|
||||
end
|
||||
if strcmp(method, "compand")
|
||||
# power law compander x = a*y^power, y = (x/a) ^ (1/power)
|
||||
power=2; a=threshold_level/(threshold_level^power);
|
||||
tx_mag = (abs(tx)/a) .^ (1/power);
|
||||
tx_ = tx_mag.*exp(j*angle(tx));
|
||||
end
|
||||
|
||||
if filt_en
|
||||
Nfilt=80;
|
||||
b = fir1(Nfilt,2*Nc*Nd/M);
|
||||
tx_ = filter(b,1,[tx_ zeros(1,Nfilt/2)]);
|
||||
tx_ = [tx_(Nfilt/2+1:end)];
|
||||
end
|
||||
|
||||
rx = tx_;
|
||||
|
||||
% multipath channel
|
||||
|
||||
if phase_est
|
||||
% estimate phase of each symbol before multipath simulation
|
||||
|
||||
rx_phase1 = zeros(Nsym,Nc);
|
||||
for s=1:Nsym
|
||||
st = (s-1)*(M+Ncp)+1+timing; en = st+M-1;
|
||||
for c=1:Nc*Nd
|
||||
rx_phase1(s,c) = sum(exp(-j*(0:M-1)*w(c)) .* rx(st:en))/M;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if strcmp(channel,'multipath')
|
||||
rx = spread1(1:Nsam).*rx + spread2(1:Nsam).*[zeros(1,path_delay) rx(1:end-path_delay)];
|
||||
end
|
||||
|
||||
% normalise power after multipath, so that Eb/No is set up
|
||||
% correctly
|
||||
|
||||
if norm_ebno == 0
|
||||
norm = sqrt(mean(abs(tx_).^2)/mean(abs(rx).^2));
|
||||
else
|
||||
% normalise after clipper, this makes norm_pwr constant for all test
|
||||
% conditions
|
||||
norm = sqrt(mean(abs(tx).^2)/mean(abs(rx).^2));
|
||||
end
|
||||
rx *= norm;
|
||||
norm_pwr = 10*log10(mean(abs(rx).^2));
|
||||
|
||||
if phase_est
|
||||
% auxiliary rx to get ideal phase ests on signal after multipath but before AWGN noise is added
|
||||
|
||||
rx_phase = zeros(Nsym,Nc);
|
||||
for s=1:Nsym
|
||||
st = (s-1)*(M+Ncp)+1+timing; en = st+M-1;
|
||||
for c=1:Nc*Nd
|
||||
arx_sym = sum(exp(-j*(0:M-1)*w(c)) .* rx(st:en))/M;
|
||||
rx_phase(s,c) = arx_sym * conj(rx_phase1(s,c));
|
||||
end
|
||||
end
|
||||
rx_phase = exp(j*arg(rx_phase));
|
||||
end
|
||||
|
||||
% AWGN channel
|
||||
|
||||
EsNodB = EbNodB(e) + 10*log10(bps);
|
||||
variance = M/(10^(EsNodB/10));
|
||||
noise = sqrt(variance/2)*randn(1,Nsam) + j*sqrt(variance/2)*randn(1,Nsam);
|
||||
rx += noise;
|
||||
|
||||
% demodulate
|
||||
rx_sym = zeros(Nsym,Nc);
|
||||
for s=1:Nsym
|
||||
st = (s-1)*(M+Ncp)+1+timing; en = st+M-1;
|
||||
for c=1:Nc*Nd
|
||||
rx_sym(s,c) = sum(exp(-j*(0:M-1)*w(c)) .* rx(st:en))/M;
|
||||
if phase_est rx_sym(s,c) *= conj(rx_phase(s,c)); end
|
||||
end
|
||||
|
||||
if strcmp(method,"diversity")
|
||||
for c=1:Nc
|
||||
rx_sym(s,c) += rx_sym(s,c+Nc)*exp(j*pi/2);
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
% count bit errors
|
||||
|
||||
Tbits = Terrs = 0; ErrPerSym = zeros(1,Nsym);
|
||||
for s=1:Nsym
|
||||
Nerrs = 0;
|
||||
for c=1:Nc
|
||||
tx_bits = qpsk_demod(tx_sym(s,c));
|
||||
rx_bits = qpsk_demod(rx_sym(s,c));
|
||||
Tbits += bps;
|
||||
Nerrs += sum(xor(tx_bits,rx_bits));
|
||||
end
|
||||
ErrPerSym(s) = Nerrs;
|
||||
Terrs += Nerrs;
|
||||
end
|
||||
|
||||
if plot_en
|
||||
figure(1); clf;
|
||||
plot(abs(tx(1:5*M))); hold on; plot(abs(tx_(1:5*M))); hold off;
|
||||
axis([0 5*M 0 max(abs(tx))]);
|
||||
figure(2); clf; [hh nn] = hist(abs(tx),25,1);
|
||||
plotyy(nn,hh,1:Nc,cdf); title('PDF and CDF'); grid;
|
||||
figure(3); clf; plot(real(rx_sym(:,1:Nc)), imag(rx_sym(:,1:Nc)), '+'); axis([-2 2 -2 2]);
|
||||
figure(4); clf; Tx_ = 10*log10(abs(fft(tx_))); plot(fftshift(Tx_));
|
||||
mx = 10*ceil(max(Tx_)/10); axis([1 length(Tx_) mx-60 mx]);
|
||||
figure(5); plot_specgram(real(rx.*exp(j*2*pi*(0:Nsam-1)/4)));
|
||||
figure(6); clf; stem(ErrPerSym);
|
||||
end
|
||||
|
||||
papr1 = calc_papr(tx);
|
||||
papr2 = calc_papr(tx_);
|
||||
papr_log = [papr_log papr2];
|
||||
ber(e) = Terrs/Tbits;
|
||||
printf("EbNodB: %4.1f %3.1f %4.1f PAPR: %5.2f %5.2f Tbits: %6d Terrs: %6d BER: %5.3f\n",
|
||||
EbNodB(e), norm, norm_pwr, papr1, papr2, Tbits, Terrs, ber(e))
|
||||
end
|
||||
|
||||
papr = mean(papr_log);
|
||||
end
|
||||
|
||||
% BER versus Eb/No curves -------------------------------------
|
||||
|
||||
% first pass at trying out a few different schemes
|
||||
function curves_experiment1(Nc=8, channel='awgn', Nsym=1000, EbNodB=2:8)
|
||||
|
||||
[ber1 papr1] = run_sim(Nc, Nsym, EbNodB, channel, 0, filt_en=1);
|
||||
[ber2 papr2] = run_sim(Nc, Nsym, EbNodB, channel, 0, filt_en=1, "clip", threshold=0.8);
|
||||
[ber3 papr3] = run_sim(Nc, Nsym, EbNodB, channel, 0, filt_en=1, "clip", threshold=0.6);
|
||||
[ber4 papr4] = run_sim(Nc, Nsym, EbNodB, channel, 0, filt_en=1, "compand", threshold=0.6);
|
||||
[ber5 papr5] = run_sim(Nc, Nsym, EbNodB, channel, 0, filt_en=1, "diversity", threshold=0.6);
|
||||
|
||||
figure(7); clf;
|
||||
semilogy(EbNodB, ber1,sprintf('b+-;vanilla OFDM %3.1f;',papr1),'markersize', 10, 'linewidth', 2); hold on;
|
||||
semilogy(EbNodB, ber2,sprintf('r+-;clip 0.8 %3.1f;',papr2),'markersize', 10, 'linewidth', 2);
|
||||
semilogy(EbNodB, ber3,sprintf('g+-;clip 0.6 %3.1f;',papr3),'markersize', 10, 'linewidth', 2);
|
||||
semilogy(EbNodB, ber4,sprintf('c+-;compand 0.6 %3.1f;',papr4),'markersize', 10, 'linewidth', 2);
|
||||
semilogy(EbNodB, ber5,sprintf('bk+-;diversity 0.6 %3.1f;',papr5),'markersize', 10, 'linewidth', 2);
|
||||
hold off;
|
||||
axis([min(EbNodB) max(EbNodB) 1E-3 1E-1]); grid;
|
||||
xlabel('Eb/No'); title(sprintf("%s Nc = %d", channel, Nc))
|
||||
fn = sprintf("papr_exp1_%s_BER_EbNo.png", channel);
|
||||
print(fn,"-dpng");
|
||||
|
||||
figure(8); clf;
|
||||
semilogy(EbNodB+papr1, ber1,sprintf('b+-;vanilla OFDM %3.1f;',papr1),'markersize', 10, 'linewidth', 2); hold on;
|
||||
semilogy(EbNodB+papr2, ber2,sprintf('r+-;clip 0.8 %3.1f;',papr2),'markersize', 10, 'linewidth', 2);
|
||||
semilogy(EbNodB+papr3, ber3,sprintf('g+-;clip 0.6 %3.1f;',papr3),'markersize', 10, 'linewidth', 2);
|
||||
semilogy(EbNodB+papr4, ber4,sprintf('c+-;compand 0.6 %3.1f;',papr4),'markersize', 10, 'linewidth', 2);
|
||||
semilogy(EbNodB+papr5, ber5,sprintf('bk+-;diversity 0.6 %3.1f;',papr5),'markersize', 10, 'linewidth', 2);
|
||||
hold off;
|
||||
xlabel('Peak Eb/No');
|
||||
axis([min(EbNodB)+papr2 max(EbNodB)+papr1 1E-3 1E-1]); grid; title(sprintf("%s Nc = %d", channel, Nc))
|
||||
fn = sprintf("papr_exp1_%s_BER_peakEbNo.png", channel);
|
||||
print(fn,"-dpng");
|
||||
end
|
||||
|
||||
|
||||
% vary threshold and plot BER v Eb/No curves
|
||||
function curves_experiment2(Nc=8, channel='awgn', Nsym=1000, EbNodB=2:16)
|
||||
|
||||
[ber1 papr1] = run_sim(Nc, Nsym, EbNodB, channel, 0, filt_en=1);
|
||||
[ber2 papr2] = run_sim(Nc, Nsym, EbNodB, channel, 0, filt_en=1, "clip", threshold=0.8);
|
||||
[ber3 papr3] = run_sim(Nc, Nsym, EbNodB, channel, 0, filt_en=1, "clip", threshold=0.6);
|
||||
[ber4 papr4] = run_sim(Nc, Nsym, EbNodB, channel, 0, filt_en=1, "clip", threshold=0.4);
|
||||
[ber5 papr5] = run_sim(Nc, Nsym, EbNodB, channel, 0, filt_en=1, "clip", threshold=0.2);
|
||||
[ber6 papr6] = run_sim(Nc, Nsym, EbNodB, channel, 0, filt_en=1, "diversity", threshold=0.8);
|
||||
|
||||
figure(7); clf;
|
||||
semilogy(EbNodB, ber1,sprintf('b+-;vanilla OFDM %3.1f;',papr1),'markersize', 10, 'linewidth', 2); hold on;
|
||||
semilogy(EbNodB, ber2,sprintf('r+-;clip 0.8 %3.1f;',papr2),'markersize', 10, 'linewidth', 2);
|
||||
semilogy(EbNodB, ber3,sprintf('g+-;clip 0.6 %3.1f;',papr3),'markersize', 10, 'linewidth', 2);
|
||||
semilogy(EbNodB, ber4,sprintf('c+-;clip 0.4 %3.1f;',papr4),'markersize', 10, 'linewidth', 2);
|
||||
semilogy(EbNodB, ber5,sprintf('bk+-;clip 0.2 %3.1f;',papr5),'markersize', 10, 'linewidth', 2);
|
||||
semilogy(EbNodB, ber6,sprintf('m+-;diversity 0.8 %3.1f;', papr6),'markersize', 10, 'linewidth', 2);
|
||||
hold off;
|
||||
axis([min(EbNodB) max(EbNodB) 1E-3 1E-1]); grid;
|
||||
xlabel('Eb/No'); title(sprintf("%s Nc = %d", channel, Nc))
|
||||
fn = sprintf("papr_exp2_Nc%d_%s_BER_EbNo.png", Nc, channel);
|
||||
print(fn,"-dpng");
|
||||
|
||||
figure(8); clf;
|
||||
semilogy(EbNodB+papr1, ber1,sprintf('b+-;vanilla OFDM %3.1f;',papr1),'markersize', 10, 'linewidth', 2); hold on;
|
||||
semilogy(EbNodB+papr2, ber2,sprintf('r+-;clip 0.8 %3.1f;',papr2),'markersize', 10, 'linewidth', 2);
|
||||
semilogy(EbNodB+papr3, ber3,sprintf('g+-;clip 0.6 %3.1f;',papr3),'markersize', 10, 'linewidth', 2);
|
||||
semilogy(EbNodB+papr4, ber4,sprintf('c+-;clip 0.4 %3.1f;',papr4),'markersize', 10, 'linewidth', 2);
|
||||
semilogy(EbNodB+papr5, ber5,sprintf('bk+-;clip 0.2 %3.1f;',papr5),'markersize', 10, 'linewidth', 2);
|
||||
semilogy(EbNodB+papr6, ber6,sprintf('m+-;diversity 0.8 %3.1f;', papr6),'markersize', 10, 'linewidth', 2);
|
||||
hold off;
|
||||
xlabel('Peak Eb/No');
|
||||
axis([min(EbNodB)+papr2 max(EbNodB)+papr1 1E-3 1E-1]); grid; title(sprintf("%s Nc = %d", channel, Nc))
|
||||
fn = sprintf("papr_exp2_Nc%d_%s_BER_peakEbNo.png", Nc, channel);
|
||||
print(fn,"-dpng");
|
||||
end
|
||||
|
||||
% PAPR against number of carriers Nc
|
||||
function curves_experiment3(Nsym=3000)
|
||||
|
||||
paper = zeros(1,32);
|
||||
Nc = 2:2:32;
|
||||
for i = 1:length(Nc)
|
||||
aNc = Nc(i);
|
||||
[aber apapr] = run_sim(aNc, Nsym, 100);
|
||||
papr(aNc) = apapr;
|
||||
end
|
||||
|
||||
figure(9); clf;
|
||||
plot(Nc, papr(Nc)); xlabel('Number of Carriers Nc'); ylabel('PAPR (dB)'); grid;
|
||||
fn = sprintf("papr_exp3_Nc.png");
|
||||
print(fn,"-dpng");
|
||||
end
|
||||
|
||||
% focus on diversity - vary threshold and plot BER v Eb/No curves
|
||||
function curves_experiment4(Nc=8, channel='multipath', Nsym=3000, EbNodB=2:2:16)
|
||||
|
||||
[ber1 papr1] = run_sim(Nc, Nsym, EbNodB, channel, 0, filt_en=1);
|
||||
[ber2 papr2] = run_sim(Nc, Nsym, EbNodB, channel, 0, filt_en=1, "diversity", threshold=1);
|
||||
[ber3 papr3] = run_sim(Nc, Nsym, EbNodB, channel, 0, filt_en=1, "diversity", threshold=0.8);
|
||||
[ber4 papr4] = run_sim(Nc, Nsym, EbNodB, channel, 0, filt_en=1, "diversity", threshold=0.6);
|
||||
|
||||
figure(7); clf;
|
||||
semilogy(EbNodB, ber1,sprintf('b+-;vanilla OFDM %3.1f;',papr1),'markersize', 10, 'linewidth', 2); hold on;
|
||||
semilogy(EbNodB, ber2,sprintf('r+-;diversity 1.0 %3.1f;',papr2),'markersize', 10, 'linewidth', 2);
|
||||
semilogy(EbNodB, ber3,sprintf('g+-;diversity 0.8 %3.1f;',papr3),'markersize', 10, 'linewidth', 2);
|
||||
semilogy(EbNodB, ber4,sprintf('c+-;diversity 0.6 %3.1f;',papr4),'markersize', 10, 'linewidth', 2);
|
||||
hold off;
|
||||
axis([min(EbNodB) max(EbNodB) 1E-3 1E-1]); grid;
|
||||
xlabel('Eb/No'); title(sprintf("%s Nc = %d", channel, Nc))
|
||||
fn = sprintf("papr_exp4_Nc%d_%s_BER_EbNo.png", Nc, channel);
|
||||
print(fn,"-dpng");
|
||||
|
||||
figure(8); clf;
|
||||
semilogy(EbNodB+papr1, ber1,sprintf('b+-;vanilla OFDM %3.1f;',papr1),'markersize', 10, 'linewidth', 2); hold on;
|
||||
semilogy(EbNodB+papr2, ber2,sprintf('r+-;diversity 1.0 %3.1f;',papr2),'markersize', 10, 'linewidth', 2);
|
||||
semilogy(EbNodB+papr3, ber3,sprintf('g+-;diversity 0.8 %3.1f;',papr3),'markersize', 10, 'linewidth', 2);
|
||||
semilogy(EbNodB+papr4, ber4,sprintf('c+-;diversity 0.6 %3.1f;',papr4),'markersize', 10, 'linewidth', 2);
|
||||
hold off;
|
||||
xlabel('Peak Eb/No');
|
||||
axis([min(EbNodB)+papr4 max(EbNodB)+papr1 1E-3 1E-1]); grid; title(sprintf("%s Nc = %d", channel, Nc))
|
||||
fn = sprintf("papr_exp4_Nc%d_%s_BER_peakEbNo.png", Nc, channel);
|
||||
print(fn,"-dpng");
|
||||
end
|
||||
|
||||
% plot BER v Eb/No curves for clipping with normalised Eb/No after clipping
|
||||
function curves_experiment5(Nc=8, channel='awgn', Nsym=1000, EbNodB=2:10)
|
||||
|
||||
[ber1 papr1] = run_sim(Nc, Nsym, EbNodB, channel, 0, filt_en=1, "", threshold=1, norm=1);
|
||||
[ber2 papr2] = run_sim(Nc, Nsym, EbNodB, channel, 0, filt_en=1, "clip", threshold=0.8, norm=1);
|
||||
[ber3 papr3] = run_sim(Nc, Nsym, EbNodB, channel, 0, filt_en=1, "clip", threshold=0.6, norm=1);
|
||||
[ber4 papr4] = run_sim(Nc, Nsym, EbNodB, channel, 0, filt_en=1, "clip", threshold=0.4, norm=1);
|
||||
[ber5 papr5] = run_sim(Nc, Nsym, EbNodB, channel, 0, filt_en=1, "clip", threshold=0.2, norm=1);
|
||||
|
||||
figure(7); clf;
|
||||
semilogy(EbNodB, ber1,sprintf('b+-;vanilla OFDM %3.1f;',papr1),'markersize', 10, 'linewidth', 2); hold on;
|
||||
semilogy(EbNodB, ber2,sprintf('r+-;clip 0.8 %3.1f;',papr2),'markersize', 10, 'linewidth', 2);
|
||||
semilogy(EbNodB, ber3,sprintf('g+-;clip 0.6 %3.1f;',papr3),'markersize', 10, 'linewidth', 2);
|
||||
semilogy(EbNodB, ber4,sprintf('c+-;clip 0.4 %3.1f;',papr4),'markersize', 10, 'linewidth', 2);
|
||||
semilogy(EbNodB, ber5,sprintf('bk+-;clip 0.2 %3.1f;',papr5),'markersize', 10, 'linewidth', 2);
|
||||
hold off;
|
||||
axis([min(EbNodB) max(EbNodB) 1E-3 1E-1]); grid;
|
||||
xlabel('Eb/No'); title(sprintf("%s Nc = %d", channel, Nc))
|
||||
fn = sprintf("papr_exp5_Nc%d_%s_BER_EbNo.png", Nc, channel);
|
||||
print(fn,"-dpng");
|
||||
end
|
||||
|
||||
pkg load statistics;
|
||||
more off;
|
||||
|
||||
test_papr;
|
||||
|
||||
% single point with lots of plots -----------
|
||||
|
||||
%run_sim(8, 1000, EbNo=100, channel='awgn', plot_en=1, filt_en=1);
|
||||
%run_sim(8, 8, EbNo=100, channel='awgn', plot_en=1, filt_en=1, "diversity", threshold=0.8);
|
||||
%run_sim(8, 1000, EbNo=10, channel='multipath', plot_en=1, filt_en=0, "diversity", threshold=5);
|
||||
%curves_experiment2(Nc=16, 'awgn', Nsym=1000);
|
||||
curves_experiment2(Nc=16,'multipath', Nsym=3000, EbNodB=2:2:16);
|
||||
%curves_experiment3()
|
||||
%curves_experiment4()
|
||||
%curves_experiment5(Nc=16)
|
||||
|
|
@ -1,72 +0,0 @@
|
|||
% phase_noise.m
|
||||
% David Nov 2019
|
||||
|
||||
% Close-in look at phase noise. Feed in a off-air sample file of a
|
||||
% sine wave, extracts the phase noise contour and returns the Doppler
|
||||
% spreading function that can be used to model the channel in
|
||||
% simulations
|
||||
|
||||
function spread_FsHz = phase_noise(file_name)
|
||||
Fs = 8000;
|
||||
s = load_raw(file_name);
|
||||
% skip past wave header
|
||||
s = [zeros(256,1); s(256:end)];
|
||||
S = abs(fft(s(1:Fs).*hanning(Fs)));
|
||||
[mx mx_bin] = max(S);
|
||||
ftone = mx_bin-1;
|
||||
|
||||
figure(1); clf;
|
||||
plot(20*log10(S(1:Fs/2)))
|
||||
title('Input Spectrum');
|
||||
|
||||
% downshift to baseband and LPF. We just want the sinusoid with as little
|
||||
% additive AWGN noise as possible
|
||||
sbb = s' .* exp(-j*(1:length(s))*2*pi*ftone/Fs);
|
||||
[b a] = cheby1(4, 1, 20/Fs);
|
||||
sbb_lpf = filter(b,a,sbb);
|
||||
|
||||
spread_fsHz = sbb_lpf;
|
||||
|
||||
% estimate and remove fine freq offset, and HF phase noise
|
||||
|
||||
st = Fs; en = 20*Fs;
|
||||
phase = unwrap(angle(sbb_lpf(st:en)));
|
||||
fine_freq = mean(phase(2:end) - phase(1:end-1));
|
||||
sbb_lpf_fine = sbb_lpf .* exp(-j*(1:length(sbb_lpf))*fine_freq);
|
||||
phase = unwrap(angle(sbb_lpf_fine(st:en)));
|
||||
|
||||
printf("length: %3.2fs freq: %5.1f\n", length(s)/Fs, ftone+fine_freq*Fs/(2*pi));
|
||||
|
||||
figure(2); clf;
|
||||
plot3((st:en)/Fs, real(sbb_lpf_fine(st:en)),imag(sbb_lpf_fine(st:en)))
|
||||
title('Polar phase trajectory');
|
||||
|
||||
figure(3); clf;
|
||||
S2 = fftshift(fft(sbb_lpf_fine(Fs:Fs*11)));
|
||||
[mx mx_bin] = max(abs(S2));
|
||||
S2dB = 20*log10(abs(S2));
|
||||
mxdB = 10*ceil(max(S2dB)/10);
|
||||
x = -10:0.1:10;
|
||||
plot(x,S2dB(mx_bin-100:mx_bin+100));
|
||||
axis([-10 10 mxdB-40 mxdB])
|
||||
title('Close in Phase Noise Spectrum');
|
||||
xlabel('Freq (Hz)');
|
||||
grid;
|
||||
|
||||
figure(5); clf;
|
||||
t = (st:en)/Fs;
|
||||
plot(t, phase,'b;phase;');
|
||||
title('Unwrapped Phase');
|
||||
xlabel('Time (sec)')
|
||||
ylabel('Phase (radians)')
|
||||
|
||||
figure(6); clf;
|
||||
beta = 0.00001;
|
||||
rate_of_change_Hz = filter(beta, [1 -(1-beta)],phase(2:end) - phase(1:end-1))*Fs/pi;
|
||||
plot(t(2:end), rate_of_change_Hz)
|
||||
title('Rate of change of phase (Hz)');
|
||||
xlabel('Time (sec)')
|
||||
ylabel('Freq (Hz)')
|
||||
|
||||
spread_FsHz = sbb_lpf_fine/std(sbb_lpf_fine);
|
||||
end
|
||||
|
|
@ -1,39 +0,0 @@
|
|||
% pitch_test.m
|
||||
% David Rowe Sep 2009
|
||||
% Constructs a sequence to test the pitch estimator
|
||||
|
||||
function pitch_test(samname)
|
||||
M=320;
|
||||
F=200;
|
||||
|
||||
fs=fopen(samname,"wb");
|
||||
|
||||
f0 = 100;
|
||||
for f=1:200
|
||||
Wo=2*pi*f0/8000;
|
||||
P=2*pi/Wo;
|
||||
L = floor(pi/Wo);
|
||||
A = 10000/L;
|
||||
phi = zeros(1,L);
|
||||
s = zeros(1,M);
|
||||
|
||||
for m=1:L
|
||||
s = s + A*cos(m*Wo*(0:(M-1)) + phi(m));
|
||||
endfor
|
||||
|
||||
figure(1);
|
||||
clf;
|
||||
plot(s);
|
||||
|
||||
fwrite(fs,s,"short");
|
||||
|
||||
f0 = f0 + 5;
|
||||
if (f0 > 400)
|
||||
f0 = 100;
|
||||
endif
|
||||
endfor
|
||||
|
||||
fclose(fs);
|
||||
|
||||
endfunction
|
||||
|
||||
45
octave/pl.m
45
octave/pl.m
|
|
@ -1,45 +0,0 @@
|
|||
% Copyright David Rowe 2009
|
||||
% This program is distributed under the terms of the GNU General Public License
|
||||
% Version 2
|
||||
%
|
||||
% Plots a raw speech sample file, you can optionally specify the start and end
|
||||
% samples and create a large and small PNGs
|
||||
|
||||
function pl(samname1, start_sam, end_sam, pngname)
|
||||
|
||||
fs=fopen(samname1,"rb");
|
||||
s=fread(fs,Inf,"short");
|
||||
|
||||
st = 1;
|
||||
en = length(s);
|
||||
if (nargin >= 2)
|
||||
st = start_sam;
|
||||
endif
|
||||
if (nargin >= 3)
|
||||
en = end_sam;
|
||||
endif
|
||||
|
||||
figure(1);
|
||||
clf;
|
||||
plot(s(st:en));
|
||||
axis([1 en-st 1.1*min(s) 1.1*max(s)]);
|
||||
|
||||
if (nargin == 4)
|
||||
|
||||
% small image
|
||||
|
||||
__gnuplot_set__ terminal png size 420,300
|
||||
ss = sprintf("__gnuplot_set__ output \"%s.png\"", pngname);
|
||||
eval(ss)
|
||||
replot;
|
||||
|
||||
% larger image
|
||||
|
||||
__gnuplot_set__ terminal png size 800,600
|
||||
ss = sprintf("__gnuplot_set__ output \"%s_large.png\"", pngname);
|
||||
eval(ss)
|
||||
replot;
|
||||
|
||||
endif
|
||||
|
||||
endfunction
|
||||
44
octave/pl2.m
44
octave/pl2.m
|
|
@ -1,44 +0,0 @@
|
|||
% Copyright David Rowe 2009
|
||||
% This program is distributed under the terms of the GNU General Public License
|
||||
% Version 2
|
||||
|
||||
function pl2(samname1, samname2, start_sam, end_sam, offset)
|
||||
|
||||
fs1=fopen(samname1,"rb");
|
||||
s1=fread(fs1,Inf,"short");
|
||||
fs2=fopen(samname2,"rb");
|
||||
s2=fread(fs2,Inf,"short");
|
||||
|
||||
st1 = st2 = 1;
|
||||
en1 = en2 = length(s1);
|
||||
if (nargin >= 3)
|
||||
st1 = st2 = start_sam;
|
||||
endif
|
||||
if (nargin >= 4)
|
||||
en1 = en2 = end_sam;
|
||||
endif
|
||||
|
||||
if (nargin == 5)
|
||||
st2 += offset
|
||||
en2 += offset
|
||||
endif
|
||||
|
||||
figure(1);
|
||||
clf;
|
||||
subplot(211);
|
||||
l1 = strcat("r;",samname1,";");
|
||||
plot(s1(st1:en1), l1); grid minor;
|
||||
axis([1 en1-st1 min(s1(st1:en1)) max(s1(st1:en1))]);
|
||||
subplot(212);
|
||||
l2 = strcat("r;",samname2,";");
|
||||
plot(s2(st2:en2),l2); grid minor;
|
||||
axis([1 en2-st2 min(s1(st2:en2)) max(s1(st2:en2))]);
|
||||
|
||||
figure(2)
|
||||
plot(s1(st1:en1)-s2(st2:en2)); grid minor;
|
||||
|
||||
f=fopen("diff.raw","wb");
|
||||
d = s1(st1:en1)-s2(st2:en2);
|
||||
fwrite(f,d,"short");
|
||||
|
||||
endfunction
|
||||
135
octave/plamp.m
135
octave/plamp.m
|
|
@ -1,135 +0,0 @@
|
|||
% Copyright David Rowe 2009
|
||||
% This program is distributed under the terms of the GNU General Public License
|
||||
% Version 2
|
||||
%
|
||||
% Plot ampltiude modelling information from dump files.
|
||||
|
||||
function plamp(samname, f, samname2)
|
||||
|
||||
% switch some stuff off to unclutter display
|
||||
|
||||
plot_sw = 0;
|
||||
|
||||
sn_name = strcat(samname,"_sn.txt");
|
||||
Sn = load(sn_name);
|
||||
|
||||
sw_name = strcat(samname,"_sw.txt");
|
||||
Sw = load(sw_name);
|
||||
|
||||
sw__name = strcat(samname,"_sw_.txt");
|
||||
if (file_in_path(".",sw__name))
|
||||
Sw_ = load(sw__name);
|
||||
endif
|
||||
|
||||
ew_name = strcat(samname,"_ew.txt");
|
||||
if (file_in_path(".",ew_name))
|
||||
Ew = load(ew_name);
|
||||
endif
|
||||
|
||||
rk_name = strcat(samname,"_rk.txt");
|
||||
if (file_in_path(".",rk_name))
|
||||
Rk = load(rk_name);
|
||||
endif
|
||||
|
||||
model_name = strcat(samname,"_model.txt");
|
||||
model = load(model_name);
|
||||
|
||||
modelq_name = strcat(samname,"_qmodel.txt");
|
||||
if (file_in_path(".",modelq_name))
|
||||
modelq = load(modelq_name);
|
||||
endif
|
||||
|
||||
pw_name = strcat(samname,"_pw.txt");
|
||||
if (file_in_path(".",pw_name))
|
||||
Pw = load(pw_name);
|
||||
endif
|
||||
|
||||
lsp_name = strcat(samname,"_lsp.txt");
|
||||
if (file_in_path(".",lsp_name))
|
||||
lsp = load(lsp_name);
|
||||
endif
|
||||
|
||||
phase_name = strcat(samname,"_phase.txt");
|
||||
if (file_in_path(".",phase_name))
|
||||
phase = load(phase_name);
|
||||
endif
|
||||
|
||||
phase_name_ = strcat(samname,"_phase_.txt");
|
||||
if (file_in_path(".",phase_name_))
|
||||
phase_ = load(phase_name_);
|
||||
endif
|
||||
|
||||
snr_name = strcat(samname,"_snr.txt");
|
||||
if (file_in_path(".",snr_name))
|
||||
snr = load(snr_name);
|
||||
endif
|
||||
|
||||
% optional second file, for exploring post filter
|
||||
|
||||
if nargin == 3
|
||||
model2_name = strcat(samname2,"_model.txt");
|
||||
model2 = load(model2_name);
|
||||
sn2_name = strcat(samname2,"_sn.txt");
|
||||
Sn2 = load(sn2_name);
|
||||
|
||||
sw_name2 = strcat(samname2,"_sw.txt");
|
||||
Sw2 = load(sw_name2);
|
||||
end
|
||||
|
||||
k = ' ';
|
||||
do
|
||||
figure(1);
|
||||
clf;
|
||||
s = [ Sn(2*f-1,:) Sn(2*f,:) ];
|
||||
plot(s,'b');
|
||||
if (nargin == 3)
|
||||
s2 = [ Sn2(2*f-1,:) Sn2(2*f,:) ];
|
||||
hold on; plot(s2,'r'); hold off;
|
||||
end
|
||||
axis([1 length(s) -30000 30000]);
|
||||
|
||||
figure(2);
|
||||
Wo = model(f,1);
|
||||
L = model(f,2);
|
||||
Am = model(f,3:(L+2));
|
||||
plot((1:L)*Wo*4000/pi, 20*log10(Am),";Am;+-b");
|
||||
axis([1 4000 -10 80]);
|
||||
hold on;
|
||||
if plot_sw; plot((0:255)*4000/256, Sw(f,:),";Sw;b"); end
|
||||
|
||||
if (nargin == 3)
|
||||
Wo2 = model2(f,1);
|
||||
L2 = model2(f,2);
|
||||
Am2 = model2(f,3:(L2+2));
|
||||
plot((1:L2)*Wo2*4000/pi, 20*log10(Am2),";Am2;+-r" );
|
||||
if plot_sw; plot((0:255)*4000/256, Sw2(f,:),";Sw2;r"); end
|
||||
endif
|
||||
|
||||
hold off; grid minor;
|
||||
|
||||
% interactive menu
|
||||
|
||||
printf("\rframe: %d menu: n-next b-back p-png s-plot_sw q-quit", f);
|
||||
fflush(stdout);
|
||||
k = kbhit();
|
||||
if k == 'n'; f = f + 1; endif
|
||||
if k == 'b'; f = f - 1; endif
|
||||
if k == 's'
|
||||
if plot_sw; plot_sw = 0; else; plot_sw = 1; end
|
||||
endif
|
||||
% optional print to PNG
|
||||
|
||||
if (k == 'p')
|
||||
figure(1);
|
||||
pngname = sprintf("%s_%d_sn.png",samname,f);
|
||||
print(pngname, '-dpng', "-S800,600")
|
||||
|
||||
figure(2);
|
||||
pngname = sprintf("%s_%d_sw.png",samname,f);
|
||||
print(pngname, '-dpng', "-S800,600")
|
||||
endif
|
||||
|
||||
until (k == 'q')
|
||||
printf("\n");
|
||||
|
||||
endfunction
|
||||
|
|
@ -1,11 +0,0 @@
|
|||
load ../unittest/tinterp_prev.txt;
|
||||
load ../unittest/tinterp_interp.txt;
|
||||
load ../unittest/tinterp_next.txt;
|
||||
|
||||
clf;
|
||||
plot(tinterp_prev(:,1), 20.0*log10(tinterp_prev(:,2)),";prev;")
|
||||
hold on;
|
||||
plot(tinterp_interp(:,1), 20.0*log10(tinterp_interp(:,2)),'g+-;interp;')
|
||||
plot(tinterp_next(:,1), 20.0*log10(tinterp_next(:,2)),'ro-;next;')
|
||||
hold off;
|
||||
axis([0 pi 0 80])
|
||||
150
octave/pllpcpf.m
150
octave/pllpcpf.m
|
|
@ -1,150 +0,0 @@
|
|||
% Copyright David Rowe 2012
|
||||
% This program is distributed under the terms of the GNU General Public License
|
||||
% Version 2
|
||||
%
|
||||
% Plot amplitude modelling information from dump files to test and develop
|
||||
% LPC post filter.
|
||||
|
||||
function pllpcpf(samname, f)
|
||||
|
||||
% switch some stuff off to unclutter display
|
||||
|
||||
plot_Am = 0;
|
||||
plot_Amq = 0;
|
||||
plot_err = 0;
|
||||
plot_lsp = 0;
|
||||
plot_snr = 0;
|
||||
plot_vsnr = 0;
|
||||
plot_sw = 0;
|
||||
plot_pw = 1;
|
||||
plot_pwb = 1;
|
||||
plot_rw = 1;
|
||||
|
||||
sn_name = strcat(samname,"_sn.txt");
|
||||
Sn = load(sn_name);
|
||||
|
||||
sw_name = strcat(samname,"_sw.txt");
|
||||
Sw = load(sw_name);
|
||||
|
||||
sw__name = strcat(samname,"_sw_.txt");
|
||||
if (file_in_path(".",sw__name))
|
||||
Sw_ = load(sw__name);
|
||||
endif
|
||||
|
||||
model_name = strcat(samname,"_model.txt");
|
||||
model = load(model_name);
|
||||
|
||||
modelq_name = strcat(samname,"_qmodel.txt");
|
||||
if (file_in_path(".",modelq_name))
|
||||
modelq = load(modelq_name);
|
||||
endif
|
||||
|
||||
% Pw (LPC synth filter spectrum) before post filter
|
||||
|
||||
pwb_name = strcat(samname,"_pwb.txt");
|
||||
if (file_in_path(".",pwb_name))
|
||||
Pwb = load(pwb_name);
|
||||
endif
|
||||
|
||||
% Rw (Post filter spectrum)
|
||||
|
||||
rw_name = strcat(samname,"_rw.txt");
|
||||
if (file_in_path(".",rw_name))
|
||||
Rw = load(rw_name);
|
||||
endif
|
||||
|
||||
% Pw (LPC synth filter spectrum) after post filter
|
||||
|
||||
pw_name = strcat(samname,"_pw.txt");
|
||||
if (file_in_path(".",pw_name))
|
||||
Pw = load(pw_name);
|
||||
endif
|
||||
|
||||
|
||||
Ew_on = 1;
|
||||
k = ' ';
|
||||
do
|
||||
figure(1);
|
||||
clf;
|
||||
s = [ Sn(2*f-1,:) Sn(2*f,:) ];
|
||||
size(s);
|
||||
plot(s);
|
||||
axis([1 length(s) -20000 20000]);
|
||||
|
||||
figure(2);
|
||||
clf;
|
||||
Wo = model(f,1);
|
||||
L = model(f,2);
|
||||
Am = model(f,3:(L+2));
|
||||
if plot_Am
|
||||
plot((1:L)*Wo*4000/pi, 20*log10(Am),";Am;r");
|
||||
end
|
||||
axis([1 4000 -10 80]);
|
||||
hold on;
|
||||
if plot_sw
|
||||
plot((0:255)*4000/256, Sw(f,:),";Sw;");
|
||||
end
|
||||
|
||||
if (file_in_path(".",modelq_name))
|
||||
|
||||
Amq = modelq(f,3:(L+2));
|
||||
if plot_Amq
|
||||
plot((1:L)*Wo*4000/pi, 20*log10(Amq),";Amq;g" );
|
||||
end
|
||||
|
||||
if (file_in_path(".",pwb_name) && plot_pwb)
|
||||
plot((0:255)*4000/256, 10*log10(Pwb(f,:)),";Pwb;r");
|
||||
endif
|
||||
|
||||
if (file_in_path(".",rw_name) && plot_rw)
|
||||
plot((0:255)*4000/256, 10*log10(Rw(f,:)),";Rw;b");
|
||||
endif
|
||||
|
||||
if (file_in_path(".",pw_name) && plot_pw)
|
||||
plot((0:255)*4000/256, 10*log10(Pw(f,:)),";Pw;g.");
|
||||
endif
|
||||
|
||||
signal = Am * Am';
|
||||
noise = (Am-Amq) * (Am-Amq)';
|
||||
snr1 = 10*log10(signal/noise);
|
||||
Am_err_label = sprintf(";Am error SNR %4.2f dB;m",snr1);
|
||||
if plot_err
|
||||
plot((1:L)*Wo*4000/pi, 20*log10(Amq) - 20*log10(Am), Am_err_label);
|
||||
end
|
||||
endif
|
||||
|
||||
|
||||
hold off;
|
||||
|
||||
% interactive menu
|
||||
|
||||
printf("\rframe: %d menu: n-next b-back p-png q-quit", f);
|
||||
fflush(stdout);
|
||||
k = kbhit();
|
||||
if (k == 'n')
|
||||
f = f + 1;
|
||||
endif
|
||||
if (k == 'b')
|
||||
f = f - 1;
|
||||
endif
|
||||
|
||||
% optional print to PNG
|
||||
|
||||
if (k == 'p')
|
||||
figure(1);
|
||||
pngname = sprintf("%s_%d_sn.png",samname,f);
|
||||
print(pngname, '-dpng', "-S500,500")
|
||||
pngname = sprintf("%s_%d_sn_large.png",samname,f);
|
||||
print(pngname, '-dpng', "-S800,600")
|
||||
|
||||
figure(2);
|
||||
pngname = sprintf("%s_%d_sw.png",samname,f);
|
||||
print(pngname, '-dpng', "-S500,500")
|
||||
pngname = sprintf("%s_%d_sw_large.png",samname,f);
|
||||
print(pngname, '-dpng', "-S1200,800")
|
||||
endif
|
||||
|
||||
until (k == 'q')
|
||||
printf("\n");
|
||||
|
||||
endfunction
|
||||
|
|
@ -1,46 +0,0 @@
|
|||
% Copyright David Rowe 2010
|
||||
% This program is distributed under the terms of the GNU General Public License
|
||||
% Version 2
|
||||
%
|
||||
% Plots a bunch of information related to LSP quantisation:
|
||||
% - speech file
|
||||
% - LSPs before and after quantisation
|
||||
% - SNR for each frame
|
||||
%
|
||||
% Note: there is a 160 sample (two frame delay) from the when a sample
|
||||
% enters the input buffer until it is at the centre of the analysis window
|
||||
|
||||
function pllsp(rawfile,
|
||||
dumpfile_prefix_lpc_only,
|
||||
dumpfile_prefix_lsp,
|
||||
start_f, end_f)
|
||||
|
||||
fs=fopen(rawfile,"rb");
|
||||
s=fread(fs,Inf,"short");
|
||||
|
||||
lpc_snr_name = strcat(dumpfile_prefix_lpc_only,"_lpc_snr.txt");
|
||||
lpc10_snr = load(lpc_snr_name);
|
||||
lpc_snr_name = strcat(dumpfile_prefix_lsp,"_lpc_snr.txt");
|
||||
lsp_snr = load(lpc_snr_name);
|
||||
|
||||
lsp_name = strcat(dumpfile_prefix_lsp,"_lsp.txt");
|
||||
lsps = load(lsp_name);
|
||||
[m,n]=size(lsps);
|
||||
lsp = lsps(1:2:m,:);
|
||||
lsp_ = lsps(2:2:m,:);
|
||||
|
||||
figure(1);
|
||||
clf;
|
||||
subplot(211);
|
||||
sp = s((start_f-2)*80:(end_f-2)*80);
|
||||
plot(sp);
|
||||
|
||||
subplot(212);
|
||||
plot(lpc10_snr((start_f+1):end_f)-lsp_snr((start_f+1):end_f));
|
||||
|
||||
figure(2);
|
||||
plot((4000/pi)*lsp((start_f+1):end_f,:));
|
||||
hold on;
|
||||
plot((4000/pi)*lsp_((start_f+1):end_f,:),'+-');
|
||||
hold off;
|
||||
endfunction
|
||||
|
|
@ -1,27 +0,0 @@
|
|||
% pllspdt.m
|
||||
% Copyright David Rowe 2010
|
||||
% This program is distributed under the terms of the GNU General Public License
|
||||
% Version 2
|
||||
%
|
||||
% Test script to plot differences in LSps between frames
|
||||
|
||||
function pllspdt(rawfile,dumpfile_prefix_lsp,lspn, start_f, end_f)
|
||||
|
||||
fs=fopen(rawfile,"rb");
|
||||
s=fread(fs,Inf,"short");
|
||||
|
||||
lsp_name = strcat(dumpfile_prefix_lsp,"_lsp.txt");
|
||||
lsps = load(lsp_name);
|
||||
[m,n]=size(lsps);
|
||||
lsp = lsps(1:2:m,:);
|
||||
lsp_ = lsps(2:2:m,:);
|
||||
lspdt = lsp(2:m/2,:) - lsp(1:m/2-1,:);
|
||||
|
||||
figure(1);
|
||||
clf;
|
||||
sp = s((start_f-2)*80:(end_f-2)*80);
|
||||
plot(sp);
|
||||
|
||||
figure(2);
|
||||
plot((4000/pi)*lspdt((start_f+1):end_f,lspn));
|
||||
endfunction
|
||||
134
octave/plnlp.m
134
octave/plnlp.m
|
|
@ -1,134 +0,0 @@
|
|||
% Copyright David Rowe 2009
|
||||
% This program is distributed under the terms of the GNU General Public License
|
||||
% Version 2
|
||||
%
|
||||
% Plot NLP states from dump files.
|
||||
|
||||
function plnlp(samname, f)
|
||||
|
||||
sn_name = strcat(samname,"_sn.txt");
|
||||
Sn = load(sn_name);
|
||||
|
||||
sw_name = strcat(samname,"_sw.txt");
|
||||
Sw = load(sw_name);
|
||||
|
||||
fw_name = strcat(samname,"_fw.txt");
|
||||
if (file_in_path(".",fw_name))
|
||||
fw = load(fw_name);
|
||||
endif
|
||||
|
||||
e_name = strcat(samname,"_e.txt");
|
||||
if (file_in_path(".",e_name))
|
||||
e = load(e_name);
|
||||
endif
|
||||
|
||||
p_name = strcat(samname,".p");
|
||||
if (file_in_path(".",p_name))
|
||||
p = load(p_name);
|
||||
endif
|
||||
|
||||
sq_name = strcat(samname,"_sq.txt");
|
||||
if (file_in_path(".",sq_name))
|
||||
sq = load(sq_name);
|
||||
endif
|
||||
|
||||
dec_name = strcat(samname,"_dec.txt");
|
||||
if (file_in_path(".",dec_name))
|
||||
dec = load(dec_name);
|
||||
endif
|
||||
|
||||
do
|
||||
figure(1);
|
||||
clf;
|
||||
s = [ Sn(2*f-1,:) Sn(2*f,:) ];
|
||||
plot(s, ";Sn;");
|
||||
grid
|
||||
axis([1 length(s) -20000 20000]);
|
||||
|
||||
figure(2);
|
||||
plot((0:255)*4000/256, Sw(f,:),";Sw;");
|
||||
grid
|
||||
axis([1 4000 -10 80]);
|
||||
hold on;
|
||||
|
||||
f0 = 8000/p(f);
|
||||
Wo = 2*pi/p(f);
|
||||
L = floor(pi/Wo);
|
||||
f0_label = sprintf("b;P=%3.1f F0=%3.0f;",p(f),f0);
|
||||
for m=1:L-1
|
||||
plot([ m*Wo*4000/pi m*Wo*4000/pi], [10 60], 'b');
|
||||
endfor
|
||||
plot([ L*Wo*4000/pi L*Wo*4000/pi], [10 60], f0_label);
|
||||
|
||||
hold off;
|
||||
|
||||
if (file_in_path(".",fw_name))
|
||||
figure(3);
|
||||
if (file_in_path(".",e_name))
|
||||
subplot(211);
|
||||
endif
|
||||
plot((0:255)*800/256, fw(f,:)/max(fw(f,:)), ";Fw;");
|
||||
axis([1 400 0 1]);
|
||||
if (file_in_path(".",e_name))
|
||||
subplot(212);
|
||||
e_concat = [ e(2*f-1,:) e(2*f,:) ];
|
||||
plot(e_concat(1:400)/max(e_concat(1:400)), "+;MBE E(f);");
|
||||
axis([1 400 0 1]);
|
||||
endif
|
||||
endif
|
||||
|
||||
if (file_in_path(".",sq_name))
|
||||
figure(4);
|
||||
sq_concat = [ sq(2*f-1,:) sq(2*f,:) ];
|
||||
axis
|
||||
plot(sq_concat, ";sq;");
|
||||
endif
|
||||
|
||||
if (file_in_path(".",dec_name))
|
||||
figure(5);
|
||||
plot(dec(f,:), ";dec;");
|
||||
endif
|
||||
|
||||
figure(2);
|
||||
|
||||
% interactive menu
|
||||
|
||||
printf("\rframe: %d menu: n-next b-back p-png q-quit ", f);
|
||||
fflush(stdout);
|
||||
k = kbhit();
|
||||
if (k == 'n')
|
||||
f = f + 1;
|
||||
endif
|
||||
if (k == 'b')
|
||||
f = f - 1;
|
||||
endif
|
||||
|
||||
% optional print to PNG
|
||||
|
||||
if (k == 'p')
|
||||
|
||||
pngname = sprintf("%s_%d",samname,f);
|
||||
|
||||
% small image
|
||||
|
||||
__gnuplot_set__ terminal png size 420,300
|
||||
ss = sprintf("__gnuplot_set__ output \"%s.png\"", pngname);
|
||||
eval(ss)
|
||||
replot;
|
||||
|
||||
% larger image
|
||||
|
||||
__gnuplot_set__ terminal png size 800,600
|
||||
ss = sprintf("__gnuplot_set__ output \"%s_large.png\"", pngname);
|
||||
eval(ss)
|
||||
replot;
|
||||
|
||||
% for some reason I need this to stop large plot getting wiped
|
||||
__gnuplot_set__ output "/dev/null"
|
||||
|
||||
endif
|
||||
|
||||
until (k == 'q')
|
||||
printf("\n");
|
||||
|
||||
endfunction
|
||||
198
octave/plphase.m
198
octave/plphase.m
|
|
@ -1,198 +0,0 @@
|
|||
% Copyright David Rowe 2009
|
||||
% This program is distributed under the terms of the GNU General Public License
|
||||
% Version 2
|
||||
%
|
||||
% Plot phase modelling information from dump files.
|
||||
|
||||
function plphase(samname, f)
|
||||
|
||||
sn_name = strcat(samname,"_sn.txt");
|
||||
Sn = load(sn_name);
|
||||
|
||||
sw_name = strcat(samname,"_sw.txt");
|
||||
Sw = load(sw_name);
|
||||
|
||||
model_name = strcat(samname,"_model.txt");
|
||||
model = load(model_name);
|
||||
|
||||
sw__name = strcat(samname,"_sw_.txt");
|
||||
if (file_in_path(".",sw__name))
|
||||
Sw_ = load(sw__name);
|
||||
endif
|
||||
|
||||
pw_name = strcat(samname,"_pw.txt");
|
||||
if (file_in_path(".",pw_name))
|
||||
Pw = load(pw_name);
|
||||
endif
|
||||
|
||||
ak_name = strcat(samname,"_ak.txt");
|
||||
if (file_in_path(".",ak_name))
|
||||
ak = load(ak_name);
|
||||
endif
|
||||
|
||||
phase_name = strcat(samname,"_phase.txt");
|
||||
if (file_in_path(".",phase_name))
|
||||
phase = load(phase_name);
|
||||
endif
|
||||
|
||||
phase_name_ = strcat(samname,"_phase_.txt");
|
||||
if (file_in_path(".",phase_name_))
|
||||
phase_ = load(phase_name_);
|
||||
endif
|
||||
|
||||
snr_name = strcat(samname,"_snr.txt");
|
||||
if (file_in_path(".",snr_name))
|
||||
snr = load(snr_name);
|
||||
endif
|
||||
|
||||
sn_name_ = strcat(samname,".raw");
|
||||
if (file_in_path(".",sn_name_))
|
||||
fs_ = fopen(sn_name_,"rb");
|
||||
sn_ = fread(fs_,Inf,"short");
|
||||
endif
|
||||
|
||||
k = ' ';
|
||||
do
|
||||
figure(1);
|
||||
clf;
|
||||
s = [ Sn(2*f-1,:) Sn(2*f,:) ];
|
||||
plot(s);
|
||||
grid;
|
||||
axis([1 length(s) -20000 20000]);
|
||||
if (k == 'p')
|
||||
pngname = sprintf("%s_%d_sn",samname,f);
|
||||
png(pngname);
|
||||
endif
|
||||
|
||||
figure(2);
|
||||
Wo = model(f,1);
|
||||
L = model(f,2);
|
||||
Am = model(f,3:(L+2));
|
||||
plot((1:L)*Wo*4000/pi, 20*log10(Am),"r;Am;");
|
||||
axis([1 4000 -10 80]);
|
||||
hold on;
|
||||
plot((0:255)*4000/256, Sw(f,:),";Sw;");
|
||||
grid;
|
||||
|
||||
if (file_in_path(".",sw__name))
|
||||
plot((0:255)*4000/256, Sw_(f,:),"g;Sw_;");
|
||||
endif
|
||||
|
||||
if (file_in_path(".",pw_name))
|
||||
plot((0:255)*4000/256, 10*log10(Pw(f,:)),";Pw;");
|
||||
endif
|
||||
|
||||
if (file_in_path(".",snr_name))
|
||||
snr_label = sprintf(";phase SNR %4.2f dB;",snr(f));
|
||||
plot(1,1,snr_label);
|
||||
endif
|
||||
|
||||
% phase model - determine SNR and error spectrum for phase model 1
|
||||
|
||||
if (file_in_path(".",phase_name_))
|
||||
orig = Am.*exp(j*phase(f,1:L));
|
||||
synth = Am.*exp(j*phase_(f,1:L));
|
||||
signal = orig * orig';
|
||||
noise = (orig-synth) * (orig-synth)';
|
||||
snr_phase = 10*log10(signal/noise);
|
||||
|
||||
phase_err_label = sprintf("g;phase_err SNR %4.2f dB;",snr_phase);
|
||||
plot((1:L)*Wo*4000/pi, 20*log10(orig-synth), phase_err_label);
|
||||
endif
|
||||
|
||||
hold off;
|
||||
if (k == 'p')
|
||||
pngname = sprintf("%s_%d_sw",samname,f);
|
||||
png(pngname);
|
||||
endif
|
||||
|
||||
if (file_in_path(".",phase_name))
|
||||
figure(3);
|
||||
plot((1:L)*Wo*4000/pi, phase(f,1:L)*180/pi, "-o;phase;");
|
||||
axis;
|
||||
if (file_in_path(".", phase_name_))
|
||||
hold on;
|
||||
plot((1:L)*Wo*4000/pi, phase_(f,1:L)*180/pi, "g;phase after;");
|
||||
grid
|
||||
hold off;
|
||||
endif
|
||||
if (k == 'p')
|
||||
pngname = sprintf("%s_%d_phase",samname,f);
|
||||
png(pngname);
|
||||
endif
|
||||
endif
|
||||
|
||||
% synthesised speech
|
||||
|
||||
if (file_in_path(".",sn_name_))
|
||||
figure(4);
|
||||
s_ = sn_((f-3)*80+1:(f+1)*80);
|
||||
plot(s_);
|
||||
axis([1 length(s_) -20000 20000]);
|
||||
if (k == 'p')
|
||||
pngname = sprintf("%s_%d_sn_",samname,f)
|
||||
png(pngname);
|
||||
endif
|
||||
endif
|
||||
|
||||
if (file_in_path(".",ak_name))
|
||||
figure(5);
|
||||
axis;
|
||||
akw = ak(f,:);
|
||||
weight = 1.0 .^ (0:length(akw)-1);
|
||||
akw = akw .* weight;
|
||||
H = 1./fft(akw,8000);
|
||||
subplot(211);
|
||||
plot(20*log10(abs(H(1:4000))),";LPC mag spec;");
|
||||
grid;
|
||||
subplot(212);
|
||||
plot(angle(H(1:4000))*180/pi,";LPC phase spec;");
|
||||
grid;
|
||||
if (k == 'p')
|
||||
% stops multimode errors from gnuplot, I know not why...
|
||||
figure(2);
|
||||
figure(5);
|
||||
|
||||
pngname = sprintf("%s_%d_lpc",samname,f);
|
||||
png(pngname);
|
||||
endif
|
||||
endif
|
||||
|
||||
|
||||
% autocorrelation function to research voicing est
|
||||
|
||||
%M = length(s);
|
||||
%sw = s .* hanning(M)';
|
||||
%for k=0:159
|
||||
% R(k+1) = sw(1:320-k) * sw(1+k:320)';
|
||||
%endfor
|
||||
%figure(4);
|
||||
%R_label = sprintf(";R(k) %3.2f;",max(R(20:159))/R(1));
|
||||
%plot(R/R(1),R_label);
|
||||
%grid
|
||||
|
||||
figure(2);
|
||||
|
||||
% interactive menu
|
||||
|
||||
printf("\rframe: %d menu: n-next b-back p-png q-quit ", f);
|
||||
fflush(stdout);
|
||||
k = kbhit();
|
||||
if (k == 'n')
|
||||
f = f + 1;
|
||||
endif
|
||||
if (k == 'b')
|
||||
f = f - 1;
|
||||
endif
|
||||
|
||||
% optional print to PNG
|
||||
|
||||
if (k == 'p')
|
||||
pngname = sprintf("%s_%d",samname,f);
|
||||
png(pngname);
|
||||
endif
|
||||
|
||||
until (k == 'q')
|
||||
printf("\n");
|
||||
|
||||
endfunction
|
||||
|
|
@ -1,36 +0,0 @@
|
|||
% Copyright David Rowe 2009
|
||||
% This program is distributed under the terms of the GNU General Public License
|
||||
% Version 2
|
||||
%
|
||||
% plpitch.m
|
||||
% Plots two pitch tracks on top of each other, used for comparing pitch
|
||||
% estimators
|
||||
|
||||
function plpitch(pitch1_name, pitch2_name, start_fr, end_fr)
|
||||
|
||||
pitch1 = load(pitch1_name);
|
||||
pitch2 = load(pitch2_name);
|
||||
|
||||
st = 1;
|
||||
en = length(pitch1);
|
||||
if (nargin >= 3)
|
||||
st = start_fr;
|
||||
endif
|
||||
if (nargin >= 4)
|
||||
en = end_fr;
|
||||
endif
|
||||
|
||||
figure(1);
|
||||
clf;
|
||||
l1 = strcat("r;",pitch1_name,";")
|
||||
l1
|
||||
st
|
||||
en
|
||||
plot(pitch1(st:en), l1);
|
||||
axis([1 en-st 20 160]);
|
||||
l2 = strcat("g;",pitch2_name,";");
|
||||
hold on;
|
||||
plot(pitch2(st:en),l2);
|
||||
hold off;
|
||||
endfunction
|
||||
|
||||
|
|
@ -1,89 +0,0 @@
|
|||
% Copyright David Rowe 2009
|
||||
% This program is distributed under the terms of the GNU General Public License
|
||||
% Version 2
|
||||
%
|
||||
% Plot voicing information from sample and dump files.
|
||||
%
|
||||
% samfilename is the raw source file, e.g. "../raw/hts1a.raw"
|
||||
% samname is the dumpfile prefix, e.g. "../src/hts1a"
|
||||
%
|
||||
% There is a 160 sample (two frame delay) from the when a sample
|
||||
% enters the input buffer until it is at the centre of the analysis window
|
||||
|
||||
function plvoicing(samfilename, samname, start_f, end_f, pngname)
|
||||
|
||||
fs=fopen(samfilename,"rb");
|
||||
s=fread(fs,Inf,"short");
|
||||
|
||||
snr_name = strcat(samname,"_snr.txt");
|
||||
snr = load(snr_name);
|
||||
model_name = strcat(samname,"_model.txt");
|
||||
model = load(model_name);
|
||||
|
||||
Wo = model((start_f+1):end_f,1);
|
||||
F0 = Wo*4000/pi;
|
||||
dF0 = F0(1:length(Wo)-1) - F0(2:length(Wo));
|
||||
|
||||
% work out LP and HP energy
|
||||
|
||||
for f=(start_f+1):end_f
|
||||
L = model(f,2);
|
||||
Am = model(f,3:(L+2));
|
||||
L2 = floor(L/2);
|
||||
elow = Am(1:L2) * Am(1:L2)';
|
||||
ehigh = Am(L2:L) * Am(L2:L)';
|
||||
erat(f-(start_f+1)+1) = 10*log10(elow/ehigh);
|
||||
endfor
|
||||
|
||||
figure(1);
|
||||
clf;
|
||||
sp = s((start_f-2)*80:(end_f-2)*80);
|
||||
plot(sp);
|
||||
hold on;
|
||||
vhigh = snr((start_f+1):end_f) > 7;
|
||||
vlow = snr((start_f+1):end_f) > 4;
|
||||
|
||||
% test correction based on erat
|
||||
|
||||
vlowadj = vlow;
|
||||
|
||||
for f=1:length(erat)-1
|
||||
if (vlow(f) == 0)
|
||||
if (erat(f) > 10)
|
||||
vlowadj(f) = 1;
|
||||
endif
|
||||
endif
|
||||
if (vlow(f) == 1)
|
||||
if (erat(f) < -10)
|
||||
vlowadj(f) = 0;
|
||||
endif
|
||||
if (abs(dF0(f)) > 15)
|
||||
vlowadj(f) = 0;
|
||||
endif
|
||||
endif
|
||||
endfor
|
||||
|
||||
x = 1:(end_f-start_f);
|
||||
plot(x*80,snr((start_f+1):end_f)*1000,';SNRdB x 1000;g+');
|
||||
plot(x*80,-8000 + vhigh*2000,';7dB thresh;g');
|
||||
plot(x*80,-11000 + vlowadj*2000,';vlow with corr;g');
|
||||
plot(x*80,erat*1000,';elow/ehigh in dB;r');
|
||||
plot(x*80,-14000 + vlow*2000,';4dB thresh;r');
|
||||
hold off;
|
||||
grid
|
||||
if (nargin == 5)
|
||||
print(pngname, "-dpng", "-S500,500")
|
||||
endif
|
||||
|
||||
figure(2)
|
||||
Wo = model((start_f+1):end_f,1);
|
||||
F0 = Wo*4000/pi;
|
||||
dF0 = F0(1:length(Wo)-1) - F0(2:length(Wo));
|
||||
%plot(dF0,'+--')
|
||||
%hold on;
|
||||
%plot([ 1 length(dF0) ], [10 10] ,'r')
|
||||
%plot([ 1 length(dF0) ], [-10 -10] ,'r')
|
||||
%axis([1 length(dF0) -50 50])
|
||||
%hold off;
|
||||
plot(F0,'+--')
|
||||
endfunction
|
||||
|
|
@ -1,27 +0,0 @@
|
|||
% power_from_gr.m
|
||||
% David Rowe June 2018
|
||||
%
|
||||
% Measure power of signal from stdio, used for SNR tests from analog radios
|
||||
|
||||
#{
|
||||
$ rec -t raw -r 8000 -s -2 -c 1 - -q | octave --no-gui -qf power_from_stdio.m
|
||||
#}
|
||||
|
||||
graphics_toolkit ("gnuplot")
|
||||
|
||||
Fs = 48000; % sample rate in Hz
|
||||
shorts_per_sample = 1; % real samples
|
||||
|
||||
[s,c] = fread(stdin, shorts_per_sample*Fs, "short");
|
||||
|
||||
while c
|
||||
S = fft(s.*hanning(Fs));
|
||||
SdB = 20*log10(abs(S));
|
||||
figure(1); plot(real(s)); axis([0 Fs -3E4 3E4]);
|
||||
figure(2); plot(SdB); axis([0 12000 40 160]);
|
||||
|
||||
printf("power: %f dB\n", 10*log10(var(s)));
|
||||
%pause(2);
|
||||
[s,c] = fread(stdin, shorts_per_sample*Fs, "short");
|
||||
endwhile
|
||||
|
||||
|
|
@ -1,37 +0,0 @@
|
|||
% pulse.m
|
||||
% David Rowe August 2009
|
||||
%
|
||||
% Experiments with human pulse perception for sinusoidal codecs
|
||||
|
||||
function pulse(samname)
|
||||
|
||||
A = 1000;
|
||||
K = 16000;
|
||||
N = 80;
|
||||
frames = K/N;
|
||||
s = zeros(1,K);
|
||||
|
||||
for f=1:frames
|
||||
% lets try placing np random pulses in every frame
|
||||
|
||||
P = 20 + (160-20)*rand(1,1);
|
||||
Wo = 2*pi/P;
|
||||
L = floor(pi/Wo);
|
||||
sf = zeros(1,N);
|
||||
for m=1:L/2:L
|
||||
pos = floor(rand(1,1)*N)+1;
|
||||
%pos = 50;
|
||||
for l=m:m+L/2-1
|
||||
sf = sf + A*cos(l*Wo*((f-1)*N+1:f*N) - pos*l*Wo);
|
||||
endfor
|
||||
endfor
|
||||
s((f-1)*N+1:f*N) = sf;
|
||||
endfor
|
||||
|
||||
plot(s(1:250));
|
||||
|
||||
fs=fopen(samname,"wb");
|
||||
fwrite(fs,s,"short");
|
||||
fclose(fs);
|
||||
endfunction
|
||||
|
||||
|
|
@ -1,14 +0,0 @@
|
|||
% save_array_c_header.m
|
||||
%
|
||||
% David Rowe Sep 2015
|
||||
|
||||
function save_array_c_header(array, array_name, filename)
|
||||
f=fopen(filename,"wt");
|
||||
fprintf(f,"/* Generated by save_array_c_header.m Octave function */\n\n");
|
||||
fprintf(f,"const float %s[]={\n", array_name);
|
||||
for m=1:length(array)-1
|
||||
fprintf(f," % .16f,\n",array(m));
|
||||
endfor
|
||||
fprintf(f," % .16f\n};\n",array(length(array)));
|
||||
fclose(f);
|
||||
endfunction
|
||||
|
|
@ -1,12 +0,0 @@
|
|||
% save_comp.m
|
||||
% David Rowe Aug 2020
|
||||
|
||||
function save_comp(fn, iq)
|
||||
l = length(iq);
|
||||
s = zeros(1,2*l);
|
||||
s(1:2:2*l) = real(iq);
|
||||
s(2:2:2*l) = imag(iq);
|
||||
fs=fopen(fn,"wb");
|
||||
s = fwrite(fs,s,"float32");
|
||||
fclose(fs);
|
||||
endfunction
|
||||
|
|
@ -1,12 +0,0 @@
|
|||
% save_f32.m
|
||||
% David Rowe Sep 2021
|
||||
%
|
||||
% save a matrix to .f32 binary files in row-major order
|
||||
|
||||
function save_f32(fn, m)
|
||||
f=fopen(fn,"wb");
|
||||
[r c] = size(m);
|
||||
mlinear = reshape(m', 1, r*c);
|
||||
fwrite(f, mlinear, 'float32');
|
||||
fclose(f);
|
||||
endfunction
|
||||
|
|
@ -1,13 +0,0 @@
|
|||
% save_hackrf.m
|
||||
%
|
||||
% David Rowe Aug 2020
|
||||
|
||||
function save_hackrf(fn,iq)
|
||||
l = length(iq);
|
||||
s = zeros(1,2*l);
|
||||
s(1:2:2*l) = real(iq);
|
||||
s(2:2:2*l) = imag(iq);
|
||||
fs = fopen(fn,"wb");
|
||||
fwrite(fs,s,"schar");
|
||||
fclose(fs);
|
||||
endfunction
|
||||
|
|
@ -1,7 +0,0 @@
|
|||
% save_raw.m
|
||||
% David Rowe 9 Feb 2015
|
||||
|
||||
function s = save_raw(fn,s)
|
||||
fs=fopen(fn,"wb");
|
||||
fwrite(fs,s,"short");
|
||||
endfunction
|
||||
|
|
@ -1,262 +0,0 @@
|
|||
% snr_curves_plot.m
|
||||
%
|
||||
% Companion script for unittest/raw_data_curves
|
||||
|
||||
1;
|
||||
|
||||
function state_vec = set_graphics_state_print()
|
||||
textfontsize = get(0,"defaulttextfontsize");
|
||||
linewidth = get(0,"defaultlinelinewidth");
|
||||
markersize = get(0, "defaultlinemarkersize");
|
||||
set(0, "defaulttextfontsize", 16);
|
||||
set(0, "defaultaxesfontsize", 16);
|
||||
set(0, "defaultlinelinewidth", 1);
|
||||
state_vec = [textfontsize linewidth markersize];
|
||||
endfunction
|
||||
|
||||
function set_graphics_state_screen(state_vec)
|
||||
textfontsize = state_vec(1);
|
||||
linewidth = state_vec(2);
|
||||
markersize = state_vec(3);
|
||||
set(0, "defaulttextfontsize", textfontsize);
|
||||
set(0, "defaultaxesfontsize", textfontsize);
|
||||
set(0, "defaultlinelinewidth", linewidth);
|
||||
set(0, "defaultlinemarkersize", markersize);
|
||||
endfunction
|
||||
|
||||
function [snr_ch per] = snr_scatter(source, mode, channel, colour)
|
||||
suffix = sprintf("_%s_%s_%s",source, mode, channel);
|
||||
snr = load(sprintf("snr%s.txt",suffix));
|
||||
offset = load(sprintf("offset%s.txt",suffix));
|
||||
snr -= offset;
|
||||
snr_x = []; snrest_y = [];
|
||||
for i=1:length(snr)
|
||||
fn = sprintf('snrest%s_%d.txt',suffix,i);
|
||||
if exist(fn,'file') == 2
|
||||
snrest=load(fn);
|
||||
if i == length(snr)
|
||||
plot(snr(i)*ones(1,length(snrest)), snrest, sprintf('%s;%s %s;',colour,source,mode));
|
||||
else
|
||||
plot(snr(i)*ones(1,length(snrest)), snrest, sprintf('%s',colour));
|
||||
end
|
||||
snr_x = [snr_x snr(i)]; snrest_y = [snrest_y mean(snrest)];
|
||||
end
|
||||
end
|
||||
plot(snr_x, snrest_y, sprintf('%s', colour));
|
||||
endfunction
|
||||
|
||||
function [snr_ch per] = per_snr(mode, colour)
|
||||
snrch = load(sprintf("snrch_%s.txt",mode));
|
||||
snroffset = load(sprintf("snroffset_%s.txt",mode));
|
||||
snrch -= snroffset;
|
||||
per = load(sprintf("per_%s.txt",mode));
|
||||
plot(snrch, per, sprintf('%so-;%s;', colour, mode));
|
||||
endfunction
|
||||
|
||||
function snrest_snr_screen(source, channel)
|
||||
clf; hold on;
|
||||
snr_scatter(source, 'datac0', channel,'b+-')
|
||||
snr_scatter(source, 'datac1', channel,'g+-')
|
||||
snr_scatter(source, 'datac3', channel,'r+-')
|
||||
snr_scatter(source, 'datac4', channel,'c+-')
|
||||
snr_scatter(source, 'datac13', channel,'m+-')
|
||||
xlabel('SNR (dB)'); ylabel('SNRest (dB)'); grid('minor');
|
||||
axis([-12 12 -12 12]);
|
||||
a = axis;
|
||||
plot([a(1) a(2)],[a(1) a(2)],'bk-');
|
||||
hold off; grid;
|
||||
if strcmp(source,'ctx')
|
||||
title(sprintf('SNR estimate versus SNR (%s) (no compression)', channel));
|
||||
else
|
||||
title(sprintf('SNR estimate versus SNR (%s) (with compression)', channel));
|
||||
end
|
||||
legend('location','northwest');
|
||||
endfunction
|
||||
|
||||
function snrest_snr_print(source, channel)
|
||||
state_vec = set_graphics_state_print();
|
||||
snrest_snr_screen(source, channel);
|
||||
print(sprintf("snrest_snr_%s.png", source), "-dpng", "-S1000,800");
|
||||
set_graphics_state_screen(state_vec);
|
||||
endfunction
|
||||
|
||||
function ber_per_v_snr(source, mode, channel, colour)
|
||||
suffix = sprintf("_%s_%s_%s.txt",source, mode, channel);
|
||||
snr = load(sprintf("snr%s",suffix));
|
||||
offset = load(sprintf("offset%s",suffix));
|
||||
snr -= offset;
|
||||
ber = load(sprintf("ber%s",suffix)) + 1E-6;
|
||||
per = load(sprintf("per%s",suffix)) + 1E-6;
|
||||
semilogy(snr, ber, sprintf('%s;%s %s ber;', colour, source, mode));
|
||||
semilogy(snr, per, sprintf('%s;%s %s per;', colour, source, mode),'linewidth',3,'markersize',10);
|
||||
endfunction
|
||||
|
||||
function per_v_snr(source, mode, channel, colour)
|
||||
suffix = sprintf("_%s_%s_%s.txt",source, mode, channel);
|
||||
snr = load(sprintf("snr%s",suffix));
|
||||
offset = load(sprintf("offset%s",suffix));
|
||||
snr -= offset;
|
||||
per = load(sprintf("per%s",suffix)) + 1E-6;
|
||||
if strcmp(channel,"awgn")
|
||||
semilogy(snr, per, sprintf('%s;%s %s;', colour, mode, channel));
|
||||
else
|
||||
semilogy(snr, per, sprintf('%s;%s %s;', colour, mode, channel),'linewidth',3,'markersize',10);
|
||||
end
|
||||
endfunction
|
||||
|
||||
function thruput_v_snr(source, mode, channel, colour)
|
||||
suffix = sprintf("_%s_%s_%s.txt",source, mode, channel);
|
||||
snr = load(sprintf("snr%s",suffix));
|
||||
offset = load(sprintf("offset%s",suffix));
|
||||
snr -= offset;
|
||||
per = load(sprintf("per%s",suffix)) + 1E-6;
|
||||
if strcmp(mode,"datac0") Rb=291; end;
|
||||
if strcmp(mode,"datac1") Rb=980; end;
|
||||
if strcmp(mode,"datac3") Rb=321; end;
|
||||
if strcmp(mode,"datac4") Rb=87; end;
|
||||
if strcmp(mode,"datac13") Rb=65; end;
|
||||
if strcmp(channel,"awgn")
|
||||
plot(snr, Rb*(1-per), sprintf('%s;%s %s;', colour, mode, channel));
|
||||
else
|
||||
plot(snr, Rb*(1-per), sprintf('%s;%s %s;', colour, mode, channel),'linewidth',3,'markersize',10);
|
||||
end
|
||||
endfunction
|
||||
|
||||
function octave_ch_noise_screen(channel)
|
||||
clf; hold on;
|
||||
ber_per_v_snr('oct','datac0',channel,'bo-')
|
||||
ber_per_v_snr('ch' ,'datac0',channel,'bx-')
|
||||
ber_per_v_snr('oct','datac1',channel,'go-')
|
||||
ber_per_v_snr('ch' ,'datac1',channel,'gx-')
|
||||
ber_per_v_snr('oct','datac3',channel,'ro-')
|
||||
ber_per_v_snr('ch' ,'datac3',channel,'rx-')
|
||||
xlabel('SNR (dB)'); grid;
|
||||
hold off;
|
||||
if strcmp(channel,"awgn")
|
||||
axis([-6 8 1E-3 1]);
|
||||
else
|
||||
axis([-2 12 1E-3 1]);
|
||||
end
|
||||
title(sprintf('Comparsion of Measuring SNR from Octave and ch tool (%s)', channel));
|
||||
endfunction
|
||||
|
||||
function octave_ch_noise_print(channel)
|
||||
state_vec = set_graphics_state_print();
|
||||
octave_ch_noise_screen(channel);
|
||||
print(sprintf("octave_ch_noise_%s.png", channel), "-dpng","-S1000,800");
|
||||
set_graphics_state_screen(state_vec);
|
||||
endfunction
|
||||
|
||||
function octave_c_tx_screen(channel)
|
||||
clf; hold on;
|
||||
ber_per_v_snr('oct','datac0',channel,'bo-')
|
||||
ber_per_v_snr('ctx','datac0',channel,'bx-')
|
||||
ber_per_v_snr('oct','datac1',channel,'go-')
|
||||
ber_per_v_snr('ctx','datac1',channel,'gx-')
|
||||
ber_per_v_snr('oct','datac3',channel,'ro-')
|
||||
ber_per_v_snr('ctx','datac3',channel,'rx-')
|
||||
xlabel('SNR (dB)'); grid;
|
||||
hold off;
|
||||
if strcmp(channel,"awgn")
|
||||
axis([-6 8 1E-3 1]);
|
||||
else
|
||||
axis([-2 12 1E-3 1]);
|
||||
end
|
||||
title(sprintf('Comparsion of Octave Tx and C Tx (no compression) (%s)', channel));
|
||||
endfunction
|
||||
|
||||
function octave_c_tx_print(channel)
|
||||
state_vec = set_graphics_state_print();
|
||||
octave_c_tx_screen(channel);
|
||||
print(sprintf("octave_c_tx_%s.png", channel), "-dpng","-S1000,800");
|
||||
set_graphics_state_screen(state_vec);
|
||||
endfunction
|
||||
|
||||
function octave_c_tx_comp_screen(channel)
|
||||
clf; hold on;
|
||||
ber_per_v_snr('oct','datac0',channel,'bo-')
|
||||
ber_per_v_snr('ctxc','datac0',channel,'bx-')
|
||||
ber_per_v_snr('oct','datac1',channel,'go-')
|
||||
ber_per_v_snr('ctxc','datac1',channel,'gx-')
|
||||
ber_per_v_snr('oct','datac3',channel,'ro-')
|
||||
ber_per_v_snr('ctxc','datac3',channel,'rx-')
|
||||
xlabel('SNR (dB)'); grid;
|
||||
hold off;
|
||||
if strcmp(channel,"awgn")
|
||||
axis([-6 8 1E-3 1]);
|
||||
else
|
||||
axis([-2 12 1E-3 1]);
|
||||
end
|
||||
title(sprintf('Comparsion of Octave Tx and C Tx (with compression) (%s)', channel));
|
||||
endfunction
|
||||
|
||||
function octave_c_tx_comp_print(channel)
|
||||
state_vec = set_graphics_state_print();
|
||||
octave_c_tx_comp_screen(channel);
|
||||
print(sprintf("octave_c_tx_comp_%s.png", channel), "-dpng","-S1000,800");
|
||||
set_graphics_state_screen(state_vec);
|
||||
endfunction
|
||||
|
||||
% composite AWGN and MPP for compressed
|
||||
function c_tx_comp_screen
|
||||
clf; hold on;
|
||||
per_v_snr('ctxc','datac0','awgn','bo-')
|
||||
per_v_snr('ctxc','datac1','awgn','go-')
|
||||
per_v_snr('ctxc','datac3','awgn','ro-')
|
||||
per_v_snr('ctxc','datac4','awgn','co-')
|
||||
per_v_snr('ctxc','datac13','awgn','mo-')
|
||||
per_v_snr('ctxc','datac0','mpp','bx-')
|
||||
per_v_snr('ctxc','datac1','mpp','gx-')
|
||||
per_v_snr('ctxc','datac3','mpp','rx-')
|
||||
per_v_snr('ctxc','datac4','mpp','cx-')
|
||||
per_v_snr('ctxc','datac13','mpp','mx-')
|
||||
xlabel('SNR (dB)'); ylabel('PER'); grid;
|
||||
hold off;
|
||||
axis([-10 10 1E-3 1]);
|
||||
title('PER of C Raw Data Modes (with compression)');
|
||||
endfunction
|
||||
|
||||
function c_tx_comp_print;
|
||||
state_vec = set_graphics_state_print();
|
||||
c_tx_comp_screen;
|
||||
print("c_tx_comp.png", "-dpng","-S1000,800");
|
||||
set_graphics_state_screen(state_vec);
|
||||
endfunction
|
||||
|
||||
function c_tx_comp_thruput_screen
|
||||
clf; hold on;
|
||||
thruput_v_snr('ctxc','datac0','awgn','bo-')
|
||||
thruput_v_snr('ctxc','datac1','awgn','go-')
|
||||
thruput_v_snr('ctxc','datac3','awgn','ro-')
|
||||
thruput_v_snr('ctxc','datac4','awgn','co-')
|
||||
thruput_v_snr('ctxc','datac13','awgn','mo-')
|
||||
thruput_v_snr('ctxc','datac0','mpp','bx-')
|
||||
thruput_v_snr('ctxc','datac1','mpp','gx-')
|
||||
thruput_v_snr('ctxc','datac3','mpp','rx-')
|
||||
thruput_v_snr('ctxc','datac4','mpp','cx-')
|
||||
thruput_v_snr('ctxc','datac13','mpp','mx-')
|
||||
xlabel('SNR (dB)'); ylabel('bits/s'); grid;
|
||||
hold off;
|
||||
axis([-10 10 0 1000]);
|
||||
title(' Throughput for C Tx (with compression)');
|
||||
legend('location','west');
|
||||
endfunction
|
||||
|
||||
function c_tx_comp_thruput_print;
|
||||
state_vec = set_graphics_state_print;
|
||||
c_tx_comp_thruput_screen;
|
||||
print("c_tx_comp_thruput.png", "-dpng","-S1000,800");
|
||||
set_graphics_state_screen(state_vec);
|
||||
endfunction
|
||||
|
||||
#{
|
||||
figure(1); octave_ch_noise_screen;
|
||||
figure(2); octave_c_tx_screen;
|
||||
figure(3); octave_c_tx_comp_screen
|
||||
figure(4); snrest_snr_screen;
|
||||
|
||||
figure(5); octave_ch_noise_print;
|
||||
figure(6); octave_c_tx_print;
|
||||
figure(7); octave_c_tx_comp_print;
|
||||
figure(8); snrest_snr_print;
|
||||
#}
|
||||
|
|
@ -1,84 +0,0 @@
|
|||
% tdetphase.m
|
||||
% David Rowe August 2017
|
||||
%
|
||||
% Testing Hilbert Transform recover of phase from magnitude spectra
|
||||
|
||||
newamp;
|
||||
Fs = 8000;
|
||||
|
||||
w = 2*pi*500/Fs; gamma = 0.95
|
||||
ak = [1 -2*gamma*cos(w) gamma*gamma];
|
||||
Nfft = 512;
|
||||
|
||||
% Test 1 - compare phase from freqz for 2nd order system (all pole filter)
|
||||
% - uses internal test of determine_phase()
|
||||
|
||||
h = freqz(1,ak,Nfft/2);
|
||||
|
||||
% note dummy_model not used, as determine_phase() is used in test mode
|
||||
|
||||
L = 20; Wo = pi/(L+1);
|
||||
dummy_model = [Wo L ones(1,L)];
|
||||
phase = determine_phase(dummy_model, 1, Nfft, ak);
|
||||
|
||||
fg = 1;
|
||||
figure(fg++); clf;
|
||||
subplot(211); plot(20*log10(abs(h))); title('test 1');
|
||||
subplot(212); plot(angle(h)); hold on; plot(phase(1:Nfft/2),'g'); hold off;
|
||||
|
||||
% Test 2 - feed in harmonic magnitudes
|
||||
|
||||
F0 = 100; Wo = 2*pi*F0/Fs; L = floor(pi/Wo);
|
||||
Am = zeros(1,L);
|
||||
for m=1:L
|
||||
b = round(m*Wo*Nfft/(2*pi));
|
||||
Am(m) = abs(h(b));
|
||||
end
|
||||
AmdB = 20*log10(Am);
|
||||
model = [Wo L Am];
|
||||
[phase Gdbfk s] = determine_phase(model, 1, Nfft);
|
||||
|
||||
fftx = (1:Nfft/2)*(Fs/Nfft);
|
||||
harmx = (1:L)*Wo*Fs/(2*pi);
|
||||
|
||||
figure(fg++); clf;
|
||||
subplot(211); plot(fftx, Gdbfk(1:Nfft/2));
|
||||
subplot(212); plot(s(1:Nfft/2))
|
||||
|
||||
figure(fg++); clf;
|
||||
subplot(211); plot(fftx, 20*log10(abs(h)));
|
||||
hold on; plot(harmx, AmdB, 'g+'); plot(fftx, Gdbfk(1:Nfft/2), 'r'); hold off;
|
||||
subplot(212); plot(fftx, angle(h)); hold on; plot(fftx, phase(1:Nfft/2),'g'); hold off;
|
||||
|
||||
% Test 3 - Use real harmonic amplitudes
|
||||
|
||||
model = load("../build_linux/src/hts1a_model.txt");
|
||||
phase_orig = load("../build_linux/src/hts1a_phase.txt");
|
||||
|
||||
f = 184;
|
||||
Wo = model(f,1); L = model(f,2); Am = model(f,3:L+2); AmdB = 20*log10(Am);
|
||||
[phase Gdbfk s] = determine_phase(model, f, Nfft);
|
||||
|
||||
fftx = (1:Nfft/2)*(Fs/Nfft);
|
||||
harmx = (1:L)*Wo*Fs/(2*pi);
|
||||
|
||||
figure(fg++); clf;
|
||||
subplot(211); plot(fftx, Gdbfk(1:Nfft/2));
|
||||
subplot(212); plot(s(1:Nfft/2))
|
||||
|
||||
figure(fg++); clf;
|
||||
subplot(211); plot(harmx, AmdB, 'g+');
|
||||
hold on; plot(fftx, Gdbfk(1:Nfft/2), 'r'); hold off;
|
||||
subplot(212); plot(fftx, phase(1:Nfft/2),'g');
|
||||
|
||||
% synthesise using phases
|
||||
|
||||
N = 320;
|
||||
s = s_phase = zeros(1,N);
|
||||
for m=1:L/4
|
||||
s = s + Am(m)*cos(m*Wo*(1:N) + phase_orig(f,m));
|
||||
b = round(m*Wo*Nfft/(2*pi));
|
||||
s_phase = s_phase + Am(m)*cos(m*Wo*(1:N) + phase(b));
|
||||
end
|
||||
figure(fg++); clf;
|
||||
subplot(211); plot(s); subplot(212); plot(s_phase,'g');
|
||||
|
|
@ -1,465 +0,0 @@
|
|||
% 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);
|
||||
594
octave/trellis.m
594
octave/trellis.m
|
|
@ -1,594 +0,0 @@
|
|||
% trellis.m
|
||||
% David Rowe July 2021
|
||||
%
|
||||
% Testing trellis decoding of Codec 2 Vector Quantiser (VQ)
|
||||
% information. Uses soft decision information, probablility of state
|
||||
% transitions, and left over redundancy to correct errors on VQ
|
||||
% reception.
|
||||
%
|
||||
% VQ indexes are transmitted as codewords mapped to +-1
|
||||
%
|
||||
% y = c + n
|
||||
%
|
||||
% where c is the transmitted codeword, y is the received codeword,
|
||||
% and n is Gaussian noise.
|
||||
%
|
||||
% This script generates the test data files:
|
||||
%
|
||||
% cd codec2/build_linux
|
||||
% ../script/train_trellis.sh
|
||||
%
|
||||
% Results so far (August 2021):
|
||||
%
|
||||
% 1/ 2dB improvement with nstages=3, dec=1
|
||||
% 2/ No useful improvement with nstages=3, dec=4. This is required for a practical codec to
|
||||
% get a useful bit rate.
|
||||
|
||||
1;
|
||||
|
||||
% converts a decimal value to a soft dec binary value
|
||||
function c = dec2sd(dec, nbits)
|
||||
|
||||
% convert to binary
|
||||
|
||||
c = zeros(1,nbits);
|
||||
for j=0:nbits-1
|
||||
mask = 2.^j;
|
||||
if bitand(dec,mask)
|
||||
c(nbits-j) = 1;
|
||||
end
|
||||
end
|
||||
|
||||
% map to +/- 1
|
||||
|
||||
c = -1 + 2*c;
|
||||
endfunction
|
||||
|
||||
|
||||
% y is vector of received soft decision values (e.g +/-1 + noise)
|
||||
function [txp indexes] = ln_tx_codeword_prob_given_rx_codeword_y(y, nstates, C)
|
||||
nbits = length(y);
|
||||
np = 2.^nbits;
|
||||
|
||||
% Find log probability of all possible transmitted codewords
|
||||
txp = C * y';
|
||||
|
||||
% return most probable codewords (number of states to search)
|
||||
[txp indexes] = sort(txp,"descend");
|
||||
txp = txp(1:nstates);
|
||||
indexes = indexes(1:nstates) - 1;
|
||||
endfunction
|
||||
|
||||
% A matrix of all possible tx codewords C, one per row
|
||||
function C = precompute_C(nbits)
|
||||
np = 2.^nbits;
|
||||
|
||||
C = zeros(np, nbits);
|
||||
for r=0:np-1
|
||||
C(r+1,:) = dec2sd(r,nbits);
|
||||
end
|
||||
|
||||
endfunction
|
||||
|
||||
|
||||
% work out transition probability matrix, given lists of current and next
|
||||
% candidate codewords
|
||||
|
||||
function tp = calculate_tp(vq, sd_table, h_table, indexes_current, indexes_next, verbose)
|
||||
ntxcw = length(indexes_current);
|
||||
tp = zeros(ntxcw, ntxcw);
|
||||
for txcw_current=1:ntxcw
|
||||
index_current = indexes_current(txcw_current);
|
||||
for txcw_next=1:ntxcw
|
||||
index_next = indexes_next(txcw_next);
|
||||
dist = vq(index_current+1,:) - vq(index_next+1,:);
|
||||
sd = mean(dist.^2);
|
||||
p = prob_from_hist(sd_table, h_table, sd);
|
||||
if bitand(verbose, 0x2)
|
||||
printf("index_current: %d index_next: %d sd: %f p: %f\n", index_current, index_next, sd, p);
|
||||
end
|
||||
tp(txcw_current, txcw_next) = log(p);
|
||||
end
|
||||
end
|
||||
endfunction
|
||||
|
||||
|
||||
% y is the sequence received soft decision codewords, each row is one
|
||||
% codeword in time. sd_table and h_table map SD to
|
||||
% probability. Returns the most likely transmitted VQ index ind in the
|
||||
% middle of the codeword sequence y. We search the most likely ntxcw
|
||||
% tx codewords out of 2^nbits possibilities.
|
||||
|
||||
function ind = find_most_likely_index(y, vq, C, sd_table, h_table, nstages, ntxcw, verbose)
|
||||
[ncodewords nbits] = size(y);
|
||||
|
||||
% populate the nodes of the trellis with the most likely transmitted codewords
|
||||
txp = zeros(nstages, ntxcw); indexes = zeros(nstages, ntxcw);
|
||||
for s=1:nstages
|
||||
[atxp aindexes] = ln_tx_codeword_prob_given_rx_codeword_y(y(s,:), ntxcw, C);
|
||||
txp(s,:) = atxp;
|
||||
indexes(s,:) = aindexes;
|
||||
end
|
||||
|
||||
if verbose
|
||||
printf("rx_codewords:\n");
|
||||
for r=1:ncodewords
|
||||
for c=1:nbits
|
||||
printf("%7.2f", y(r,c));
|
||||
end
|
||||
printf("\n");
|
||||
end
|
||||
|
||||
printf("\nProbability of each tx codeword index/binary/ln(prob):\n");
|
||||
printf(" ");
|
||||
for s=1:nstages
|
||||
printf("Time n%+d ", s - (floor(nstages/2)+1));
|
||||
end
|
||||
printf("\n");
|
||||
|
||||
for i=1:ntxcw
|
||||
printf("%d ", i);
|
||||
for s=1:nstages
|
||||
ind = indexes(s,i);
|
||||
printf("%4d %12s %5.2f ", ind, dec2bin(ind,nbits), txp(s, i));
|
||||
end
|
||||
printf("\n");
|
||||
end
|
||||
printf("\n");
|
||||
end
|
||||
|
||||
% Determine transition probability matrix for each stage, this
|
||||
% changes between stages as lists of candidate tx codewords
|
||||
% changes
|
||||
|
||||
tp = zeros(nstages, ntxcw, ntxcw);
|
||||
for s=1:nstages-1
|
||||
if verbose printf("Calc tp(%d,:,:)\n", s), end
|
||||
tp(s,:,:) = calculate_tp(vq, sd_table, h_table, indexes(s,:), indexes(s+1,:), verbose);
|
||||
end
|
||||
|
||||
if verbose
|
||||
printf("Evaluation of all possible paths:\n");
|
||||
printf(" ");
|
||||
for s=1:nstages
|
||||
printf(" n%+d", s - (floor(nstages/2)+1));
|
||||
end
|
||||
printf(" indexes");
|
||||
printf(" ");
|
||||
|
||||
for s=1:nstages
|
||||
printf(" txp(%d)", s-1);
|
||||
if s < nstages
|
||||
printf(" tp(%d,%d) ", s-1,s);
|
||||
end
|
||||
end
|
||||
printf(" prob max_prob\n");
|
||||
end
|
||||
|
||||
% OK lets search all possible paths and find most probable
|
||||
|
||||
n = ones(1,nstages); % current node at each stage through trellis, describes current path
|
||||
max_prob = -100;
|
||||
do
|
||||
|
||||
if bitand(verbose, 0x4)
|
||||
printf(" ");
|
||||
for s=1:nstages
|
||||
printf("%4d", n(s)-1);
|
||||
end
|
||||
printf(" ");
|
||||
for s=1:nstages
|
||||
printf("%4d ", indexes(s,n(s)));
|
||||
end
|
||||
end
|
||||
|
||||
% find the probability of current path
|
||||
prob = 0;
|
||||
for s=1:nstages
|
||||
prob += txp(s, n(s));
|
||||
if bitand(verbose,0x4)
|
||||
printf("%8.2f ", txp(s, n(s)));
|
||||
end
|
||||
if s < nstages
|
||||
prob += tp(s, n(s), n(s+1));
|
||||
if bitand(verbose,0x4)
|
||||
printf("%8.2f ", tp(s, n(s), n(s+1)));
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if (prob > max_prob)
|
||||
max_prob = prob;
|
||||
max_n = n;
|
||||
end
|
||||
|
||||
if bitand(verbose,0x4)
|
||||
printf("%9.2f %9.2f\n", prob, max_prob);
|
||||
end
|
||||
|
||||
% next path
|
||||
|
||||
s = nstages;
|
||||
n(s)++;
|
||||
while (s && (n(s) == (ntxcw+1)))
|
||||
n(s) = 1;
|
||||
s--;
|
||||
if s > 0
|
||||
n(s)++;
|
||||
end
|
||||
end
|
||||
until (sum(n) == nstages)
|
||||
|
||||
middle = floor(nstages/2)+1;
|
||||
ind = indexes(middle, max_n(middle));
|
||||
if verbose
|
||||
printf("\nMost likely path through nodes... ");
|
||||
for s=1:nstages
|
||||
printf("%4d ", max_n(s)-1);
|
||||
end
|
||||
printf("\nMost likely path through indexes: ");
|
||||
for s=1:nstages
|
||||
printf("%4d ", indexes(s,max_n(s)));
|
||||
end
|
||||
printf("\nMost likely VQ index at time n..: %4d\n", ind);
|
||||
end
|
||||
endfunction
|
||||
|
||||
|
||||
% Given a normalised histogram, estimate probability from SD
|
||||
function p = prob_from_hist(sd_table, h_table, sd)
|
||||
p = interp1 (sd_table, h_table, sd, "extrap", "nearest");
|
||||
endfunction
|
||||
|
||||
|
||||
% Calculate a normalised histogram of the SD of adjacent frames from
|
||||
% a file of output vectors from the VQ.
|
||||
function [sd_table h_table] = vq_hist(vq_output_fn, dec=1)
|
||||
K=20; K_st=2+1; K_en=16+1;
|
||||
vq_out = load_f32(vq_output_fn, K);
|
||||
[r c]= size(vq_out);
|
||||
diff = vq_out(dec+1:end,K_st:K_en) - vq_out(1:end-dec,K_st:K_en);
|
||||
% Octave efficient way to determine MSE or each row of matrix
|
||||
sd_adj = meansq(diff');
|
||||
[h_table sd_table] = hist(sd_adj,100,1);
|
||||
h_table = max(h_table, 1E-5);
|
||||
endfunction
|
||||
|
||||
|
||||
% vector quantise a sequence of target input vectors, returning the VQ indexes and
|
||||
% quantised vectors target_
|
||||
function [indexes target_] = vector_quantiser(vq, target, verbose=1)
|
||||
[vq_size K] = size(vq);
|
||||
[ntarget tmp] = size(target);
|
||||
target_ = zeros(ntarget,K);
|
||||
indexes = zeros(1,ntarget);
|
||||
for i=1:ntarget
|
||||
best_e = 1E32;
|
||||
for ind=1:vq_size
|
||||
e = sum((vq(ind,:)-target(i,:)).^2);
|
||||
if verbose printf("i: %d ind: %d e: %f\n", i, ind, e), end;
|
||||
if e < best_e
|
||||
best_e = e;
|
||||
best_ind = ind;
|
||||
end
|
||||
end
|
||||
if verbose printf("best_e: %f best_ind: %d\n", best_e, best_ind), end;
|
||||
target_(i,:) = vq(best_ind,:); indexes(i) = best_ind;
|
||||
end
|
||||
endfunction
|
||||
|
||||
|
||||
% faster version of vector quantiser
|
||||
function [indexes target_] = vector_quantiser_fast(vq, target, verbose=1)
|
||||
[vq_size K] = size(vq);
|
||||
[ntarget tmp] = size(target);
|
||||
target_ = zeros(ntarget,K);
|
||||
indexes = zeros(1,ntarget);
|
||||
|
||||
% pre-compute energy of each VQ vector
|
||||
vqsq = zeros(vq_size,1);
|
||||
for i=1:vq_size
|
||||
vqsq(i) = vq(i,:)*vq(i,:)';
|
||||
end
|
||||
|
||||
% use efficient matrix multiplies to search for best match to target
|
||||
for i=1:ntarget
|
||||
best_e = 1E32;
|
||||
e = vqsq - 2*(vq * target(i,:)');
|
||||
[best_e best_ind] = min(e);
|
||||
if verbose printf("best_e: %f best_ind: %d\n", best_e, best_ind), end;
|
||||
target_(i,:) = vq(best_ind,:); indexes(i) = best_ind;
|
||||
end
|
||||
endfunction
|
||||
|
||||
|
||||
% VQ a target sequence of frames then run a test using vanilla uncoded/trellis decoder
|
||||
function results = run_test(target, vq, sd_table, h_table, ntxcw, nstages, EbNo, verbose)
|
||||
[frames tmp] = size(target);
|
||||
[vq_length tmp] = size(vq);
|
||||
nbits = log2(vq_length);
|
||||
nerrors = 0;
|
||||
nerrors_vanilla = 0;
|
||||
tbits = 0;
|
||||
nframes = 0;
|
||||
nper = 0;
|
||||
nper_vanilla = 0;
|
||||
|
||||
C = precompute_C(nbits);
|
||||
|
||||
% Vector Quantise target vectors sequence
|
||||
[tx_indexes target_ ] = vector_quantiser_fast(vq, target, verbose);
|
||||
% use convention of indexes starting from 0
|
||||
tx_indexes -= 1;
|
||||
% mean SD of VQ with no errors
|
||||
diff = target - target_;
|
||||
mse_noerrors = mean(diff(:).^2);
|
||||
|
||||
% construct tx symbol codewords from VQ indexes
|
||||
tx_codewords = zeros(frames, nbits);
|
||||
for f=1:frames
|
||||
tx_codewords(f,:) = dec2sd(tx_indexes(f), nbits);
|
||||
end
|
||||
|
||||
rx_codewords = tx_codewords + randn(frames, nbits)*sqrt(1/(2*EbNo));
|
||||
rx_indexes = zeros(1,frames);
|
||||
rx_indexes_vanilla = ones(1,frames);
|
||||
|
||||
ns2 = floor(nstages/2);
|
||||
for f=ns2+1:frames-ns2
|
||||
%if f==10 verbose = 1+0x2, else verbose = 0;, end
|
||||
if verbose
|
||||
printf("f: %d tx_indexes: ", f);
|
||||
for i=f-ns2:f+ns2
|
||||
printf("%d ", tx_indexes(i));
|
||||
end
|
||||
printf("\n");
|
||||
end
|
||||
tx_bits = tx_codewords(f,:) > 0;
|
||||
if verbose
|
||||
printf("tx_bits: ");
|
||||
for i=1:nbits
|
||||
printf("%d",tx_bits(i));
|
||||
end
|
||||
printf("\n");
|
||||
end
|
||||
rx_bits_vanilla = rx_codewords(f,:) > 0;
|
||||
rx_indexes(f) = find_most_likely_index(rx_codewords(f-ns2:f+ns2,:)*EbNo,
|
||||
vq, C, sd_table, h_table, nstages, ntxcw, verbose);
|
||||
rx_bits = dec2sd(rx_indexes(f), nbits) > 0;
|
||||
rx_indexes_vanilla(f) = sum(rx_bits_vanilla .* 2.^(nbits-1:-1:0));
|
||||
errors = sum(xor(tx_bits, rx_bits));
|
||||
nerrors += errors;
|
||||
if errors nper++;, end
|
||||
errors = sum(xor(tx_bits, rx_bits_vanilla));
|
||||
nerrors_vanilla += errors;
|
||||
if errors nper_vanilla++;, end
|
||||
if verbose
|
||||
printf("[%d] %d %d\n", f, nerrors, nerrors_vanilla);
|
||||
end
|
||||
tbits += nbits;
|
||||
nframes++;
|
||||
end
|
||||
|
||||
EbNodB = 10*log10(EbNo);
|
||||
target = target(ns2+1:frames-ns2,:);
|
||||
target_vanilla_ = vq(rx_indexes_vanilla(ns2+1:frames-ns2)+1,:);
|
||||
target_ = vq(rx_indexes(ns2+1:frames-ns2)+1,:);
|
||||
diff_vanilla = target - target_vanilla_;
|
||||
mse_vanilla = mean(diff_vanilla(:).^2);
|
||||
diff = target - target_;
|
||||
mse = mean(diff(:).^2);
|
||||
printf("Eb/No: %3.2f dB nframes: %2d nerrors %3d %3d BER: %4.3f %4.3f PER: %3.2f %3.2f mse: %3.2f %3.2f %3.2f\n",
|
||||
EbNodB, nframes, nerrors, nerrors_vanilla, nerrors/tbits, nerrors_vanilla/tbits,
|
||||
nper/nframes, nper_vanilla/nframes,
|
||||
mse_noerrors, mse, mse_vanilla);
|
||||
results.ber = nerrors/tbits;
|
||||
results.ber_vanilla = nerrors_vanilla/tbits;
|
||||
results.per = nper/nframes;
|
||||
results.per_vanilla = nper_vanilla/nframes;
|
||||
results.mse_noerrors = mse_noerrors;
|
||||
results.mse = mse;
|
||||
results.mse_vanilla = mse_vanilla;
|
||||
results.tx_indexes = tx_indexes;
|
||||
results.rx_indexes = rx_indexes;
|
||||
results.rx_indexes_vanilla = rx_indexes_vanilla;
|
||||
endfunction
|
||||
|
||||
% Simulations ---------------------------------------------------------------------
|
||||
|
||||
% top level function to set up and run a test
|
||||
function [results target_] = test_trellis(target_fn, nframes=100, dec=1, ntxcw=8, nstages=3, EbNodB=3, verbose=0)
|
||||
K = 20; K_st=2+1; K_en=16+1;
|
||||
vq_fn = "../build_linux/vq_stage1_bs004.f32";
|
||||
vq_output_fn = "../build_linux/all_speech_8k_test.f32";
|
||||
|
||||
% load VQ
|
||||
vq = load_f32(vq_fn, K);
|
||||
[vq_size tmp] = size(vq);
|
||||
vqsub = vq(:,K_st:K_en);
|
||||
|
||||
% load file of VQ-ed vectors to train up SD PDF estimator
|
||||
[sd_table h_table] = vq_hist(vq_output_fn, dec);
|
||||
|
||||
% load sequence of target vectors we wish to VQ
|
||||
target = load_f32(target_fn, K);
|
||||
|
||||
% limit test to the first nframes vectors
|
||||
if nframes != -1
|
||||
last = nframes;
|
||||
else
|
||||
last = length(target);
|
||||
end
|
||||
target = target(1:dec:last,K_st:K_en);
|
||||
|
||||
% run a test
|
||||
EbNo=10^(EbNodB/10);
|
||||
results = run_test(target, vqsub, sd_table, h_table, ntxcw, nstages, EbNo, verbose);
|
||||
if verbose
|
||||
for f=2:nframes-1
|
||||
printf("f: %03d tx_index: %04d rx_index: %04d\n", f, results.tx_indexes(f), results.rx_indexes(f));
|
||||
end
|
||||
end
|
||||
|
||||
% return full band vq-ed vectors
|
||||
target_ = zeros(last,K);
|
||||
target_(1:dec:last,:) = vq(results.rx_indexes+1,:);
|
||||
|
||||
% use linear interpolation to restore original frame rate
|
||||
for f=1:dec:last-dec
|
||||
prev = f; next = f + dec;
|
||||
for g=prev+1:next-1
|
||||
cnext = (g-prev)/dec; cprev = 1 - cnext;
|
||||
target_(g,:) = cprev*target_(prev,:) + cnext*target_(next,:);
|
||||
%printf("f: %d g: %d cprev: %f cnext: %f\n", f, g, cprev, cnext);
|
||||
end
|
||||
end
|
||||
endfunction
|
||||
|
||||
% Plot histograms of SD at different decimations in time
|
||||
function vq_hist_dec(vq_output_fn)
|
||||
figure(1); clf;
|
||||
[sd_table h_table] = vq_hist(vq_output_fn, dec=1);
|
||||
plot(sd_table, h_table, "b;dec=1;");
|
||||
hold on;
|
||||
[sd_table h_table] = vq_hist(vq_output_fn, dec=2);
|
||||
plot(sd_table, h_table, "r;dec=2;");
|
||||
[sd_table h_table] = vq_hist(vq_output_fn, dec=3);
|
||||
plot(sd_table, h_table, "g;dec=3;");
|
||||
[sd_table h_table] = vq_hist(vq_output_fn, dec=4);
|
||||
plot(sd_table, h_table, "c;dec=4;");
|
||||
hold off;
|
||||
axis([0 300 0 0.5])
|
||||
xlabel("SD dB*dB"); title('Histogram of SD(n,n+1)');
|
||||
endfunction
|
||||
|
||||
% Automated tests for vanilla and fast VQ search functions
|
||||
function test_vq(vq_fn)
|
||||
K=20;
|
||||
vq = load_f32(vq_fn, K);
|
||||
vq_size = 100;
|
||||
target = vq(1:vq_size,:);
|
||||
indexes = vector_quantiser(target,target, verbose=0);
|
||||
assert(indexes == 1:vq_size);
|
||||
printf("Vanilla OK!\n");
|
||||
indexes = vector_quantiser_fast(target,target, verbose=0);
|
||||
assert(indexes == 1:vq_size);
|
||||
printf("Fast OK!\n");
|
||||
endfunction
|
||||
|
||||
% Test trellis decoding a single vector in a sequence of 3
|
||||
function ind = run_test_single(tx_codewords, ntxcw, var, verbose)
|
||||
nstages = 3;
|
||||
nbits = 2;
|
||||
|
||||
rx_codewords = tx_codewords + randn(nstages, nbits)*var;
|
||||
vq = [0 0 0 1;
|
||||
0 0 1 0;
|
||||
0 1 0 0;
|
||||
1 0 0 0];
|
||||
sd_table = [0 1 2 4];
|
||||
h_table = [0.5 0.25 0.15 0.1];
|
||||
C = precompute_C(nbits);
|
||||
ind = find_most_likely_index(rx_codewords, vq, C, sd_table, h_table, nstages, ntxcw, verbose);
|
||||
endfunction
|
||||
|
||||
% Series of single point sanity checks
|
||||
function test_single
|
||||
printf("Single vector decode tests....\n");
|
||||
ind = run_test_single([-1 -1; -1 -1; -1 -1], ntxcw=1, var=0, verbose=0);
|
||||
assert(ind == 0);
|
||||
printf("00 with no noise OK!\n");
|
||||
|
||||
ind = run_test_single([-1 1; 1 1; -1 1], ntxcw=1, var=0, verbose=0);
|
||||
assert(ind == 3);
|
||||
printf("11 with no noise OK!\n");
|
||||
|
||||
ind = run_test_single([-1 -1; -1 1; -1 -1], ntxcw=4, var=1, verbose=0);
|
||||
assert(ind == 1);
|
||||
printf("01 with noise OK!\n");
|
||||
endfunction
|
||||
|
||||
% BPSK simulation to check noise injection
|
||||
function test_bpsk_ber
|
||||
nbits = 12;
|
||||
frames = 10000;
|
||||
tx_codewords = zeros(frames,nbits);
|
||||
tx_bits = zeros(frames,nbits);
|
||||
for f=1:frames
|
||||
tx_codewords(f,:) = dec2sd(f, nbits);
|
||||
tx_bits(f,:) = tx_codewords(f,:) > 0;
|
||||
end
|
||||
|
||||
EbNodB = 5;
|
||||
EbNo = 10^(EbNodB/10);
|
||||
rx_codewords = tx_codewords + randn(frames, nbits)*sqrt(1/(2*EbNo));
|
||||
rx_bits = rx_codewords > 0;
|
||||
nerrors = sum(xor(tx_bits, rx_bits)(:));
|
||||
tbits = frames*nbits;
|
||||
printf("EbNo: %4.2f dB tbits: %d errs: %d BER: %4.3f %4.3f\n", EbNodB, tbits, nerrors, nerrors/tbits, 0.5*erfc(sqrt(EbNo)));
|
||||
endfunction
|
||||
|
||||
% generate sets of curves
|
||||
function [EbNodB rms_sd] = run_curves(frames=100, dec=1, nstages=5)
|
||||
results_log = [];
|
||||
EbNodB = [0 1 2 3 4 5];
|
||||
target_fn = "../build_linux/all_speech_8k_lim.f32";
|
||||
|
||||
for i=1:length(EbNodB)
|
||||
results = test_trellis(target_fn, frames, dec, ntxcw=8, nstages, EbNodB(i), verbose=0);
|
||||
results_log = [results_log results];
|
||||
end
|
||||
for i=1:length(results_log)
|
||||
ber(i) = results_log(i).ber;
|
||||
ber_vanilla(i) = results_log(i).ber_vanilla;
|
||||
per(i) = results_log(i).per;
|
||||
per_vanilla(i) = results_log(i).per_vanilla;
|
||||
rms_sd_noerrors(i) = sqrt(results_log(i).mse_noerrors);
|
||||
rms_sd(i) = sqrt(results_log(i).mse);
|
||||
rms_sd_vanilla(i) = sqrt(results_log(i).mse_vanilla);
|
||||
end
|
||||
|
||||
figure(1); clf; semilogy(EbNodB, ber_vanilla, "r+-;uncoded;"); hold on;
|
||||
semilogy(EbNodB, ber, "g+-;trellis;"); hold off;
|
||||
grid('minor'); title(sprintf("BER dec=%d nstages=%d",dec,nstages));
|
||||
print("-dpng", sprintf("trellis_dec_%d_ber.png",dec));
|
||||
|
||||
figure(2); clf; semilogy(EbNodB, per_vanilla, "r+-;uncoded;"); hold on;
|
||||
semilogy(EbNodB, per, "g+-;trellis;");
|
||||
grid('minor'); title(sprintf("PER dec=%d nstages=%d",dec,nstages));
|
||||
print("-dpng", sprintf("trellis_dec_%d_per.png",dec));
|
||||
|
||||
figure(3); clf; plot(EbNodB, rms_sd_noerrors, "b+-;no errors;"); hold on;
|
||||
plot(EbNodB, rms_sd_vanilla, "r+-;uncoded;");
|
||||
plot(EbNodB, rms_sd, "g+-;trellis;"); hold off;
|
||||
grid('minor'); title(sprintf("RMS SD dec=%d nstages=%d",dec,nstages));
|
||||
print("-dpng", sprintf("trellis_dec_%d_rms_sd.png",dec));
|
||||
endfunction
|
||||
|
||||
function vq_file(vq_fn, dec, EbNodB, in_fn, out_fn)
|
||||
[results target_] = test_trellis(in_fn, nframes=-1, dec, ntxcw=8, nstages=3, EbNodB, verbose=0);
|
||||
save_f32(out_fn, target_);
|
||||
endfunction
|
||||
|
||||
% -------------------------------------------------------------------
|
||||
|
||||
more off;
|
||||
randn('state',1);
|
||||
|
||||
% uncomment one of the below to run a test or simulation
|
||||
|
||||
% These two tests show where we are at:
|
||||
%test_trellis(target_fn, nframes=600, dec=1, ntxcw=8, nstages=3, EbNodB=3, verbose=0);
|
||||
%test_trellis(target_fn, nframes=600, dec=4, ntxcw=8, nstages=3, EbNodB=3, verbose=0);
|
||||
|
||||
%run_curves(600,1)
|
||||
%run_curves(600,2)
|
||||
%run_curves(600,4)
|
||||
%[EbNodB rms_sd] = run_curves(30*100,3,3)
|
||||
|
||||
%test_trellis(target_fn, nframes=200, dec=1, ntxcw=1, nstages=3, EbNodB=3, verbose=0);
|
||||
%test_trellis(target_fn, nframes=100, dec=2, ntxcw=8, nstages=3, EbNodB=3, verbose=0);
|
||||
%test_vq("../build_linux/vq_stage1.f32");
|
||||
%vq_hist_dec("../build_linux/all_speech_8k_test.f32");
|
||||
%test_single
|
||||
%test_bpsk_ber
|
||||
|
|
@ -1,366 +0,0 @@
|
|||
% vq_700c.m
|
||||
% David Rowe May 2019
|
||||
%
|
||||
% Researching Codec 2 700C VQ equaliser ideas
|
||||
% See also scripts/train_700c_quant.sh, tnewamp1.m
|
||||
|
||||
melvq;
|
||||
newamp_700c;
|
||||
|
||||
% general purpose plot function for looking at averages of K-band
|
||||
% sequences in scripts dir and VQs:
|
||||
% vq_700c_plots({"hts2a.f32" "vk5qi.f32" "train_120_1.txt"})
|
||||
|
||||
function vq_700c_plots(fn_array)
|
||||
K = 20; rate_K_sample_freqs_kHz = mel_sample_freqs_kHz(K);
|
||||
freq_Hz = rate_K_sample_freqs_kHz * 1000;
|
||||
|
||||
figure(1); clf; hold on; axis([200 4000 40 90]); title('Max Hold');
|
||||
figure(2); clf; hold on; axis([200 4000 0 40]); title('Average');
|
||||
|
||||
for i=1:length(fn_array)
|
||||
[dir name ext] = fileparts(fn_array{i});
|
||||
if strcmp(ext, ".f32")
|
||||
% f32 feature file
|
||||
fn = sprintf("../build_linux/%s%s", name, ext)
|
||||
bands = load_f32(fn , K);
|
||||
else
|
||||
% text file (e.g. existing VQ)
|
||||
bands = load(fn_array{i});
|
||||
end
|
||||
% for max hold: break into segments of Nsec, find max, average maximums
|
||||
% this avoids very rare global peaks setting the max
|
||||
Nsec = 10; Tframe = 0.01; frames_per_seg = Nsec/Tframe
|
||||
Nsegs = floor(length(bands)/frames_per_seg)
|
||||
max_holds = zeros(Nsegs, K);
|
||||
if Nsegs == 0
|
||||
max_holds = max(bands)
|
||||
else
|
||||
for s=1:Nsegs
|
||||
st = (s-1)*frames_per_seg+1; en = st + frames_per_seg - 1;
|
||||
max_holds(s,:) = max(bands(st:en,:));
|
||||
end
|
||||
max_holds = mean(max_holds);
|
||||
end
|
||||
figure(1); plot(freq_Hz, max_holds, '+-', 'linewidth', 2);
|
||||
figure(2); plot(freq_Hz, mean(bands), '+-', 'linewidth', 2);
|
||||
end
|
||||
figure(1); legend(fn_array); grid; xlabel('Freq (Hz)'); ylabel('Amp dB');
|
||||
figure(2); legend(fn_array); grid; xlabel('Freq (Hz)'); ylabel('Amp dB');
|
||||
endfunction
|
||||
|
||||
|
||||
% limit mean of each vector to between lower_lim and upper_lim
|
||||
function vout = limit_vec(vin, lower_lim, upper_lim)
|
||||
m = mean(vin');
|
||||
vout = zeros(size(vin));
|
||||
for i=1:length(vin)
|
||||
vec_no_mean = vin(i,:) - m(i);
|
||||
if m(i) < lower_lim
|
||||
m(i) = lower_lim;
|
||||
end
|
||||
if m(i) > upper_lim
|
||||
m(i) = upper_lim;
|
||||
end
|
||||
vout(i,:) = vec_no_mean + m(i);
|
||||
end
|
||||
endfunction
|
||||
|
||||
|
||||
% single stage vq a target matrix
|
||||
function errors = vq_targets(vq, targets)
|
||||
errors = [];
|
||||
for i=1:length(targets)
|
||||
[mse_list index_list] = search_vq(vq, targets(i,:), 1);
|
||||
error = targets(i,:) - vq(index_list(1),:);
|
||||
errors = [errors; error];
|
||||
end
|
||||
endfunction
|
||||
|
||||
|
||||
% single stage vq a target matrix with adaptive EQ, this didn't work
|
||||
|
||||
function [errors eqs] = vq_targets_adap_eq(vq, targets, eqs)
|
||||
errors = []; gain=0.02;
|
||||
eq = eqs(end,:);
|
||||
for i=1:length(targets)
|
||||
t = targets(i,:) - eq;
|
||||
mean(t)
|
||||
%t -= mean(t);
|
||||
[mse_list index_list] = search_vq(vq, t, 1);
|
||||
error = t - vq(index_list(1),:);
|
||||
eq = (1-gain)*eq + gain*error;
|
||||
errors = [errors; error]; eqs = [eqs; eq];
|
||||
end
|
||||
endfunction
|
||||
|
||||
|
||||
% single stage vq a target matrix with block adaptive EQ, this works
|
||||
% well with nblock == 10
|
||||
|
||||
function [errors eq] = vq_targets_block_eq(vq, targets, eq, nblock)
|
||||
errors = []; n = 0; [tmp K] = size(vq); error_eq = zeros(1,K); gain=0.20;
|
||||
for i=1:length(targets)
|
||||
t = targets(i,:) - eq;
|
||||
[mse_list index_list] = search_vq(vq, t, 1);
|
||||
error = t - vq(index_list(1),:);
|
||||
error_eq += error;
|
||||
errors = [errors; error];
|
||||
n++;
|
||||
if n == nblock
|
||||
eq = 0.99*eq + gain*error_eq/nblock;
|
||||
n = 0; error_eq = zeros(1,K);
|
||||
end
|
||||
end
|
||||
endfunction
|
||||
|
||||
|
||||
% two stage mbest VQ a target matrix
|
||||
|
||||
function [errors targets_] = vq_targets2(vq1, vq2, targets)
|
||||
vqset(:,:,1)= vq1; vqset(:,:,2)=vq2; m=5;
|
||||
[errors targets_] = mbest(vqset, targets, m);
|
||||
endfunction
|
||||
|
||||
|
||||
% two stage mbest VQ a target matrix, with adap_eq
|
||||
|
||||
function [errors targets_ eq] = vq_targets2_adap_eq(vq1, vq2, targets, eq)
|
||||
vqset(:,:,1)= vq1; vqset(:,:,2)=vq2; m=5; gain=0.02;
|
||||
errors = []; targets_ = [];
|
||||
for i=1:length(targets)
|
||||
t = targets(i,:)-eq;
|
||||
t -= mean(t')';
|
||||
[error target_ indexes] = mbest(vqset, t, m);
|
||||
% use first stage VQ as error driving adaptive EQ
|
||||
eq_error = t - vq1(indexes(1),:);
|
||||
eq = (1-gain)*eq + gain*eq_error;
|
||||
errors = [errors; error]; targets_ = [targets_; target_];
|
||||
end
|
||||
endfunction
|
||||
|
||||
|
||||
% Given target and vq matrices, estimate eq via two metrics. First
|
||||
% metric seems to work best. Both uses first stage VQ error for EQ
|
||||
|
||||
function [eq1 eq2] = est_eq(vq, targets)
|
||||
[ntargets K] = size(targets);
|
||||
[nvq K] = size(vq);
|
||||
|
||||
eq1 = zeros(1,K); eq2 = zeros(1,K);
|
||||
for i=1:length(targets)
|
||||
[mse_list index_list] = search_vq(vq, targets(i,:), 1);
|
||||
|
||||
% eq metric 1: average of error for best VQ entry
|
||||
eq1 += targets(i,:) - vq(index_list(1),:);
|
||||
|
||||
% eq metric 2: average of error across all VQ entries
|
||||
for j=1:nvq
|
||||
eq2 += targets(i,:) - vq(j,:);
|
||||
end
|
||||
end
|
||||
|
||||
eq1 /= ntargets;
|
||||
eq2 /= (ntargets*nvq);
|
||||
endfunction
|
||||
|
||||
function [targets e] = load_targets(fn_target_f32)
|
||||
nb_features = 41;
|
||||
K = 20;
|
||||
|
||||
% .f32 files are in scripts directory, first K values rate_K_no_mean vectors
|
||||
[dir name ext] = fileparts(fn_target_f32);
|
||||
fn = sprintf("../script/%s_feat.f32", name);
|
||||
feat = load_f32(fn, nb_features);
|
||||
e = feat(:,1);
|
||||
targets = feat(:,2:K+1);
|
||||
endfunction
|
||||
|
||||
% rather simple EQ in front of VQ
|
||||
|
||||
function [eqs ideal] = est_eq_front(targets)
|
||||
[tmp K] = size(targets);
|
||||
ideal = [ 8 10 12 14 14*ones(1,K-1-4) -20];
|
||||
eq = zeros(1,K); gain = 0.02;
|
||||
eqs = [];
|
||||
for i=1:length(targets)
|
||||
update = targets(i,:) - ideal;
|
||||
eq = (1-gain)*eq + gain*update;
|
||||
eq(find(eq < 0)) = 0;
|
||||
eqs = [eqs; eq];
|
||||
end
|
||||
endfunction
|
||||
|
||||
function table_across_samples
|
||||
K = 20;
|
||||
|
||||
% VQ is in .txt file in this directory, we have two to choose from. train_120 is the Codec 2 700C VQ,
|
||||
% train_all_speech was trained up from a different, longer database, as a later exercise
|
||||
vq_name = "train_120";
|
||||
#vq_name = "train_all_speech";
|
||||
vq1 = load(sprintf("%s_1.txt", vq_name));
|
||||
vq2 = load(sprintf("%s_2.txt", vq_name));
|
||||
|
||||
printf("----------------------------------------------------------------------------------\n");
|
||||
printf("Sample Initial vq1 vq1_eq2 vq1_eq2 vq2 vq2_eq1 vq2_eq2 \n");
|
||||
printf("----------------------------------------------------------------------------------\n");
|
||||
|
||||
fn_targets = { "cq_freedv_8k_lfboost" "cq_freedv_8k_hfcut" "cq_freedv_8k" "hts1a" "hts2a" "cq_ref" "ve9qrp_10s" "vk5qi" "c01_01_8k" "ma01_01"};
|
||||
#fn_targets = {"cq_freedv_8k_lfboost"};
|
||||
figs=1;
|
||||
for i=1:length(fn_targets)
|
||||
|
||||
% load target and estimate eq
|
||||
[targets e] = load_targets(fn_targets{i});
|
||||
eq1 = est_eq(vq1, targets);
|
||||
eq2s = est_eq_front(targets);
|
||||
% for these simulation uses fixed EQ sample, rather than letting it vary frame by frame
|
||||
eq2 = eq2s(end,:);
|
||||
|
||||
% first stage VQ -----------------
|
||||
|
||||
errors1 = vq_targets(vq1, targets);
|
||||
errors1_eq1 = vq_targets(vq1, targets-eq1);
|
||||
errors1_eq2 = vq_targets(vq1, targets-eq2);
|
||||
|
||||
% two stage mbest VQ --------------
|
||||
|
||||
[errors2 targets_] = vq_targets2(vq1, vq2, targets);
|
||||
[errors2_eq1 targets_eq1_] = vq_targets2(vq1, vq2, targets-eq1);
|
||||
[errors2_eq2 targets_eq2_] = vq_targets2(vq1, vq2, targets-eq2);
|
||||
|
||||
% save to .f32 files for listening tests
|
||||
if strcmp(vq_name,"train_120")
|
||||
save_f32(sprintf("../script/%s_vq2.f32", fn_targets{i}), targets_);
|
||||
save_f32(sprintf("../script/%s_vq2_eq1.f32", fn_targets{i}), targets_eq1_);
|
||||
save_f32(sprintf("../script/%s_vq2_eq2.f32", fn_targets{i}), targets_eq2_);
|
||||
else
|
||||
save_f32(sprintf("../script/%s_vq2_as.f32", fn_targets{i}), targets_);
|
||||
save_f32(sprintf("../script/%s_vq2_as_eq.f32", fn_targets{i}), targets_eq_);
|
||||
end
|
||||
printf("%-21s %6.2f %6.2f %6.2f %6.2f %6.2f %6.2f %6.2f\n", fn_targets{i},
|
||||
var(targets(:)), var(errors1(:)), var(errors1_eq1(:)), var(errors1_eq2(:)),
|
||||
var(errors2(:)), var(errors2_eq1(:)), var(errors2_eq2(:)));
|
||||
|
||||
figure(figs++); clf;
|
||||
%plot(var(errors2'),'b;vq2;'); hold on; plot(var(errors2_eq1'),'g;vq2_eq1;'); plot(var(errors2_eq2'),'r;vq2_eq2;'); hold off;
|
||||
plot(mean(targets),'g;mean(targets);'); hold on; plot(mean(vq1),'g;mean(vq1);'); plot(eq2,'r;eq2;'); hold off;
|
||||
title(fn_targets{i}); axis([1 K -20 30]);
|
||||
end
|
||||
endfunction
|
||||
|
||||
|
||||
% interactve, menu driven frame by frame plots
|
||||
|
||||
function interactive(fn_vq_txt, fn_target_f32)
|
||||
K = 20;
|
||||
vq = load("train_120_1.txt");
|
||||
[targets e] = load_targets(fn_target_f32);
|
||||
eq1 = est_eq(vq, targets);
|
||||
|
||||
[errors1_eq2 eqs2] = vq_targets_adap_eq(vq, targets, zeros(1,K));
|
||||
[errors1_eq2 eqs2] = vq_targets_adap_eq(vq, targets, eqs2(end,:));
|
||||
eq2 = eqs2(end,:);
|
||||
|
||||
figure(1); clf;
|
||||
mesh(e+targets)
|
||||
figure(2); clf;
|
||||
plot(eq1,'b;eq1;')
|
||||
hold on;
|
||||
plot(mean(targets),'c;mean(targets);'); plot(eq2,'g;eq2;');
|
||||
hold off;
|
||||
figure(3); clf; mesh(eqs2); title('eq2 evolving')
|
||||
|
||||
% enter single step loop
|
||||
f = 20; neq = 0; eq=zeros(1,K);
|
||||
do
|
||||
figure(4); clf;
|
||||
t = targets(f,:) - eq;
|
||||
[mse_list index_list] = search_vq(vq, t, 1);
|
||||
error = t - vq(index_list(1),:);
|
||||
plot(e(f)+t,'b;target;');
|
||||
hold on;
|
||||
plot(e(f)+vq(index_list,:),'g;vq;');
|
||||
plot(error,'r;error;');
|
||||
plot(eq,'c;eq;');
|
||||
plot([1 K],[e(f) e(f)],'--')
|
||||
hold off;
|
||||
axis([1 K -20 80])
|
||||
% interactive menu
|
||||
|
||||
printf("\r f: %2d eq: %d ind: %3d var: %3.1f menu: n-next b-back e-eq q-quit", f, neq, index_list(1), var(error));
|
||||
fflush(stdout);
|
||||
k = kbhit();
|
||||
|
||||
if k == 'n' f+=1; end
|
||||
if k == 'e'
|
||||
neq++;
|
||||
end
|
||||
if neq == 3 neq = 0; end
|
||||
if neq == 0 eq = zeros(1,K); end
|
||||
if neq == 1 eq = eq1; end
|
||||
if neq == 2 eq = eqs2(f,:); end
|
||||
if k == 'b' f-=1; end
|
||||
until (k == 'q')
|
||||
printf("\n");
|
||||
endfunction
|
||||
|
||||
|
||||
% Experiment to test iterative approach of block update and remove
|
||||
% mean (ie frame energy), shows some promise at reducing HF energy
|
||||
% over several iterations while not affecting already good samples
|
||||
|
||||
function experiment_iterate_block(fn_vq_txt, fn_target_f32)
|
||||
K = 20;
|
||||
vq = load("train_120_1.txt");
|
||||
[targets e] = load_targets(fn_target_f32);
|
||||
|
||||
figure(1); clf;
|
||||
plot(mean(targets),'b;mean(targets);');
|
||||
hold on;
|
||||
plot(mean(vq), 'g;mean(vq);');
|
||||
figure(2); clf; hold on;
|
||||
eq = zeros(1,K);
|
||||
for i=1:3
|
||||
[errors eq] = vq_targets_block_eq(vq, targets, eq, 10);
|
||||
figure(1); plot(mean(targets-eq));
|
||||
figure(2); plot(eq);
|
||||
printf("i: %d %6.2f\n", i, var(errors(:)))
|
||||
end
|
||||
endfunction
|
||||
|
||||
% Experiment to test EQ of input (before) VQ. We set a threshold on
|
||||
% when to equalise, so we don't upset already flat-ish samples. This
|
||||
% is the algorithm used for C at the time of writing (newamp1.c, newamp_700c.m)
|
||||
|
||||
function experiment_front_eq(fn_vq_txt, fn_target_f32)
|
||||
K = 20;
|
||||
vq = load("train_120_1.txt");
|
||||
[targets e] = load_targets(fn_target_f32);
|
||||
|
||||
[eqs ideal] = est_eq_front(targets);
|
||||
|
||||
figure(1); clf;
|
||||
plot(mean(targets),'b;mean(targets);');
|
||||
hold on;
|
||||
plot(ideal, 'g;ideal;');
|
||||
plot(eqs(end,:), 'r;eq;');
|
||||
plot(mean(targets)-eqs(end,:), 'c;equalised;');
|
||||
plot(mean(vq),'b--;mean(vq);');
|
||||
hold off;
|
||||
figure(2); clf; mesh(eqs(1:100,:)); title('EQ weights over time');
|
||||
ylabel('Time (frames'); xlabel('Freq (mel)');
|
||||
endfunction
|
||||
|
||||
more off
|
||||
|
||||
% choose one of these to run first
|
||||
% You'll need to run scripts/train_700C_quant.sh first to generate the .f32 files
|
||||
|
||||
%interactive("train_120_1.txt", "cq_freedv_8k_lfboost.f32")
|
||||
%table_across_samples;
|
||||
%vq_700c_plots({"all_speech_8k.f32" "all_speech_8k_hp300.f32" "dev-clean-8k.f32" "train_8k.f32" } )
|
||||
%vq_700c_plots({"ve9qrp_10s.f32" "cq_freedv_8k_lfboost.f32" "cq_ref.f32" "hts1a.f32" "vk5qi.f32"})
|
||||
%experiment_iterate_block("train_120_1.txt", "ve9qrp_10s.f32")
|
||||
%experiment_iterate_block("train_120_1.txt", "cq_freedv_8k_lfboost.f32")
|
||||
%experiment_front_eq("train_120_1.txt", "cq_freedv_8k_lfboost.f32")
|
||||
|
|
@ -1,349 +0,0 @@
|
|||
% vq_compare.m
|
||||
% David Rowe Sep 2021
|
||||
%
|
||||
% Compare the Eb/No performance of Vector Quantisers (robustness to bit errors) using
|
||||
% Spectral Distortion (SD) measure.
|
||||
|
||||
#{
|
||||
usage:
|
||||
|
||||
1. Generate the initial VQ (vq_stage1.f32) and input test vector file (all_speech_8k_lim.f32):
|
||||
|
||||
cd codec2/build_linux
|
||||
../script/train_trellis.sh
|
||||
|
||||
2. Run the Psuedo-Gray binary switch tool to optimise the VQ against single bit errors:
|
||||
|
||||
./misc/vq_binary_switch -d 20 vq_stage1.f32 vq_stage1_bs001.f32 -m 5000 --st 2 --en 16 -f
|
||||
|
||||
This can take a while, but if you ctrl-C at any time it will have saved the most recent optimised VQ.
|
||||
|
||||
3. Run this script to compare the two VQs:
|
||||
|
||||
octave:34> vq_compare
|
||||
#}
|
||||
|
||||
|
||||
function vq_compare(action="run_curves", vq_fn, dec=1, EbNodB=3, in_fn, out_fn)
|
||||
more off;
|
||||
randn('state',1);
|
||||
graphics_toolkit("gnuplot");
|
||||
|
||||
if strcmp(action, "run_curves")
|
||||
run_curves(30*100);
|
||||
end
|
||||
if strcmp(action, "vq_file")
|
||||
vq_file(vq_fn, dec, EbNodB, in_fn, out_fn)
|
||||
end
|
||||
endfunction
|
||||
|
||||
|
||||
% -------------------------------------------------------------------
|
||||
|
||||
% converts a decimal value to a soft dec binary value
|
||||
function c = dec2sd(dec, nbits)
|
||||
|
||||
% convert to binary
|
||||
|
||||
c = zeros(1,nbits);
|
||||
for j=0:nbits-1
|
||||
mask = 2.^j;
|
||||
if bitand(dec,mask)
|
||||
c(nbits-j) = 1;
|
||||
end
|
||||
end
|
||||
|
||||
% map to +/- 1
|
||||
|
||||
c = -1 + 2*c;
|
||||
endfunction
|
||||
|
||||
% fast version of vector quantiser
|
||||
function [indexes target_] = vector_quantiser_fast(vq, target, verbose=1)
|
||||
[vq_size K] = size(vq);
|
||||
[ntarget tmp] = size(target);
|
||||
target_ = zeros(ntarget,K);
|
||||
indexes = zeros(1,ntarget);
|
||||
|
||||
% pre-compute energy of each VQ vector
|
||||
vqsq = zeros(vq_size,1);
|
||||
for i=1:vq_size
|
||||
vqsq(i) = vq(i,:)*vq(i,:)';
|
||||
end
|
||||
|
||||
% use efficient matrix multiplies to search for best match to target
|
||||
for i=1:ntarget
|
||||
best_e = 1E32;
|
||||
e = vqsq - 2*(vq * target(i,:)');
|
||||
[best_e best_ind] = min(e);
|
||||
if verbose printf("best_e: %f best_ind: %d\n", best_e, best_ind), end;
|
||||
target_(i,:) = vq(best_ind,:); indexes(i) = best_ind;
|
||||
end
|
||||
endfunction
|
||||
|
||||
|
||||
% VQ a target sequence of frames then run a test using vanilla uncoded/trellis decoder
|
||||
function results = run_test(target, vq, EbNo, verbose)
|
||||
[frames tmp] = size(target);
|
||||
[vq_length tmp] = size(vq);
|
||||
nbits = log2(vq_length);
|
||||
nerrors = 0;
|
||||
tbits = 0;
|
||||
nframes = 0;
|
||||
nper = 0;
|
||||
|
||||
% Vector Quantise target vectors sequence
|
||||
[tx_indexes target_ ] = vector_quantiser_fast(vq, target, verbose);
|
||||
% use convention of indexes starting from 0
|
||||
tx_indexes -= 1;
|
||||
% mean SD of VQ with no errors
|
||||
diff = target - target_;
|
||||
mse_noerrors = mean(diff(:).^2);
|
||||
|
||||
% construct tx symbol codewords from VQ indexes
|
||||
tx_codewords = zeros(frames, nbits);
|
||||
for f=1:frames
|
||||
tx_codewords(f,:) = dec2sd(tx_indexes(f), nbits);
|
||||
end
|
||||
|
||||
rx_codewords = tx_codewords + randn(frames, nbits)*sqrt(1/(2*EbNo));
|
||||
rx_indexes = zeros(1,frames);
|
||||
|
||||
for f=1:frames
|
||||
tx_bits = tx_codewords(f,:) > 0;
|
||||
rx_bits = rx_codewords(f,:) > 0;
|
||||
rx_indexes(f) = sum(rx_bits .* 2.^(nbits-1:-1:0));
|
||||
errors = sum(xor(tx_bits, rx_bits));
|
||||
nerrors += errors;
|
||||
if errors nper++;, end
|
||||
tbits += nbits;
|
||||
nframes++;
|
||||
end
|
||||
|
||||
EbNodB = 10*log10(EbNo);
|
||||
target_ = vq(rx_indexes+1,:);
|
||||
diff = target - target_;
|
||||
mse = mean(diff(:).^2);
|
||||
printf("Eb/No: %3.2f dB nframes: %3d nerrors: %4d BER: %4.3f PER: %3.2f mse: %3.2f %3.2f\n",
|
||||
EbNodB, nframes, nerrors, nerrors/tbits, nper/nframes, mse_noerrors, mse);
|
||||
results.ber = nerrors/tbits;
|
||||
results.per = nper/nframes;
|
||||
results.mse_noerrors = mse_noerrors;
|
||||
results.mse = mse;
|
||||
results.tx_indexes = tx_indexes;
|
||||
results.rx_indexes = rx_indexes;
|
||||
endfunction
|
||||
|
||||
% VQ a target sequence of frames then run a test using a LDPC code
|
||||
function results = run_test_ldpc(target, vq, EbNo, verbose)
|
||||
[frames tmp] = size(target);
|
||||
[vq_length tmp] = size(vq);
|
||||
nbits = log2(vq_length);
|
||||
nerrors = 0;
|
||||
tbits = 0;
|
||||
nframes = 0;
|
||||
nper = 0;
|
||||
|
||||
% init LDPC code
|
||||
mod_order = 4; bps = 2;
|
||||
modulation = 'QPSK';
|
||||
mapping = 'gray';
|
||||
max_iterations = 100; demod_type = 0; decoder_type = 0;
|
||||
ldpc; init_cml();
|
||||
tempStruct = load("HRA_56_56.txt");
|
||||
b = fieldnames(tempStruct);
|
||||
ldpcArrayName = b{1,1};
|
||||
% extract the array from the struct
|
||||
HRA = tempStruct.(ldpcArrayName);
|
||||
[code_param framesize rate] = ldpc_init_user(HRA, modulation, mod_order, mapping);
|
||||
|
||||
% set up noise
|
||||
EbNodB = 10*log10(EbNo);
|
||||
EsNodB = EbNodB + 10*log10(rate) + 10*log10(bps);
|
||||
EsNo = 10^(EsNodB/10);
|
||||
variance = 1/EsNo;
|
||||
|
||||
% Vector Quantise target vectors sequence
|
||||
[tx_indexes target_ ] = vector_quantiser_fast(vq, target, verbose);
|
||||
% use convention of indexes starting from 0
|
||||
tx_indexes -= 1;
|
||||
% mean SD of VQ with no errors
|
||||
diff = target - target_;
|
||||
mse_noerrors = mean(diff(:).^2);
|
||||
|
||||
% construct tx frames x nbit matrix using VQ indexes
|
||||
tx_bits = zeros(frames, nbits);
|
||||
for f=1:frames
|
||||
tx_bits(f,:) = dec2sd(tx_indexes(f), nbits) > 0;
|
||||
end
|
||||
|
||||
% find a superframe size, that has an integer number of nbits and data_bits_per_frame frames
|
||||
bits_per_superframe = nbits;
|
||||
while mod(bits_per_superframe,nbits) || mod(bits_per_superframe,code_param.data_bits_per_frame)
|
||||
bits_per_superframe += nbits;
|
||||
end
|
||||
|
||||
Nsuperframes = floor(frames*nbits/bits_per_superframe);
|
||||
Nldpc_codewords = Nsuperframes*bits_per_superframe/code_param.data_bits_per_frame;
|
||||
frames = Nsuperframes*bits_per_superframe/nbits;
|
||||
%printf("bits_per_superframe: %d Nldpc_codewords: %d frames: %d\n", bits_per_superframe, Nldpc_codewords, frames);
|
||||
|
||||
% reshape tx_bits matrix into Nldpc_codewords x data_bits_per_frame
|
||||
tx_bits = tx_bits(1:frames,:);
|
||||
tx_bits_ldpc = reshape(tx_bits',code_param.data_bits_per_frame, Nldpc_codewords)';
|
||||
|
||||
% modulate tx symbols
|
||||
tx_symbols = [];
|
||||
for nn=1:Nldpc_codewords
|
||||
[tx_codeword atx_symbols] = ldpc_enc(tx_bits_ldpc(nn,:), code_param);
|
||||
tx_symbols = [tx_symbols atx_symbols];
|
||||
end
|
||||
|
||||
noise = sqrt(variance*0.5)*(randn(1,length(tx_symbols)) + j*randn(1,length(tx_symbols)));
|
||||
rx_symbols = tx_symbols+noise;
|
||||
|
||||
% LDPC decode
|
||||
for nn = 1:Nldpc_codewords
|
||||
st = (nn-1)*code_param.coded_syms_per_frame + 1;
|
||||
en = (nn)*code_param.coded_syms_per_frame;
|
||||
|
||||
arx_codeword = ldpc_dec(code_param, max_iterations, demod_type, decoder_type, rx_symbols(st:en), EsNo, ones(1,code_param.coded_syms_per_frame));
|
||||
rx_bits_ldpc(nn,:) = arx_codeword(1:code_param.data_bits_per_frame);
|
||||
end
|
||||
|
||||
% reshape rx_bits_ldpc matrix into frames x nbits
|
||||
rx_bits = reshape(rx_bits_ldpc',nbits,frames)';
|
||||
|
||||
rx_indexes = tx_indexes;
|
||||
for f=1:frames
|
||||
rx_indexes(f) = sum(rx_bits(f,:) .* 2.^(nbits-1:-1:0));
|
||||
errors = sum(xor(tx_bits(f,:), rx_bits(f,:)));
|
||||
nerrors += errors;
|
||||
if errors nper++;, end
|
||||
tbits += nbits;
|
||||
nframes++;
|
||||
end
|
||||
|
||||
EbNodB = 10*log10(EbNo);
|
||||
target_ = vq(rx_indexes+1,:);
|
||||
diff = target - target_;
|
||||
mse = mean(diff(:).^2);
|
||||
printf("Eb/No: %3.2f dB nframes: %4d nerrors: %4d BER: %4.3f PER: %3.2f mse: %3.2f %3.2f\n",
|
||||
EbNodB, nframes, nerrors, nerrors/tbits, nper/nframes, mse_noerrors, mse);
|
||||
results.ber = nerrors/tbits;
|
||||
results.per = nper/nframes;
|
||||
results.mse = mse;
|
||||
results.tx_indexes = tx_indexes;
|
||||
results.rx_indexes = rx_indexes;
|
||||
endfunction
|
||||
|
||||
% Simulations ---------------------------------------------------------------------
|
||||
|
||||
% top level function to set up and run a test with a specific vq
|
||||
function [results target_] = run_test_vq(vq_fn, target_fn, nframes=100, dec=1, EbNodB=3, ldpc_en=0, verbose=0)
|
||||
K = 20; K_st=2+1; K_en=16+1;
|
||||
|
||||
% load VQ
|
||||
vq = load_f32(vq_fn, K);
|
||||
[vq_size tmp] = size(vq);
|
||||
vqsub = vq(:,K_st:K_en);
|
||||
|
||||
% load sequence of target vectors we wish to VQ
|
||||
target = load_f32(target_fn, K);
|
||||
|
||||
% limit test to the first nframes vectors
|
||||
if nframes != -1
|
||||
last = nframes;
|
||||
else
|
||||
last = length(target);
|
||||
end
|
||||
target = target(1:dec:last, K_st:K_en);
|
||||
|
||||
% run a test
|
||||
EbNo=10^(EbNodB/10);
|
||||
if ldpc_en
|
||||
results = run_test_ldpc(target, vqsub, EbNo, verbose);
|
||||
else
|
||||
results = run_test(target, vqsub, EbNo, verbose);
|
||||
end
|
||||
if verbose
|
||||
for f=2:nframes-1
|
||||
printf("f: %03d tx_index: %04d rx_index: %04d\n", f, results.tx_indexes(f), results.rx_indexes(f));
|
||||
end
|
||||
end
|
||||
|
||||
% return full band vq-ed vectors
|
||||
target_ = zeros(last,K);
|
||||
target_(1:dec:last,:) = vq(results.rx_indexes+1,:);
|
||||
|
||||
% use linear interpolation to restore original frame rate
|
||||
for f=1:dec:last-dec
|
||||
prev = f; next = f + dec;
|
||||
for g=prev+1:next-1
|
||||
cnext = (g-prev)/dec; cprev = 1 - cnext;
|
||||
target_(g,:) = cprev*target_(prev,:) + cnext*target_(next,:);
|
||||
%printf("f: %d g: %d cprev: %f cnext: %f\n", f, g, cprev, cnext);
|
||||
end
|
||||
end
|
||||
endfunction
|
||||
|
||||
% generate sets of curves
|
||||
function run_curves(frames=100, dec=1)
|
||||
target_fn = "../build_linux/all_speech_8k_lim.f32";
|
||||
EbNodB = 0:5;
|
||||
|
||||
results1_ldpc_log = [];
|
||||
for i=1:length(EbNodB)
|
||||
results = run_test_vq("../build_linux/vq_stage1.f32", target_fn, frames, dec, EbNodB(i), ldpc_en=1, verbose=0);
|
||||
results1_ldpc_log = [results1_ldpc_log results];
|
||||
end
|
||||
results4_ldpc_log = [];
|
||||
for i=1:length(EbNodB)
|
||||
results = run_test_vq("../build_linux/vq_stage1_bs004.f32", target_fn, frames, dec, EbNodB(i), ldpc_en=1, verbose=0);
|
||||
results4_ldpc_log = [results4_ldpc_log results];
|
||||
end
|
||||
|
||||
results1_log = [];
|
||||
for i=1:length(EbNodB)
|
||||
results = run_test_vq("../build_linux/vq_stage1.f32", target_fn, frames, dec, EbNodB(i), ldpc_en=0, verbose=0);
|
||||
results1_log = [results1_log results];
|
||||
end
|
||||
results4_log = [];
|
||||
for i=1:length(EbNodB)
|
||||
results = run_test_vq("../build_linux/vq_stage1_bs004.f32", target_fn, frames, dec, EbNodB(i), ldpc_en=0, verbose=0);
|
||||
results4_log = [results4_log results];
|
||||
end
|
||||
for i=1:length(results1_log)
|
||||
ber(i) = results1_log(i).ber;
|
||||
per(i) = results1_log(i).per;
|
||||
mse_noerrors(i) = sqrt(results1_log(i).mse_noerrors);
|
||||
mse_vq1(i) = sqrt(results1_log(i).mse);
|
||||
mse_vq4(i) = sqrt(results4_log(i).mse);
|
||||
mse_vq1_ldpc(i) = sqrt(results1_ldpc_log(i).mse);
|
||||
mse_vq4_ldpc(i) = sqrt(results4_ldpc_log(i).mse);
|
||||
end
|
||||
|
||||
figure(1); clf;
|
||||
semilogy(EbNodB, ber, 'g+-;ber;','linewidth', 2); hold on;
|
||||
semilogy(EbNodB, per, 'b+-;per;','linewidth', 2);
|
||||
grid('minor'); xlabel('Eb/No(dB)');
|
||||
hold off;
|
||||
|
||||
figure(2); clf;
|
||||
plot(EbNodB, mse_noerrors, "b+-;no errors;"); hold on;
|
||||
plot(EbNodB, mse_vq1, "g+-;vanilla AWGN;");
|
||||
plot(EbNodB, mse_vq4, "b+-;binary switch;");
|
||||
plot(EbNodB, mse_vq1_ldpc, "r+-;ldpc (112,56);");
|
||||
plot(EbNodB, mse_vq4_ldpc, "k+-;binary switch ldpc (112,56);");
|
||||
load trellis_dec3_nstage3.txt
|
||||
plot(EbNodB, rms_sd, "c+-;binary switch trellis dec3;");
|
||||
hold off; grid; title("RMS SD (dB)"); xlabel('Eb/No(dB)');
|
||||
endfunction
|
||||
|
||||
|
||||
function vq_file(vq_fn, dec, EbNodB, in_fn, out_fn)
|
||||
[results target_] = run_test_vq(vq_fn, in_fn, nframes=-1, dec, EbNodB, verbose=0);
|
||||
save_f32(out_fn, target_);
|
||||
endfunction
|
||||
|
||||
|
||||
Loading…
Add table
Add a link
Reference in a new issue