some more Octave files rm-ed

This commit is contained in:
drowe67 2023-07-07 14:22:31 +09:30 committed by David Rowe
parent 87025ac7d2
commit a291cfaf4c
41 changed files with 0 additions and 5552 deletions

View file

@ -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

View file

@ -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);

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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;

View file

@ -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

View file

@ -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

View file

@ -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);
#}

View file

@ -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

View file

@ -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

View file

@ -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)

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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])

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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;
#}

View file

@ -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');

View file

@ -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);

View file

@ -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

View file

@ -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")

View file

@ -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