aboutsummaryrefslogtreecommitdiff
path: root/octave/hf_sim.m
diff options
context:
space:
mode:
authorAuthor Name <[email protected]>2023-07-07 12:20:59 +0930
committerDavid Rowe <[email protected]>2023-07-07 12:29:06 +0930
commitac7c48b4dee99d4c772f133d70d8d1b38262fcd2 (patch)
treea2d0ace57a9c0e2e5b611c4987f6fed1b38b81e7 /octave/hf_sim.m
shallow zip-file copy from codec2 e9d726bf20
Diffstat (limited to 'octave/hf_sim.m')
-rw-r--r--octave/hf_sim.m78
1 files changed, 78 insertions, 0 deletions
diff --git a/octave/hf_sim.m b/octave/hf_sim.m
new file mode 100644
index 0000000..c9105c0
--- /dev/null
+++ b/octave/hf_sim.m
@@ -0,0 +1,78 @@
+% hf_sim.m
+% David Rowe March 2014
+%
+% Two path CCIR poor HF channel simulation, with apaologies to PathSim
+
+% Init HF channel model from stored sample files of spreading signal ----------------------------------
+
+global spread;
+global spread_2ms;
+global hf_gain;
+
+% 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. Because I'm too
+% lazy to generate my own spreading signals
+
+Fc = 1000; Fs=8000;
+fspread = fopen("../raw/sine1k_2Hz_spread.raw","rb");
+spread1k = fread(fspread, "int16")/10000;
+fclose(fspread);
+fspread = fopen("../raw/sine1k_2ms_delay_2Hz_spread.raw","rb");
+spread1k_2ms = fread(fspread, "int16")/10000;
+fclose(fspread);
+
+% down convert to complex baseband
+
+spreadbb = spread1k.*exp(-j*(2*pi*Fc/Fs)*(1:length(spread1k))');
+spreadbb_2ms = spread1k_2ms.*exp(-j*(2*pi*Fc/Fs)*(1:length(spread1k_2ms))');
+
+% remove -2000 Hz image
+
+b = fir1(50, 5/Fs);
+spread = filter(b,1,spreadbb);
+spread_2ms = filter(b,1,spreadbb_2ms);
+
+% discard first 1000 samples as these were near 0, probably as
+% PathSim states were ramping up
+
+spread = spread(1000:length(spread));
+spread_2ms = spread_2ms(1000:length(spread_2ms));
+
+hf_gain = 1.0/sqrt(var(spread)+var(spread_2ms));
+
+% This function simulates the HF channel at 8kHz for real signals. A
+% good use case is passing a vector of speech samples through it to
+% simulate SSB over HF. There's a really good reason for the 300 -
+% 3000 Hz filter that escapes me right now :-)
+
+function [sim_out snr3kHz_measured ] = hf_sim_real(sim_in, snr3kHz)
+
+ % 300 - 3000 Hz filter
+
+ b = fir1(100,[300/4000, 3000/4000], 'pass');
+
+ % det power of unit variance noise passed through this filter
+
+ filter_var = var(filter(b,1,randn(1000,1)));
+
+ % Start simulation
+
+ s = hilbert(filter(b,1,sim_in));
+ n1 = length(s); n2 = length(spread);
+ n = min(n1,n2);
+ path1 = s(1:n) .* spread(1:n);
+ path2 = s(1:n) .* spread_2ms(1:n);
+ delay = floor(0.002*Fs);
+
+ combined = path1(delay+1:n) + path2(1:n-delay);
+
+ snr = 10 .^ (snr3kHz/10);
+ variance = (combined'*combined)/(snr*n);
+ noise = sqrt(variance*0.5/filter_var)*(randn(n-delay,1) + j*randn(n-delay,1));
+ filtered_noise = filter(b,1,noise);
+
+ sim_out = real(combined+filtered_noise);
+ snr3kHz_measured = 10*log10(var(real(combined))/var(real(filtered_noise)));
+endfunction
+