mirror of https://github.com/drowe67/codec2.git
270 lines
13 KiB
Matlab
270 lines
13 KiB
Matlab
% ofdm_mode.m
|
|
%
|
|
% Library of functions to help setting up OFDM modes
|
|
|
|
%------------------------------------------------------------------------------
|
|
% ofdm_init_mode - Helper function to set up modems for various FreeDV modes,
|
|
% and parse mode string.
|
|
%------------------------------------------------------------------------------
|
|
|
|
1;
|
|
|
|
function config = ofdm_init_mode(mode="700D")
|
|
% defaults for 700D
|
|
|
|
Tcp = 0.002;
|
|
Ns = 8;
|
|
Ts = 0.018;
|
|
Nc = 17;
|
|
config.bps = 2;
|
|
config.Np = 1;
|
|
config.Ntxtbits = 4;
|
|
config.Nuwbits = 5*config.bps;
|
|
config.ftwindow_width = 32;
|
|
config.timing_mx_thresh = 0.35;
|
|
config.bad_uw_errors = 3;
|
|
config.amp_scale = 245E3;
|
|
config.amp_est_mode = 0;
|
|
config.EsNo_est_all_symbols = 1;
|
|
config.EsNodB = 3;
|
|
config.state_machine = "voice1";
|
|
config.edge_pilots = 1;
|
|
config.clip_gain1 = 2.5;
|
|
config.clip_gain2 = 0.8;
|
|
config.foff_limiter = 0;
|
|
config.txbpf_width_Hz = 2000;
|
|
config.data_mode = "";
|
|
|
|
if strcmp(mode,"700D") || strcmp(mode,"700d")
|
|
% defaults above
|
|
elseif strcmp(mode,"700E") || strcmp(mode,"700e")
|
|
Ts = 0.014; Tcp=0.006; Nc = 21; Ns=4;
|
|
config.edge_pilots = 0; config.state_machine = "voice2";
|
|
config.Nuwbits = 12; config.bad_uw_errors = 3; config.Ntxtbits = 2;
|
|
config.amp_est_mode = 1; config.ftwindow_width = 80;
|
|
config.amp_scale = 155E3; config.clip_gain1 = 3; config.clip_gain2 = 0.8;
|
|
config.foff_limiter = 1;
|
|
elseif strcmp(mode,"2020")
|
|
Ts = 0.0205; Nc = 31;
|
|
config.amp_scale = 167E3; config.clip_gain1 = 2.5; config.clip_gain2 = 0.8;
|
|
elseif strcmp(mode,"2020B")
|
|
Ts = 0.014; Tcp = 0.004; Nc = 29; Ns=5;
|
|
config.Ntxtbits = 4; config.Nuwbits = 8*2; config.bad_uw_errors = 5;
|
|
config.amp_scale = 130E3; config.clip_gain1 = 2.5; config.clip_gain2 = 0.8;
|
|
config.edge_pilots = 0; config.state_machine = "voice2";
|
|
config.foff_limiter = 1; config.ftwindow_width = 64;
|
|
config.txbpf_width_Hz = 2200;
|
|
elseif strcmp(mode,"qam16c1")
|
|
Ns=5; config.Np=5; Tcp = 0.004; Ts = 0.016; Nc = 33; config.data_mode = "streaming";
|
|
config.bps=4; config.Ntxtbits = 0; config.Nuwbits = 15*4; config.bad_uw_errors = 5;
|
|
config.state_machine = "data";
|
|
config.ftwindow_width = 32; config.amp_scale = 132E3;
|
|
config.EsNo_est_all_symbols = 0; config.amp_est_mode = 1; config.EsNodB = 10;
|
|
elseif strcmp(mode,"qam16c2")
|
|
Ns=5; config.Np=31; Tcp = 0.004; Ts = 0.016; Nc = 33; config.data_mode = "streaming";
|
|
config.bps=4; config.Ntxtbits = 0; config.Nuwbits = 42*4; config.bad_uw_errors = 15;
|
|
config.ftwindow_width = 80; config.amp_scale = 135E3; config.state_machine = "data";
|
|
config.EsNo_est_all_symbols = 0; config.amp_est_mode = 1; config.EsNodB = 10;
|
|
config.tx_uw = zeros(1,config.Nuwbits = 42*4);
|
|
config.tx_uw(1:24) = [1 1 0 0 1 0 1 0 1 1 1 1 0 0 0 0 1 1 1 1 0 0 0 0];
|
|
config.tx_uw(end-24+1:end) = [1 1 0 0 1 0 1 0 1 1 1 1 0 0 0 0 1 1 1 1 0 0 0 0];
|
|
elseif strcmp(mode,"datac0")
|
|
Ns=5; config.Np=4; Tcp = 0.006; Ts = 0.016; Nc = 9; config.data_mode = "streaming";
|
|
config.Ntxtbits = 0; config.Nuwbits = 32; config.bad_uw_errors = 9;
|
|
config.state_machine = "data";
|
|
config.ftwindow_width = 80; config.amp_est_mode = 1; config.EsNodB = 3;
|
|
config.edge_pilots = 0; config.timing_mx_thresh = 0.08;
|
|
config.tx_uw = zeros(1,config.Nuwbits);
|
|
config.tx_uw(1:16) = [1 1 0 0 1 0 1 0 1 1 1 1 0 0 0 0];
|
|
config.amp_scale = 300E3; config.clip_gain1 = 2.2; config.clip_gain2 = 0.85;
|
|
elseif strcmp(mode,"datac5")
|
|
Ns=5; config.Np=58; Tcp = 0.004; Ts = 0.016; Nc = 35; config.data_mode = "streaming";
|
|
config.Ntxtbits = 0; config.Nuwbits = 40; config.bad_uw_errors = 14;
|
|
config.state_machine = "data";
|
|
config.ftwindow_width = 80; config.amp_est_mode = 1; config.EsNodB = 3;
|
|
config.amp_scale = 145E3; config.clip_gain1 = 2.7; config.clip_gain2 = 0.8;
|
|
config.edge_pilots = 0; config.timing_mx_thresh = 0.10;
|
|
config.tx_uw = zeros(1,config.Nuwbits);
|
|
config.tx_uw(1:16) = [1 1 0 0 1 0 1 0 1 1 1 1 0 0 0 0];
|
|
elseif strcmp(mode,"datac1")
|
|
Ns=5; config.Np=38; Tcp = 0.006; Ts = 0.016; Nc = 27; config.data_mode = "streaming";
|
|
config.Ntxtbits = 0; config.Nuwbits = 16; config.bad_uw_errors = 6;
|
|
config.state_machine = "data";
|
|
config.ftwindow_width = 80; config.amp_est_mode = 1; config.EsNodB = 3;
|
|
% clipper/compression adjustment:
|
|
% 1. With clipper off increase amp_scale until peak just hit 16384
|
|
% 2. With clipper on increase clip_gain1 until about 30% clipped
|
|
% 3. BPF will drop level beneath 16384, adjust clip_gain2 to just hit 16384 peak again
|
|
% 4. Clipped/unclipped operating point for same PER should be about 1dB apart
|
|
config.amp_scale = 145E3; config.clip_gain1 = 2.7; config.clip_gain2 = 0.8;
|
|
config.edge_pilots = 0; config.timing_mx_thresh = 0.10;
|
|
config.tx_uw = [1 1 0 0 1 0 1 0 1 1 1 1 0 0 0 0];
|
|
elseif strcmp(mode,"datac3")
|
|
Ns=5; config.Np=29; Tcp = 0.006; Ts = 0.016; Nc = 9; config.data_mode = "streaming";
|
|
config.edge_pilots = 0;
|
|
config.Ntxtbits = 0; config.Nuwbits = 40; config.bad_uw_errors = 10;
|
|
config.ftwindow_width = 80; config.timing_mx_thresh = 0.10;
|
|
config.tx_uw = zeros(1,config.Nuwbits);
|
|
config.tx_uw(1:24) = [1 1 0 0 1 0 1 0 1 1 1 1 0 0 0 0 1 1 1 1 0 0 0 0];
|
|
config.tx_uw(end-24+1:end) = [1 1 0 0 1 0 1 0 1 1 1 1 0 0 0 0 1 1 1 1 0 0 0 0];
|
|
config.amp_est_mode = 1; config.EsNodB = 3;
|
|
config.state_machine = "data";
|
|
config.amp_scale = 300E3; config.clip_gain1 = 2.2; config.clip_gain2 = 0.8;
|
|
elseif strcmp(mode,"datac4")
|
|
Ns=5; config.Np=47; Tcp = 0.006; Ts = 0.016; Nc = 4; config.data_mode = "streaming";
|
|
config.edge_pilots = 0;
|
|
config.Ntxtbits = 0; config.Nuwbits = 32; config.bad_uw_errors = 12;
|
|
config.ftwindow_width = 80; config.timing_mx_thresh = 0.5;
|
|
config.tx_uw = zeros(1,config.Nuwbits);
|
|
config.tx_uw(1:24) = [1 1 0 0 1 0 1 0 1 1 1 1 0 0 0 0 1 1 1 1 0 0 0 0];
|
|
config.tx_uw(end-24+1:end) = [1 1 0 0 1 0 1 0 1 1 1 1 0 0 0 0 1 1 1 1 0 0 0 0];
|
|
config.amp_est_mode = 1; config.EsNodB = 3;
|
|
config.state_machine = "data";
|
|
config.amp_scale = 2*300E3; config.clip_gain1 = 1.2; config.clip_gain2 = 1.0;
|
|
config.txbpf_width_Hz = 400;
|
|
elseif strcmp(mode,"datac13")
|
|
Ns=5; config.Np=18; Tcp = 0.006; Ts = 0.016; Nc = 3; config.data_mode = "streaming";
|
|
config.edge_pilots = 0;
|
|
config.Ntxtbits = 0; config.Nuwbits = 48; config.bad_uw_errors = 18;
|
|
config.ftwindow_width = 80; config.timing_mx_thresh = 0.45;
|
|
config.tx_uw = zeros(1,config.Nuwbits);
|
|
config.tx_uw(1:24) = [1 1 0 0 1 0 1 0 1 1 1 1 0 0 0 0 1 1 1 1 0 0 0 0];
|
|
config.tx_uw(end-24+1:end) = [1 1 0 0 1 0 1 0 1 1 1 1 0 0 0 0 1 1 1 1 0 0 0 0];
|
|
config.amp_est_mode = 1; config.EsNodB = 3;
|
|
config.state_machine = "data";
|
|
config.amp_scale = 2.5*300E3; config.clip_gain1 = 1.2; config.clip_gain2 = 1.0;
|
|
config.txbpf_width_Hz = 400;
|
|
elseif strcmp(mode,"datac14")
|
|
Ns=5; config.Np=4; Tcp = 0.005; Ts = 0.018; Nc = 4; config.data_mode = "streaming";
|
|
config.edge_pilots = 0;
|
|
config.Ntxtbits = 0; config.Nuwbits = 32; config.bad_uw_errors = 12;
|
|
config.ftwindow_width = 80; config.timing_mx_thresh = 0.45;
|
|
config.tx_uw = zeros(1,config.Nuwbits);
|
|
config.tx_uw(1:24) = [1 1 0 0 1 0 1 0 1 1 1 1 0 0 0 0 1 1 1 1 0 0 0 0];
|
|
config.tx_uw(end-24+1:end) = [1 1 0 0 1 0 1 0 1 1 1 1 0 0 0 0 1 1 1 1 0 0 0 0];
|
|
config.amp_est_mode = 1; config.EsNodB = 3;
|
|
config.state_machine = "data";
|
|
config.amp_scale = 2*300E3; config.clip_gain1 = 2; config.clip_gain2 = 1;
|
|
config.txbpf_width_Hz = 400;
|
|
elseif strcmp(mode,"1")
|
|
Ns=5; config.Np=10; Tcp=0; Tframe = 0.1; Ts = Tframe/Ns; Nc = 1;
|
|
else
|
|
% try to parse mode string for user defined mode
|
|
vec = sscanf(mode, "Ts=%f Nc=%d Ncp=%f");
|
|
Ts=vec(1); Nc=vec(2); Ncp=vec(3);
|
|
end
|
|
Rs=1/Ts;
|
|
config.Rs = Rs; config.Tcp = Tcp; config.Ns = Ns; config.Nc = Nc;
|
|
if !isfield(config,"tx_uw")
|
|
config.tx_uw = zeros(1,config.Nuwbits);
|
|
end
|
|
end
|
|
|
|
% ------------------------------------------------------------------------------
|
|
% codec_to_frame_packing - Set up a bunch of constants to support modem frame
|
|
% construction from LDPC codewords and codec source bits
|
|
% ------------------------------------------------------------------------------
|
|
|
|
function [code_param Nbitspercodecframe Ncodecframespermodemframe] = codec_to_frame_packing(states, mode)
|
|
ofdm_load_const;
|
|
mod_order = 4; bps = 2; modulation = 'QPSK'; mapping = 'gray';
|
|
|
|
init_cml();
|
|
if strcmp(mode, "700D")
|
|
load HRA_112_112.txt
|
|
code_param = ldpc_init_user(HRA_112_112, modulation, mod_order, mapping);
|
|
assert(Nbitsperframe == (code_param.coded_bits_per_frame + Nuwbits + Ntxtbits));
|
|
% unused for this mode
|
|
Nbitspercodecframe = Ncodecframespermodemframe = 0;
|
|
end
|
|
if strcmp(mode, "700E")
|
|
load HRA_56_56.txt
|
|
code_param = ldpc_init_user(HRA_56_56, modulation, mod_order, mapping);
|
|
assert(Nbitsperframe == (code_param.coded_bits_per_frame + Nuwbits + Ntxtbits));
|
|
% unused for this mode
|
|
Nbitspercodecframe = Ncodecframespermodemframe = 0;
|
|
end
|
|
if strcmp(mode, "2020")
|
|
load HRA_504_396.txt
|
|
code_param = ldpc_init_user(HRA_504_396, modulation, mod_order, mapping);
|
|
code_param.data_bits_per_frame = 312;
|
|
code_param.coded_bits_per_frame = code_param.data_bits_per_frame + code_param.ldpc_parity_bits_per_frame;
|
|
code_param.coded_syms_per_frame = code_param.coded_bits_per_frame/code_param.bits_per_symbol;
|
|
printf("2020 mode\n");
|
|
printf("ldpc_data_bits_per_frame = %d\n", code_param.ldpc_data_bits_per_frame);
|
|
printf("ldpc_coded_bits_per_frame = %d\n", code_param.ldpc_coded_bits_per_frame);
|
|
printf("ldpc_parity_bits_per_frame = %d\n", code_param.ldpc_parity_bits_per_frame);
|
|
printf("data_bits_per_frame = %d\n", code_param.data_bits_per_frame);
|
|
printf("coded_bits_per_frame = %d\n", code_param.coded_bits_per_frame);
|
|
printf("coded_syms_per_frame = %d\n", code_param.coded_syms_per_frame);
|
|
printf("ofdm_bits_per_frame = %d\n", Nbitsperframe);
|
|
Nbitspercodecframe = 52; Ncodecframespermodemframe = 6;
|
|
printf(" Nuwbits: %d Ntxtbits: %d\n", Nuwbits, Ntxtbits);
|
|
Nparity = code_param.ldpc_parity_bits_per_frame;
|
|
totalbitsperframe = code_param.data_bits_per_frame + Nparity + Nuwbits + Ntxtbits;
|
|
printf("Total bits per frame: %d\n", totalbitsperframe);
|
|
assert(totalbitsperframe == Nbitsperframe);
|
|
end
|
|
if strcmp(mode, "qam16c1")
|
|
load H2064_516_sparse.mat
|
|
code_param = ldpc_init_user(HRA, modulation='QAM', mod_order=16, mapping="", reshape(states.qam16,1,16));
|
|
end
|
|
if strcmp(mode, "qam16c2")
|
|
framesize = 16200; rate = 0.6;
|
|
code_param = ldpc_init_builtin("dvbs2", rate, framesize, modulation='QAM', mod_order=16, mapping="", reshape(states.qam16,1,16));
|
|
end
|
|
if strcmp(mode, "datac5")
|
|
framesize = 16200; rate = 0.6;
|
|
code_param = ldpc_init_builtin("dvbs2", rate, framesize, modulation='QPSK', mod_order=4, mapping="");
|
|
end
|
|
if strcmp(mode, "datac0") || strcmp(mode, "datac13")
|
|
load H_128_256_5.mat
|
|
code_param = ldpc_init_user(H, modulation, mod_order, mapping);
|
|
end
|
|
if strcmp(mode, "datac1")
|
|
load H_4096_8192_3d.mat
|
|
code_param = ldpc_init_user(HRA, modulation, mod_order, mapping);
|
|
end
|
|
if strcmp(mode, "datac3")
|
|
load H_1024_2048_4f.mat
|
|
code_param = ldpc_init_user(H, modulation, mod_order, mapping);
|
|
end
|
|
if strcmp(mode, "datac4")
|
|
load H_1024_2048_4f
|
|
code_param = ldpc_init_user(H, modulation, mod_order, mapping);
|
|
code_param.data_bits_per_frame = 448;
|
|
code_param.coded_bits_per_frame = code_param.data_bits_per_frame + code_param.ldpc_parity_bits_per_frame;
|
|
code_param.coded_syms_per_frame = code_param.coded_bits_per_frame/code_param.bits_per_symbol;
|
|
end
|
|
if strcmp(mode, "datac13")
|
|
load H_256_512_4.mat
|
|
code_param = ldpc_init_user(H, modulation, mod_order, mapping);
|
|
code_param.data_bits_per_frame = 128;
|
|
code_param.coded_bits_per_frame = code_param.data_bits_per_frame + code_param.ldpc_parity_bits_per_frame;
|
|
code_param.coded_syms_per_frame = code_param.coded_bits_per_frame/code_param.bits_per_symbol;
|
|
end
|
|
if strcmp(mode, "datac14")
|
|
load HRA_56_56.txt
|
|
code_param = ldpc_init_user(HRA_56_56, modulation, mod_order, mapping);
|
|
code_param.data_bits_per_frame = 40;
|
|
code_param.coded_bits_per_frame = code_param.data_bits_per_frame + code_param.ldpc_parity_bits_per_frame;
|
|
code_param.coded_syms_per_frame = code_param.coded_bits_per_frame/code_param.bits_per_symbol;
|
|
end
|
|
if strcmp(mode, "datac0") || strcmp(mode, "datac1") || strcmp(mode, "datac3") ...
|
|
|| strcmp(mode, "datac4") || strcmp(mode, "qam16c1") ...
|
|
|| strcmp(mode, "qam16c2") || strcmp(mode, "datac5") || strcmp(mode, "datac13") ...
|
|
|| strcmp(mode, "datac14")
|
|
printf("ldpc_data_bits_per_frame = %d\n", code_param.ldpc_data_bits_per_frame);
|
|
printf("ldpc_coded_bits_per_frame = %d\n", code_param.ldpc_coded_bits_per_frame);
|
|
printf("ldpc_parity_bits_per_frame = %d\n", code_param.ldpc_parity_bits_per_frame);
|
|
printf("Nbitsperpacket = %d\n", Nbitsperpacket);
|
|
Nparity = code_param.ldpc_parity_bits_per_frame;
|
|
totalbitsperframe = code_param.data_bits_per_frame + Nparity + Nuwbits + Ntxtbits;
|
|
printf("totalbitsperframe = %d\n", totalbitsperframe);
|
|
assert(totalbitsperframe == Nbitsperpacket);
|
|
Nbitspercodecframe = Ncodecframespermodemframe = -1;
|
|
end
|
|
endfunction
|
|
|
|
|