Files
imdd_silas/projects/FSO_transmission/Evaluation Scripts/first_analysis_ber.m
magf 3676d92b30 +++ Changes +++
+ duobinary_target now supports memoryless decoding (FFE targets DB response without MLSE)
+ PAMmapper.quantize now supports custom constellations for quantization
+ Added a new folder 'Documentations' for pdfs, slides, etc.
+ Added new FSO evaluation scripts in projects/FSO transmission/Evaluation Scripts
+ Added ffe_db (rudimentary module, not important anymore)
2026-03-05 10:41:36 +01:00

222 lines
10 KiB
Matlab
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
function BER_value = first_analysis_ber(current, power, num_pf_coeff, taps_ffe, taps_dfe, M, trlength, eq_method, filter_length, num_signal, our_signal, weighted_DFE, db_target)
%%
close all
%%
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=" + current + "mA_RoP=" + power + "mW_L=31m_PS=RRC_rolloff=0.75_Mode=Rise.mat");
data_tr_mf = load("C:\Users\magf\Desktop\Desktop\MATLAB-Zeugs\FSO Equalizer\FSO_FP_QCL_60umUTC\Already Recovered and Filtered\AfterSync_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=" + current + "mA_RoP=" + power + "mW_L=31m_PS=RRC_rolloff=0.6_Mode=Rise.mat");
data_tr_mf = load("C:\Users\magf\Desktop\Desktop\MATLAB-Zeugs\FSO Equalizer\FSO_FP_QCL_60umUTC\Already Recovered and Filtered\AfterSync_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","rrc","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)
Kov = 14;
Scope_sig = Scope_sig.resample('fs_in', fs, 'fs_out', Kov*fsym);
% 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",Kov*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{num_signal};
data_tr_mf = Electricalsignal(data_tr_mf.Results, "fs", fsym);
[~,Rx_synced_cell_tr_mf,inverted_tr_mf,sequenceFound_tr_mf,sequenceStarts_tr_mf] = data_tr_mf.tsynch("reference", Symbols, "fs_ref", fsym, "debug_plots", 1);
Rx_tr_mf = Rx_synced_cell_tr_mf{num_signal};
% Rx_Time_Rec = Rx_matched;
% Rx_Time_Rec = Timing_Recovery_Move_It('f_sim', 28e9, 'gamma', 0.1).process(Rx_matched_1);
Time_Rec = 1;
if Time_Rec
Rx_Time_Rec = MaxVar_Timing_Recovery('mode',0,'fsym',fsym,'fadc',Kov*fsym,'num_tau',Kov*128,'sps',Kov,'comp_signal',0,'comp_mode',0).process(Rx_matched_1);
sps = 1;
else
sps = Kov;
end
Rx_Time_Rec.fs = fsym;
Rx_Time_Rec = Rx_Time_Rec.normalize('mode','rms');
Rx_tr_mf = Rx_tr_mf.normalize('mode','rms');
% Rx_Time_Rec.signal = resample(Rx_Time_Rec.signal, 12e9, 6e9);
% Rx_matched_1.plot("fignum",231231)
% Rx_Time_Rec.plot("fignum",231231)
%% not working..
if our_signal
Rx_synced = Rx_Time_Rec;
else
Rx_synced = Rx_tr_mf;
end
% Rx_synced = Rx_Time_Rec;
% Rx_synced = Rx_synced_cell{1};
len_tr = trlength;
mu_ffe1 = 0.0001;
mu_ffe2 = 0.0008;
mu_ffe3 = 0.001;
mu_dc = 0.004;
mu_ffe = [mu_ffe1 mu_ffe3 mu_ffe3];
mu_dfe = 0.0004;
duob_mode = db_mode.no_db;
Rx_synced.plot("displayname",'RX: Matched+Sync+2sps','fignum',103);
Rx_synced.spectrum("displayname",'RX: Matched+Sync+2sps','fignum',104);
Digi_sig_compare.normalize("mode","rms").spectrum("displayname",'Tx: RC-shaped','fignum',1,'normalizeTo0dB',1);
Rx_sig_compare.normalize("mode","rms").spectrum("displayname",'Tx: RC-shaped + matched filtered ','fignum',1,'normalizeTo0dB',1);
Rx_synced.normalize("mode","rms").spectrum("displayname",'RX: matched filtered + synced','fignum',1,'normalizeTo0dB',1);
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
if eq_method == 1
%% -------------------- FFE --------------------
% requires some more digging what is going on :-)
eq_ffe = EQ("Ne",taps_ffe,"Nb",taps_dfe, ...
"training_length",len_tr,"training_loops",5,"dd_loops",5, ...
"K",sps,"DCmu",mu_dc,"DDmu",[mu_ffe mu_dfe],"DFEmu",0.005, ...
"FFEmu",0,"plotfinal",0,"ideal_dfe",1);
ffe_results = ffe(eq_ffe,M,Rx_synced,Symbols,Bits, ...
"precode_mode",duob_mode,'showAnalysis',0,"postFFE",[], ...
"eth_style_symbol_mapping",mapping_style,'db_target',db_target);
% 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;
elseif eq_method == 2
%% -------------------- VNLE + MLSE --------------------
pf_ncoeffs = num_pf_coeff;
eq_v = EQ("Ne",taps_ffe,"Nb",taps_dfe, ...
"training_length",len_tr,"training_loops",5,"dd_loops",5, ...
"K",sps,"DCmu",mu_dc,"DDmu",[mu_ffe mu_dfe],"DFEmu",0.005, ...
"FFEmu",0,"plotfinal",0,"ideal_dfe",0,'weighted_DFE',1,'weighted_DFE_d_min',0.5, ...
'weighted_DFE_mode','I2','weighted_DFE_I_mode',weighted_DFE,'PDFE_coefficient',0.01);
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;
elseif eq_method == 3
%% -------------------- 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",len_tr,"training_loops",5,"dd_loops",5, ...
"K",sps,"DCmu",mu_dc,"DDmu",[mu_ffe mu_dfe],"DFEmu",0.005,"FFEmu",0,"plotfinal",0,"ideal_dfe",1);
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');
fprintf('My EQ: %.1e \n',dbt_results.metrics.BER);
fprintf('Paper: %.1e \n \n',ber_in_paper);
BER_value = dbt_results.metrics.BER;
elseif eq_method == 4
%% -------------------- ML-based MLSE (L=2) --------------------
ml_mlse_equalizer = ML_MLSE("epochs_tr",150,"epochs_dd",1, ...
"len_tr",length(Rx_synced),"mu_dd",0.03,"mu_tr",0.03,"order",filter_length,"sps",1, ...
"traceback_depth",256,"L",1,"delta",4,"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:\n');
fprintf('My EQ: %.1e \n',ml_mlse_results.metrics.BER);
fprintf('Paper: %.1e \n \n',ber_in_paper);
BER_value = ml_mlse_results.metrics.BER;
end
end