- Class folder 'Timing Recovery' with different timing recoveries
- Minimal example for the timing recovery on the FSO data
- New evaluation scripts in the FSO project folder
This commit is contained in:
magf
2026-02-02 10:56:12 +01:00
parent 798a0ca3b3
commit 005e821131
28 changed files with 3685 additions and 0 deletions

View File

@@ -0,0 +1,190 @@
function BER_value = first_analysis_2(taps_ffe, taps_dfe, trlen, trloops, ddloops, K_FFE, DCmu, DDmu, DFEmu, FFEmu, plot_final, idealdfe, num_pf_coeffs, damp_factor, norm_loop_bw, det_gain)
%%
base = "C:\Users\magf\Desktop\Desktop\MATLAB-Zeugs\FSO Equalizer\FSO_FP_QCL_60umUTC\";
mode = 0; %0 oder 1
M = 2;
all_files = dir(fullfile(base, "**/*.mat"));
if M == 2
tx_data_path = fullfile(base, "14G_PAM2\tx_info\tx_info_PAM2_14Gbd0.75RRC.mat");
filename = fullfile(base, "14G_PAM2\M=2_Rs=1.4e10_Fs=8e10_I=265mA_RoP=46.3mW_L=31m_PS=RRC_rolloff=0.75_Mode=Rise.mat");
elseif M == 4
tx_data_path = fullfile(base, "6G_PAM4\tx_info\tx_info_PAM4_6Gbd0.6RRC.mat");
filename = fullfile(base, "6G_PAM4\M=4_Rs=6e9_Fs=8e10_I=255mA_RoP=42.3mW_L=31m_PS=RRC_rolloff=0.6_Mode=Rise.mat");
end
if mode == 1
[f, p] = uigetfile(fullfile(base, "**/*.mat"));
if f~=0
filename = fullfile(p,f);
end
end
tx_data = load(tx_data_path);
datas = load(filename);
%%
str = filename;
M_ = str2double(regexp(str, 'M=([^_]+)', 'tokens', 'once'));
assert(M==M_);
fsym = str2double(regexp(str, 'Rs=([^_]+)', 'tokens', 'once'));
fs = str2double(regexp(str, 'Fs=([^_]+)', 'tokens', 'once'));
I = sscanf(char(regexp(str, 'I=([^_]+)', 'tokens', 'once')), '%f');
rop = sscanf(char(regexp(str, 'RoP=([^_]+)', 'tokens', 'once')), '%f');
L = sscanf(char(regexp(str, 'L=([^_]+)', 'tokens', 'once')), '%f');
pulseshape = string( regexp(str, 'PS=([^_]+)', 'tokens', 'once'));
rolloff = str2double(regexp(str, 'rolloff=([^_]+)', 'tokens', 'once'));
mode = string( regexp(str, 'Mode=([^\.]+)', 'tokens', 'once'));
%%
% Tx data
Bits = Informationsignal(tx_data.tx_data,"fs",fsym);
Symbols = Informationsignal(real(tx_data.tx_PAM_sym),"fs",fsym);
mapping_style = M==4; % Pam2 is like move-it; PAM-4 is different, same mapping like ETH peopled used in Zurich... hence the "eth_style" argument here and there
PM = PAMmapper(M,0,"eth_style",mapping_style); % one should rename "eth style" as this is simply a different mapping scheme
Symbols_ = PM.map(Bits) .* PM.scaling;
assert(isequal(Symbols.signal,Symbols_.signal));
Bits_ = PM.demap(Symbols);
[bits,errors,ber,errorIndice] = calc_ber(Bits_.signal,Bits.signal);
assert(ber == 0);
%% For comparison, apply pulsef on Tx Symbols
Pform = Pulseformer("fsym",fsym,"fdac",fs,"pulse","rc","pulselength",16,"alpha",rolloff);
Digi_sig_compare = Pform.process(Symbols);
MF = Pulseformer("fsym",fsym,"fdac",2*fsym,"pulse","rrc","pulselength",16,"alpha",rolloff);
Rx_sig_compare = MF.process(Digi_sig_compare);
%%
% Rx Data
traceData = datas.tr.lastData(2).trace.ch3;
%FYI: Voltage=(RawDataYReference)×YIncrement+YOrigin
scoperead_volts = (traceData.RawData - traceData.YReference) * traceData.YIncrement + traceData.YOrigin;
demystified = isequal(traceData.YData,scoperead_volts);
assert(demystified);
Scope_sig = Electricalsignal(traceData.YData,"fs",fs);
Scope_sig.plot("displayname",'raw','fignum',100);
Scope_sig.spectrum("displayname",'raw','fignum',101)
% 1) matched filter
% pulse is symmetric, hence we can use pulsef firectly as matched filter.
% It feels off (bit I think correct) that the fsym is now the output freq.!!
% -> output 2 sps to omit timing recovery!?
Matched_Filter = Pulseformer("fsym",fsym,"fdac",2*fsym,"pulse","rrc","pulselength",16,"alpha",rolloff,"matched",1);
Rx_matched = Matched_Filter.process(Scope_sig);
Rx_matched.spectrum("displayname",'Signal after matched filter','fignum',1);
% timing sync -> at this point we still have no symbol timing recovery, we
% try to do this with 2sps EQ!
[~,Rx_synced_cell,inverted,sequenceFound,sequenceStarts] = Rx_matched.tsynch("reference", Symbols, "fs_ref", fsym, "debug_plots", 1);
Rx_matched_1 = Rx_synced_cell{1};
% Rx_Time_Rec = Rx_matched;
[Rx_Time_Rec, Timing_Error] = Timing_Recovery("modulation", 'PAM/PSK/QAM', "timing_error_detector",'Gardner (non-data-aided)','sps',2, ...
'damping_factor',damp_factor,'normalized_loop_bandwidth',norm_loop_bw,'detector_gain',det_gain).process(Rx_matched_1);
figure;plot(Timing_Error);
% Rx_Time_Rec.signal = resample(Rx_Time_Rec.signal, 28e9, 14e9);
%% not working..
Rx_synced = Rx_Time_Rec;
Rx_synced.fs = 14e9;
% Rx_synced = Rx_synced_cell{1};
% len_tr = trlen;
% mu_ffe1 = mu_ffe_values(1);
% mu_ffe2 = mu_ffe_values(2);
% mu_ffe3 = mu_ffe_values(3);
% mu_dc = 0.005;
% mu_ffe = [mu_ffe1 mu_ffe3 mu_ffe3];
% mu_dfe = mu_dfe_values;
duob_mode = db_mode.no_db;
Rx_synced.plot("displayname",'RX: Matched+Sync+2sps','fignum',2);
Digi_sig_compare.normalize("mode","rms").spectrum("displayname",'Tx: RC-shaped','fignum',1,'normalizeTo0dB',0);
Rx_sig_compare.normalize("mode","rms").spectrum("displayname",'Tx: RC-shaped + matched filtered ','fignum',1,'normalizeTo0dB',0);
Rx_synced.normalize("mode","rms").spectrum("displayname",'RX: matched filtered + synced','fignum',1,'normalizeTo0dB',0);
if M == 2
ber_in_paper = 10^(-2.6); %fig 3a) 4 Gb/s MWIR FSO Transmission using Directly Modulated QCL and an Uncooled UTC-PD at Room-Temperature
elseif M == 4
ber_in_paper = 10^(-2.5);
end
%% -------------------- FFE --------------------
% % requires some more digging what is going on :-)
% eq_ffe = EQ("Ne",taps_ffe,"Nb",taps_dfe, ...
% "training_length",trlen,"training_loops",trloops,"dd_loops",ddloops, ...
% "K",K_FFE,"DCmu",DCmu,"DDmu",DDmu,"DFEmu",DFEmu, ...
% "FFEmu",FFEmu,"plotfinal",plot_final,"ideal_dfe",idealdfe);
%
% ffe_results = ffe(eq_ffe,M,Rx_synced,Symbols,Bits, ...
% "precode_mode",duob_mode,'showAnalysis',0,"postFFE",[], ...
% "eth_style_symbol_mapping",mapping_style);
%
% % ffe_results.metrics.print
% fprintf('My EQ: %.1e \n',ffe_results.metrics.BER);
% fprintf('Paper: %.1e \n \n',ber_in_paper);
% BER_value = ffe_results.metrics.BER;
%% -------------------- VNLE + MLSE --------------------
pf_ncoeffs = num_pf_coeffs;
eq_v = EQ("Ne",taps_ffe,"Nb",taps_dfe, ...
"training_length",trlen,"training_loops",trloops,"dd_loops",ddloops, ...
"K",K_FFE,"DCmu",DCmu,"DDmu",DDmu,"DFEmu",DFEmu, ...
"FFEmu",FFEmu,"plotfinal",plot_final,"ideal_dfe",idealdfe);
pf_ = Postfilter("ncoeff",pf_ncoeffs,"useBurg",1);
mlse_ = MLSE("duobinary_output",0,'M',M,'trellis_states',PAMmapper(M,0,"eth_style",mapping_style).levels);
[vnle_results, mlse_results] = vnle_postfilter_mlse(eq_v, pf_, mlse_, M, Rx_synced, Symbols, Bits, ...
"precode_mode", duob_mode, 'showAnalysis', 1, "postFFE", [], "eth_style_symbol_mapping", mapping_style);
mlse_results.metrics.print
fprintf('My EQ: %.1e \n',mlse_results.metrics.BER);
fprintf('Paper: %.1e \n \n',ber_in_paper);
BER_value = mlse_results.metrics.BER;
%% -------------------- DB target --------------------
% mlse_db_ = MLSE("DIR",[1,1],"duobinary_output",0,"M",M,'trellis_states',PAMmapper(M,0).levels);
%
% eq_ = EQ("Ne",taps_ffe,"Nb",taps_dfe, ...
% "training_length",trlen,"training_loops",trloops,"dd_loops",ddloops, ...
% "K",K_FFE,"DCmu",DCmu,"DDmu",DDmu,"DFEmu",DFEmu, ...
% "FFEmu",FFEmu,"plotfinal",plot_final,"ideal_dfe",idealdfe);
%
% dbt_results = duobinary_target(eq_,mlse_db_, M, Rx_synced, Symbols, Bits, ...
% "precode_mode", duob_mode, 'showAnalysis', 0, "postFFE", [],"eth_style_symbol_mapping",mapping_style);
%
% dbt_results.metrics.print("description",'Duobinary');
% mlse_results.metrics.print
% fprintf('My EQ: %.1e \n',dbt_results.metrics.BER);
% fprintf('Paper: %.1e \n \n',ber_in_paper);
%% -------------------- ML-based MLSE (L=2) --------------------
% ml_mlse_equalizer = ML_MLSE("epochs_tr",100,"epochs_dd",1, ...
% "len_tr",length(Rx_synced)/2,"mu_dd",0.03,"mu_tr",0.03,"order",30,"sps",1, ...
% "traceback_depth",256,"L",2,"delta",10,"adaptive_mu",0);
%
% [ml_mlse_results] = ml_mlse(ml_mlse_equalizer, M, Rx_synced, Symbols, Bits,"precode_mode",duob_mode,"eth_style_symbol_mapping",mapping_style);
% fprintf('ML-based MLSE:');
% fprintf('My EQ: %.1e \n',ml_mlse_results.metrics.BER);
% fprintf('Paper: %.1e \n \n',ber_in_paper);
%
% % -------------------- Post-FFE --------------------
% eq_post = FFE("epochs_tr",5,"epochs_dd",5,"len_tr",len_tr,"mu_dd",1e-4,"mu_tr",0,"order",1001,"sps",1,"decide",0);
% post_ffe_results = ffe(eq_ffe,M,Rx_synced,Symbols,Bits, ...
% "precode_mode",duob_mode,'showAnalysis',0,"postFFE",[], ...
% "eth_style_symbol_mapping",mapping_style);
% fprintf('Post-FFE:');
% fprintf('My EQ: %.1e \n',post_ffe_results.metrics.BER);
% fprintf('Paper: %.1e \n \n',ber_in_paper);
end