diff --git a/Classes/01_transmit/PAMsource.m b/Classes/01_transmit/PAMsource.m index 3a1b2eb..804777a 100644 --- a/Classes/01_transmit/PAMsource.m +++ b/Classes/01_transmit/PAMsource.m @@ -71,20 +71,17 @@ classdef PAMsource function [digi_sig,symbols,bits] = process(obj) %%%%% PRBS Generation in correct shape for Modulation Format %%%%%% - O = obj.order; %order of prbs - N = 2^(O-1); %length of prbs - [~,seed] = prbs(O,1); %initialize first seed of prbs bitpattern=[]; if obj.useprbs - % for i = 1:log2(obj.M) - % [bitpattern(:,i),seed] = prbs(O,N,seed); - % end + % O = obj.order; %order of prbs + % N = 2^(O-1); %length of prbs + % [~,seed] = prbs(O,1); %initialize first seed of prbs + % % for i = 1:log2(obj.M) + % % [bitpattern(:,i),seed] = prbs(O,N,seed); + % % end %%%%% MOVE-IT PRMS %%%% - - - state = struct(); para = struct(); @@ -155,24 +152,46 @@ classdef PAMsource sym_max = max(symbols.signal); end - % symbols.spectrum("fignum",111,"displayname","1) RAW SIGNAL"); - - pulsf = Moveit_wrapper('pulsef'); - pulsf.para.alpharacos = obj.pulseformer.alpha; - pulsf.para.f_sym = obj.fsym; - pulsf.para.fs = obj.fsym; - pulsf.para.pulse = 'racos'; - pulsf.process(symbols); %%%%% Pulse-forming %%%%%% if obj.applypulseform + %%% MY CODE digi_sig = obj.pulseformer.process(symbols); + + %%% MOVEIT WRAPPER BETA + % symbols.spectrum("fignum",111,"displayname","1) RAW SIGNAL"); + % + % pulsf = Moveit_wrapper('pulsef'); + % pulsf.para.alpharacos = obj.pulseformer.alpha; + % pulsf.para.f_sym = obj.fsym; + % pulsf.para.fs = obj.fsym; + % pulsf.para.pulse = 2; + % + % digi_sig = pulsf.process(symbols); + + % Design raised cosine filter with given order in symbols + % digi_sig = symbols; + % sps = 4; + % nsym = 128; + % rctFilt3 = comm.RaisedCosineTransmitFilter(... + % Shape='Square root', ... + % RolloffFactor=1, ... + % FilterSpanInSymbols=nsym, ... + % OutputSamplesPerSymbol=sps); + % + % digi_sig.signal = rctFilt3([symbols.signal; zeros(nsym/2,1)]); + % % Correct for propagation delay by removing filter transients + % fltDelay = nsym / (2*obj.fsym); + % digi_sig.signal = digi_sig.signal(fltDelay*sps*obj.fsym+1:end); + % + % digi_sig.fs = sps .* symbols.fs; + + else digi_sig = symbols; end - % digi_sig.spectrum("fignum",112,"displayname","2) after pulseforming"); %%%%% Re-sample to f DAC %%%%%% n = 10; diff --git a/Classes/Moveit_wrapper.m b/Classes/Moveit_wrapper.m index a518303..025a464 100644 --- a/Classes/Moveit_wrapper.m +++ b/Classes/Moveit_wrapper.m @@ -110,7 +110,7 @@ classdef Moveit_wrapper < handle previousLevel = currentLevel; % Determine input type from obj.comment.type - if + if 1 inputType = obj.comment.type.(fieldName); else inputType = 'number'; % Default type diff --git a/Functions/EQ_structures/duobinary_target.m b/Functions/EQ_structures/duobinary_target.m index c2d760e..d2d3671 100644 --- a/Functions/EQ_structures/duobinary_target.m +++ b/Functions/EQ_structures/duobinary_target.m @@ -9,6 +9,7 @@ arguments tx_bits options.precode_mode db_mode options.showAnalysis = 0; + options.eth_style_symbol_mapping = 0; end %Duobinary Targeting @@ -18,7 +19,7 @@ end % dir = [1,1]; mlse_sig_sd = mlse_.process(eq_signal); - mlse_sig_hd = PAMmapper(M,0).quantize(mlse_sig_sd); + mlse_sig_hd = PAMmapper(M,0,"eth_style",options.eth_style_symbol_mapping).quantize(mlse_sig_sd); % precoding to mitigate error propagation, most prominently used in % combination with duobinary signaling to avoid catastrophic error @@ -37,12 +38,12 @@ end tx_symbols_precoded = Duobinary().encode(tx_symbols); tx_symbols_precoded = Duobinary().decode(tx_symbols_precoded); - tx_bits = PAMmapper(M,0).demap(tx_symbols_precoded); + tx_bits = PAMmapper(M,0,"eth_style",options.eth_style_symbol_mapping).demap(tx_symbols_precoded); case db_mode.db_discard % normal dsp for precoded sequence == discard/omit/ignore precode - tx_bits = PAMmapper(M,0).demap(tx_symbols); + tx_bits = PAMmapper(M,0,"eth_style",options.eth_style_symbol_mapping).demap(tx_symbols); case db_mode.db_encoded @@ -56,7 +57,7 @@ end end % M = numel(unique(tx_symbols.signal)); - rx_bits = PAMmapper(M,0).demap(mlse_sig_hd); + rx_bits = PAMmapper(M,0,"eth_style",options.eth_style_symbol_mapping).demap(mlse_sig_hd); [~,numErrors,ber,~] = calc_ber(rx_bits.signal,tx_bits.signal,"skip_front",100,"skip_end",150,"returnErrorLocation",1); @@ -66,11 +67,15 @@ end if options.showAnalysis eq_noise = eq_noise - mean(eq_noise.signal); -rx_signal.spectrum("normalizeTo0dB",1,"fignum",250); + rx_signal.spectrum("normalizeTo0dB",1,"fignum",250,"displayname","Rx Spectrum"); - showEQNoisePSD(eq_noise,"fignum",250,"displayname",'Duobinary Target Noise'); + Duobinary().encode(tx_symbols).spectrum("normalizeTo0dB",1,"fignum",250,"displayname","DB encoded reference"); - Duobinary().encode(tx_symbols).spectrum("normalizeTo0dB",1,"fignum",250); + showEQNoisePSD(eq_noise,"fignum",250,"displayname",'Duobinary Target Noise after Equalization'); + + fprintf('DB tgt BER: %.2e \n',ber); + + end diff --git a/Functions/EQ_structures/vnle.m b/Functions/EQ_structures/vnle.m index 4c766fd..8905066 100644 --- a/Functions/EQ_structures/vnle.m +++ b/Functions/EQ_structures/vnle.m @@ -74,20 +74,21 @@ function [eq_package] = vnle(eq_,M,rx_signal,tx_symbols,tx_bits,options) [~,numErrors,ber,~] = calc_ber(rx_bits.signal,tx_bits.signal,"skip_front",100,"skip_end",150,"returnErrorLocation",1); [evm_total,evm_lvl] = calc_evm(eq_signal_sd,tx_symbols); [inf_rate] = calc_air(eq_signal_sd,tx_symbols,"skip_front",10000,"skip_end",10000); - snr(eq_signal_sd.signal,eq_noise.signal) eq_package.ber_vnle = ber; eq_package.evm_total = evm_total; eq_package.evm_lvl = evm_lvl; eq_package.inf_rate_vnle = inf_rate; - eq_package.snr = snr(eq_signal_sd.signal,eq_noise.signal); + eq_package.signal = eq_signal_sd; + if options.showAnalysis - snr(eq_signal_sd.signal,eq_noise.signal); + fprintf('SNR: %d dB \n',snr(eq_signal_sd.signal,eq_noise.signal)); + fprintf(['VNLE EVM lvl: ',repmat('%.3f ',1,numel(evm_lvl)),' \n'],evm_lvl); fprintf('VNLE BER: %.2e \n',ber); diff --git a/Functions/EQ_structures/vnle_postfilter_mlse.m b/Functions/EQ_structures/vnle_postfilter_mlse.m index 466e908..dc1501f 100644 --- a/Functions/EQ_structures/vnle_postfilter_mlse.m +++ b/Functions/EQ_structures/vnle_postfilter_mlse.m @@ -10,6 +10,7 @@ arguments tx_bits options.precode_mode db_mode options.showAnalysis = 0; + options.eth_style_symbol_mapping = 0; end %FFE or VNLE @@ -23,7 +24,7 @@ end % [mlse_sig_hd,mlse_sig_sd] = mlse_.process(mlse_sig_sd,tx_symbols); mlse_sig_sd = mlse_.process(mlse_sig_sd); - mlse_sig_hd = PAMmapper(M,0).quantize(mlse_sig_sd); + mlse_sig_hd = PAMmapper(M,0,"eth_style",options.eth_style_symbol_mapping).quantize(mlse_sig_sd); % precoding to mitigate error propagation, most prominently used in % combination with duobinary signaling to avoid catastrophic error @@ -46,12 +47,12 @@ end tx_symbols_precoded = Duobinary().encode(tx_symbols); tx_symbols_precoded = Duobinary().decode(tx_symbols_precoded); - tx_bits = PAMmapper(M,0).demap(tx_symbols_precoded); + tx_bits = PAMmapper(M,0,"eth_style",options.eth_style_symbol_mapping).demap(tx_symbols_precoded); case db_mode.db_discard % normal dsp for precoded sequence == discard/omit/ignore precode - tx_bits = PAMmapper(M,0).demap(tx_symbols); + tx_bits = PAMmapper(M,0,"eth_style",options.eth_style_symbol_mapping).demap(tx_symbols); case db_mode.db_encoded @@ -68,7 +69,7 @@ end end % METRICS OF VNLE % - rx_bits_vnle = PAMmapper(M,0).demap(eq_signal_hd); + rx_bits_vnle = PAMmapper(M,0,"eth_style",options.eth_style_symbol_mapping).demap(eq_signal_hd); [~,~,ber_vnle,~] = calc_ber(rx_bits_vnle.signal,tx_bits.signal,"skip_front",100,"skip_end",150,"returnErrorLocation",1); % correct TUM implementation of AIR @@ -76,7 +77,7 @@ end [evm_vnle_total,evm_vnle_lvl] = calc_evm(eq_signal_sd,tx_symbols); % METRICS OF MLSE (HD-VITERBI) - rx_bits_mlse = PAMmapper(M,0).demap(mlse_sig_hd); + rx_bits_mlse = PAMmapper(M,0,"eth_style",options.eth_style_symbol_mapping).demap(mlse_sig_hd); [~,~,ber_mlse,~] = calc_ber(rx_bits_mlse.signal,tx_bits.signal,"skip_front",100,"skip_end",150,"returnErrorLocation",1); diff --git a/projects/IMDD_base_system/imdd_it.m b/projects/IMDD_base_system/imdd_it.m index dc1779c..9b0925e 100644 --- a/projects/IMDD_base_system/imdd_it.m +++ b/projects/IMDD_base_system/imdd_it.m @@ -6,20 +6,13 @@ if 1 uloops.precomp = [0]; uloops.db_precode = [0]; uloops.bitrate = [330].*1e9; %[300,330,360,390,420,450,480] - uloops.precomp = [1]; - uloops.db_precode = [0]; - uloops.bitrate = [300,330,360,390,420,450,480].*1e9; %[300,330,360,390,420,450,480] - % uloops.bitrate = 390e9; - % uloops.laser_wavelength = [1293,1297.5,1302,1306.5,1310,1313.4,1318,1322.7,1327.4]; - uloops.laser_wavelength = [1293]; - uloops.M = [4]; uloops.laser_wavelength = [1310]; uloops.M = [6]; uloops.link_length = [2]; % 1,2,3,5,6,8,10 wh = DataStorage(uloops); wh.addStorage("ber"); - wh = submit_simulations(wh,"parallel",0,"simulation_mode",0); + wh = submit_simulations(wh,"parallel",0,"simulation_mode",1); end wh_ana = wh; diff --git a/projects/IMDD_base_system/imdd_model.m b/projects/IMDD_base_system/imdd_model.m index 5f90ddb..342b247 100644 --- a/projects/IMDD_base_system/imdd_model.m +++ b/projects/IMDD_base_system/imdd_model.m @@ -35,7 +35,7 @@ tx_bw_nyquist = 0.8; link_length = 1; % RX -rop = -8; +rop = -5; rx_bw_nyquist = 0.8; vnle_order1 = 50; @@ -61,7 +61,7 @@ mu_dfe = 0.0004; dfe_ = sum(dfe_order)>0; -doub_mode = db_mode.db_precoded; +doub_mode = db_mode.no_db; %%% change specific parameter if given in varargin % Parse optional input arguments @@ -132,10 +132,14 @@ f_nyquist = fsym/2; %%% run the simulation or measurement or ... if simulation_mode - Pform = Pulseformer("fsym",fsym,"fdac",4*fsym,"pulse","rrc","pulselength",16,"rrcalpha",rcalpha); + rcalpha = 1; + Pform = Pulseformer("fsym",fsym,"fdac",4*fsym,"pulse","rrc","pulselength",16,"alpha",rcalpha); + db_precode = 0; + db_encode = 0; + apply_pulsef = 1; [Digi_sig,Symbols,Tx_bits] = PAMsource(... - "fsym",fsym,"M",M,"order",16,"useprbs",0,... + "fsym",fsym,"M",M,"order",18,"useprbs",1,... "fs_out",fdac,... "applyclipping",0,"clipfactor",1.5,... "applypulseform",apply_pulsef,"pulseformer",Pform,... @@ -143,7 +147,7 @@ if simulation_mode "db_precode",db_precode,"db_encode",db_encode,... "mrds_code",0,"mrds_blocklength",512).process(); - % Digi_sig.spectrum("displayname",'Digi Spectrum','fignum',10,'normalizeTo0dB',1); + Digi_sig.spectrum("displayname",'Digi Spectrum','fignum',10,'normalizeTo0dB',1); %%%%% AWG % El_sig = M8199A("kover",kover).process(Digi_sig); @@ -274,6 +278,13 @@ for occ = 1:proc_occ Scpe_sig = Filter('filtdegree',4,"f_cutoff",Symbols.fs.*0.5,"fs",Scpe_sig.fs,"filterType",filtertypes.gaussian,"active",true).process(Scpe_sig); Scpe_sig = Scpe_sig - mean(Scpe_sig.signal); + % + % Pform = Pulseformer("fsym",Scpe_sig.fs,"fdac",2*fsym,"pulse","rrc","pulselength",16,"alpha",rcalpha,"matched",0); + % + % Scpe_sig_matched = Pform.process(Scpe_sig); + % + % Scpe_sig.spectrum("normalizeTo0dB",0,"fignum",336,"displayname","scope "); + % Scpe_sig_matched.spectrum("normalizeTo0dB",0,"fignum",336,"displayname","matched"); %%% EQUALIZING @@ -294,7 +305,7 @@ for occ = 1:proc_occ end %%%%% VNLE + PF + MLSE %%%% - if 1 + if 0 % len_tr = length(Symbols)-1000; eq_vnle_ = EQ("Ne",vnle_order,"Nb",dfe_order,"training_length",len_tr,"training_loops",5,"dd_loops",5,"K",2,"DCmu",mu_dc,"DDmu",[mu_ffe mu_dfe],"DFEmu",0.005,"FFEmu",0,"plotfinal",0,"ideal_dfe",1); @@ -309,7 +320,7 @@ for occ = 1:proc_occ %%%%% Duobinary Targeting %%%% - if 1 + if 0 mlse_db = MLSE_viterbi("DIR",[1,1],"duobinary_output",0,"M",M,"trellis_states",PAMmapper(M,0).levels); eq_db = EQ("Ne",vnle_order,"Nb",dfe_order,"training_length",len_tr,"training_loops",5,"dd_loops",5,"K",2,"DCmu",mu_dc,"DDmu",[mu_ffe mu_dfe],"DFEmu",0.005,"FFEmu",0,"plotfinal",0,"ideal_dfe",1); diff --git a/projects/Messung_Zürich/Pmod_-0dBm_P_PD_5p8dBm_W03C34-0409E03_128GBd_2PAM__20250217T161301.h5 b/projects/Messung_Zürich/Pmod_-0dBm_P_PD_5p8dBm_W03C34-0409E03_128GBd_2PAM__20250217T161301.h5 deleted file mode 100644 index a66cf34..0000000 Binary files a/projects/Messung_Zürich/Pmod_-0dBm_P_PD_5p8dBm_W03C34-0409E03_128GBd_2PAM__20250217T161301.h5 and /dev/null differ diff --git a/projects/Messung_Zürich/Pmod_-0dBm_P_PD_5p8dBm_W03C34-0409E03_32GBd_2PAM__20250217T161634.h5 b/projects/Messung_Zürich/Pmod_-0dBm_P_PD_5p8dBm_W03C34-0409E03_32GBd_2PAM__20250217T161634.h5 deleted file mode 100644 index c29a4a2..0000000 Binary files a/projects/Messung_Zürich/Pmod_-0dBm_P_PD_5p8dBm_W03C34-0409E03_32GBd_2PAM__20250217T161634.h5 and /dev/null differ diff --git a/projects/Messung_Zürich/Pmod_10p006dBm_P_PD_6p4732dBm_W03C34-0409E03_128GBd_4PAM__20250218T195459.h5 b/projects/Messung_Zürich/Pmod_10p006dBm_P_PD_6p4732dBm_W03C34-0409E03_128GBd_4PAM__20250218T195459.h5 deleted file mode 100755 index 483c5e4..0000000 Binary files a/projects/Messung_Zürich/Pmod_10p006dBm_P_PD_6p4732dBm_W03C34-0409E03_128GBd_4PAM__20250218T195459.h5 and /dev/null differ diff --git a/projects/Messung_Zürich/Pmod_10p01dBm_P_PD_6p4727dBm_W03C34-0409E03_160GBd_2PAM__20250218T195221.h5 b/projects/Messung_Zürich/Pmod_10p01dBm_P_PD_6p4727dBm_W03C34-0409E03_160GBd_2PAM__20250218T195221.h5 deleted file mode 100755 index 1730dcf..0000000 Binary files a/projects/Messung_Zürich/Pmod_10p01dBm_P_PD_6p4727dBm_W03C34-0409E03_160GBd_2PAM__20250218T195221.h5 and /dev/null differ diff --git a/projects/Messung_Zürich/Pmod_7p9772dBm_P_PD_6p477dBm_W03C34-0409E03_200GBd_2PAM__20250218T181515.h5 b/projects/Messung_Zürich/Pmod_7p9772dBm_P_PD_6p477dBm_W03C34-0409E03_200GBd_2PAM__20250218T181515.h5 deleted file mode 100755 index d385cd8..0000000 Binary files a/projects/Messung_Zürich/Pmod_7p9772dBm_P_PD_6p477dBm_W03C34-0409E03_200GBd_2PAM__20250218T181515.h5 and /dev/null differ diff --git a/projects/Messung_Zürich/Pmod_7p9943dBm_P_PD_6p4526dBm_W03C34-0409E03_160GBd_2PAM__20250218T181637.h5 b/projects/Messung_Zürich/Pmod_7p9943dBm_P_PD_6p4526dBm_W03C34-0409E03_160GBd_2PAM__20250218T181637.h5 deleted file mode 100755 index ee78ab4..0000000 Binary files a/projects/Messung_Zürich/Pmod_7p9943dBm_P_PD_6p4526dBm_W03C34-0409E03_160GBd_2PAM__20250218T181637.h5 and /dev/null differ diff --git a/projects/Messung_Zürich/Pmod_8p0011dBm_P_PD_6p4762dBm_W03C34-0409E03_64GBd_4PAM__20250218T181158.h5 b/projects/Messung_Zürich/Pmod_8p0011dBm_P_PD_6p4762dBm_W03C34-0409E03_64GBd_4PAM__20250218T181158.h5 deleted file mode 100755 index 9bf3ad0..0000000 Binary files a/projects/Messung_Zürich/Pmod_8p0011dBm_P_PD_6p4762dBm_W03C34-0409E03_64GBd_4PAM__20250218T181158.h5 and /dev/null differ diff --git a/projects/Messung_Zürich/Pmod_8p0023dBm_P_PD_6p4776dBm_W03C34-0409E03_64GBd_2PAM__20250218T181323.h5 b/projects/Messung_Zürich/Pmod_8p0023dBm_P_PD_6p4776dBm_W03C34-0409E03_64GBd_2PAM__20250218T181323.h5 deleted file mode 100755 index b0cdc20..0000000 Binary files a/projects/Messung_Zürich/Pmod_8p0023dBm_P_PD_6p4776dBm_W03C34-0409E03_64GBd_2PAM__20250218T181323.h5 and /dev/null differ diff --git a/projects/Messung_Zürich/Pmod_9p994dBm_P_PD_7p4733dBm_W03C34-0409E03_128GBd_4PAM__20250218T195746.h5 b/projects/Messung_Zürich/Pmod_9p994dBm_P_PD_7p4733dBm_W03C34-0409E03_128GBd_4PAM__20250218T195746.h5 deleted file mode 100755 index ba0471f..0000000 Binary files a/projects/Messung_Zürich/Pmod_9p994dBm_P_PD_7p4733dBm_W03C34-0409E03_128GBd_4PAM__20250218T195746.h5 and /dev/null differ diff --git a/projects/Messung_Zürich/dsp_all_files.m b/projects/Messung_Zürich/dsp_all_files.m new file mode 100644 index 0000000..4fcefba --- /dev/null +++ b/projects/Messung_Zürich/dsp_all_files.m @@ -0,0 +1,113 @@ + + + +M = 8; +if M == 4 + file_codes = {"20250221T032043",... + "20250221T032312",... + "20250221T032424",... + "20250221T032529",... + "20250221T032632",... + "20250221T032800",... + "20250221T032936",... + "20250221T033035",... + "20250221T033138",... + "20250221T033138",... + "20250221T033425",... + "20250221T033527",... + "20250221T033642",... + "20250221T033743",... + "20250221T033851",... + "20250221T034314",... + "20250221T034529",... + "20250221T034647",... + "20250221T034756",... + "20250221T034915",... + }; + baudrate = [96,120,128,136,144,152,160,168,172,176,180,184,188,192,196,200,204,212,220,224]; + pam4.result_vnle = result_vnle; + pam4.result_db = result_db; +elseif M ==8 + file_codes = {"20250221T004651",... %96 + "20250221T004926",... + "20250221T005844",... + "20250221T010032",... + "20250221T010150",... + "20250221T025505",...%144 ohne balun + "20250221T024629",...%152 ohne balun + "20250221T024315",...%160 ohne balun + "20250221T023534",...%168 ohne balun + "20250221T024929",...%172 ohne balun + "20250221T025305",...%176 ohne balun + }; + file_codes = {"20250221T004651"}; + baudrate = [96,112,120,128,136,144,152,160,168,172,176]; +end + +if 1 + + uloops = struct; + uloops.filecode = file_codes; + uloops.tcorrect = [0]; + wh = DataStorage(uloops); + wh.addStorage("ber"); + + wh = submit_handle(@dsp_ief_file,wh,"parallel",0); +end + +a = wh.getStoValue('ber',uloops.filecode, uloops.tcorrect); + +% get best results per baudrate +% ber_vnle_values = cellfun(@(a) cellfun(@(y) y.ber_vnle, a.vnle_package, 'UniformOutput', false), a, 'UniformOutput', false); +% best_vnle = cellfun(@(x) min(cell2mat(x)), ber_vnle_values); + +ber_vnle_values = cellfun(@(a) cellfun(@(y) y.ber_vnle, a.vnle_pf_package, 'UniformOutput', false), a, 'UniformOutput', false); +best_vnle = cellfun(@(x) min(cell2mat(x)), ber_vnle_values); + +ber_mlse_values = cellfun(@(a) cellfun(@(y) y.ber_mlse, a.vnle_pf_package, 'UniformOutput', false), a, 'UniformOutput', false); +best_mlse = cellfun(@(x) min(cell2mat(x)), ber_mlse_values); + +%%% PLOT PARAMETER OPTIMIZATION +figure() +cols = cbrewer2('Set1',6); +hold on +title(sprintf('%d km | %d nm | PAM %d',1,1313.5,M)); +xax = uloops.tcorrect; +plot(xax,best_vnle,'DisplayName',sprintf('VNLE'),'Color',cols(1,:),'LineStyle','-','HandleVisibility','on'); + +plot(xax,best_mlse,'DisplayName',sprintf('VNLE + 1 tap post-filter + MLSE'),'Color',cols(2,:),'LineStyle','-','HandleVisibility','on'); + +% plot(xax,best_db,'DisplayName',sprintf('DB tgt. + MLSE'),'Color',cols(3,:),'LineStyle','-','HandleVisibility','on'); + +set(gca, 'YScale', 'log'); +ylim([5e-5 0.3]); +xlim([min(xax), max(xax) ]); +yline([3.8e-3, 2e-2],'HandleVisibility','off'); +legend +beautifyBERplot() +xlabel('Number 1st order taps'); +ylabel('BER'); + + + + +%%% PLOT COMPLETE BAUDRATE +figure(20) +cols = cbrewer2('Set1',6); +hold on +title(sprintf('%d km | %d nm | PAM %d',1,1313.5,M)); + +plot(baudrate,best_vnle,'DisplayName',sprintf('VNLE'),'Color',cols(1,:),'LineStyle','-','HandleVisibility','on'); + +plot(baudrate,best_mlse,'DisplayName',sprintf('VNLE + 1 tap post-filter + MLSE'),'Color',cols(2,:),'LineStyle','-','HandleVisibility','on'); + +plot(baudrate,best_db,'DisplayName',sprintf('DB tgt. + MLSE'),'Color',cols(3,:),'LineStyle','-','HandleVisibility','on'); + +set(gca, 'YScale', 'log'); +ylim([5e-5 0.3]); +xlim([min(baudrate), max(baudrate) ]); +yline([3.8e-3, 2e-2],'HandleVisibility','off'); +legend +beautifyBERplot() +xlabel('Bit Rate in Gbps'); +ylabel('BER'); diff --git a/projects/Messung_Zürich/dsp_ief_file.m b/projects/Messung_Zürich/dsp_ief_file.m index 28946ea..90d7d2e 100644 --- a/projects/Messung_Zürich/dsp_ief_file.m +++ b/projects/Messung_Zürich/dsp_ief_file.m @@ -1,91 +1,161 @@ -% Get the script folder -scriptFolder = fileparts(mfilename('fullpath')); +function [results] = dsp_ief_file(varargin) + + mu_ffe1 = 0.0001; + mu_ffe2 = 0.0008; + mu_ffe3 = 0.001; + mu_dc = 0.005; + + mu_dfe = 0.0004; + vnle_order1 = 50; + vnle_order2 = 3; + vnle_order3 = 3; + + + tcorrect = 0; + %%% change specific parameter if given in varargin + % Parse optional input arguments + if ~isempty(varargin) + var_s = varargin{1}; + if isstruct(var_s) + fields = fieldnames(var_s); + for i = 1:numel(fields) + if isnumeric(fields{i}) + eval([fields{i}, ' = ', num2str( var_s.(fields{i}) ), ';']); + fprintf("%s <-- %.2f \n", fields{i}, var_s.(fields{i})); + else + eval([fields{i}, ' = ', 'var_s.(fields{',num2str(i),'})' , ';']); + end + + end + else + error('Optional variables should be passed as a struct.'); + end + end + + ssdPath = "D:\36_IMDD_Kiel\Data"; + % code = "20250221T004802"; + % code = "20250221T032043"; + filename = findFileByCode(ssdPath, filecode{1}); + + % Extract parameters from the filename using an updated regex + tokens = regexp(filename, 'Pmod_([-0-9p]+)dBm_P_PD_([-0-9p]+)dBm_.*?_(\d+)GBd_(\d+)PAM__\d+T\d+', 'tokens'); + if isempty(tokens) + error('Filename format not recognized.'); + end + + tokens = tokens{1}; + + % Convert values + config.P_laser = str2double(strrep(tokens{1}, 'p', '.')); + config.P_pd = str2double(strrep(tokens{2}, 'p', '.')); + config.fsym = str2double(tokens{3}) * 1e9; % Convert GBd to Hz + config.M = str2double(tokens{4}); + + % Display results + fprintf('Loaded file: %s\n', filename); + fprintf('P_laser: %.3f dBm\n', config.P_laser); + fprintf('P_pd: %.3f dBm\n', config.P_pd); + fprintf('fsym: %.1f GBd\n', config.fsym*1e-9); + fprintf('M: %d\n', config.M); + + %%% Load Data + filepath = fullfile(filename); + ief_ = h5info(filepath); + + config.fs_rx = h5readatt(filepath,'/','fs'); %sampling frequency at Rx + config.fs_tx = h5readatt(filepath, '/','fs_Tx'); %sampling frequency at Tx + config.fsym = h5readatt(filepath, '/','R'); %Baudrate + config.M = h5readatt(filepath, '/','M'); % PAM- 'M' + config.ROF = h5readatt(filepath, '/','ROF'); + config.PulseShape =h5readatt(filepath, '/','PulseShape'); + + yOrg = h5readatt(filepath, ief_.Groups(4).Groups(1).Name, 'YOrg'); + yInc = h5readatt(filepath, ief_.Groups(4).Groups(1).Name, 'YInc'); + + + dataRx = double(h5read(filepath, '/Waveforms/Channel 2/Channel 2Data')); % rohdaten des CH4 + bitsTx = h5read(filepath, '/Settings/dataTx'); %Binär + bitsTx = reshape(bitsTx,log2(config.M),[])'; + + %%% Build Tx Signal (Bits, Pam Map, Symbols) + Tx_bits = Informationsignal(bitsTx); + Tx_symbols = PAMmapper(config.M,0,"eth_style",1).map(Tx_bits); + Tx_symbols.fs = config.fsym; + + %%% Build Rx Signal (Rx, normalize,remove mean) + dataRx = dataRx*yInc+yOrg; + Rx_Sig = Informationsignal(dataRx,"fs",config.fs_rx); + Rx_Sig = Rx_Sig.normalize("mode","rms"); + + % Rx_Sig.spectrum("fignum",3,"displayname",'Rx Signal','normalizeTo0dB',0); + + Rx_Sig = Filter('filtdegree',6,"f_cutoff",Tx_symbols.fs.*0.9,"fs",Rx_Sig.fs,"filterType",filtertypes.gaussian,"active",true).process(Rx_Sig); + + % Rx_Sig.spectrum("fignum",3,"displayname",'Rx Signal filt','normalizeTo0dB',0); + + Rx_Sig = Rx_Sig.delay(tcorrect,"mode","samples"); + + %%%%%% Sample to 2x fsym %%%%%% + Rx_Sig_resamp = Rx_Sig.resample("fs_out",2*config.fsym); + + %%%%%% Sync Rx signal with reference (S is a cell array with all occurences) %%%%%% + [Rx_Sig_sync,S,isFlipped] = Rx_Sig_resamp.tsynch("reference",Tx_symbols,"fs_ref",config.fsym,"debug_plots",0); + + % Rx_Sig_sync.eye(fsym,M,"fignum",4,"displayname",'eye diagram'); + + + % timing syncroization ?? + % filter Bw + output = struct(); + vnle_package = {}; + vnle_pf_package = {}; + dbtgt_package = {}; + + for s = 1:length(S) + Rx_Sig_sync = S{s}; + + Rx_Sig_sync.spectrum("fignum",3,"displayname",'No Matched Filter','normalizeTo0dB',0); + + mu_ffe = [mu_ffe1 mu_ffe3 mu_ffe3]; + vnle_order=[vnle_order1,vnle_order2,vnle_order3]; + eq_ = EQ("Ne",vnle_order,"Nb",[0,0,0],"training_length",4096*2,"training_loops",5,"dd_loops",5,"K",2,"DCmu",mu_dc,"DDmu",[mu_ffe mu_dfe],"DFEmu",0.005,"FFEmu",0,"plotfinal",0,"ideal_dfe",1); + + %%%%% VNLE only (or DFE) %%%% + if 0 + + [result] = vnle(eq_,config.M,Rx_Sig_sync,Tx_symbols,Tx_bits,"precode_mode",db_mode.no_db,"showAnalysis",1,'eth_style',1); + vnle_package{s} = result; + end + + %%%%% VNLE + PF + MLSE %%%% + if 0 + + pf_ = Postfilter("ncoeff",1,"useBurg",1); + mlse_ = MLSE_viterbi("duobinary_output",0,'M',config.M,'trellis_states',PAMmapper(config.M,0).levels); + doub_mode = db_mode.no_db; + + [result] = vnle_postfilter_mlse(eq_,pf_,mlse_,config.M,Rx_Sig_sync,Tx_symbols,Tx_bits,"precode_mode",doub_mode,'showAnalysis',1,'eth_style_symbol_mapping',1); + vnle_pf_package{s} = result; + + end + + %%%%% Duobinary Targeting %%%% + if 1 + + mlse_db = MLSE_viterbi("DIR",[1,1],"duobinary_output",0,"M",config.M,"trellis_states",PAMmapper(config.M,0).levels); + doub_mode = db_mode.db_emulate; + + [result] = duobinary_target(eq_, mlse_db, config.M, Rx_Sig_sync, Tx_symbols, Tx_bits, "precode_mode", doub_mode,'showAnalysis',1,'eth_style_symbol_mapping',1); + dbtgt_package{s} = result; + + end + + end + + results.vnle_package = vnle_package; + results.vnle_pf_package = vnle_pf_package; + results.dbtgt_package = dbtgt_package; + -% Find the HDF5 file in the folder -files = dir(fullfile(scriptFolder, '*.h5')); -if isempty(files) - error('No HDF5 files found in the script folder.'); end - -% Select the first matching file (modify as needed) -filename = files(6).name; -% filename = 'Pmod_8p0023dBm_P_PD_6p4776dBm_W03C34-0409E03_64GBd_2PAM__20250218T181323.h5'; - -% Extract parameters from the filename using an updated regex -tokens = regexp(filename, 'Pmod_([-0-9p]+)dBm_P_PD_([-0-9p]+)dBm_.*?_(\d+)GBd_(\d+)PAM__\d+T\d+', 'tokens'); -if isempty(tokens) - error('Filename format not recognized.'); -end - -tokens = tokens{1}; - -% Convert values -P_laser = str2double(strrep(tokens{1}, 'p', '.')); -P_pd = str2double(strrep(tokens{2}, 'p', '.')); -fsym = str2double(tokens{3}) * 1e9; % Convert GBd to Hz -M = str2double(tokens{4}); - -% Display results -fprintf('Loaded file: %s\n', filename); -fprintf('P_laser: %.3f dBm\n', P_laser); -fprintf('P_pd: %.3f dBm\n', P_pd); -fprintf('fsym: %.3f Hz\n', fsym); -fprintf('M: %d\n', M); - -%%% Load Data -folder = "/Users/silasoettinghaus/Documents/MATLAB/imdd_simulation/projects/Messung_Zürich"; - -filepath = fullfile(folder,filename); -ief_ = h5info(filepath); - -fs_rx = h5readatt(filepath,'/','fs'); %sampling frequency at Rx -fs_tx = h5readatt(filepath, '/','fs_Tx'); %sampling frequency at Tx -fsym = h5readatt(filepath, '/','R'); %Baudrate -M = h5readatt(filepath, '/','M'); % PAM- 'M' -ROF = h5readatt(filepath, '/','ROF'); -PulseShape =h5readatt(filepath, '/','PulseShape'); - -yOrg = h5readatt(filepath, ief_.Groups(4).Groups(1).Name, 'YOrg'); -yInc = h5readatt(filepath, ief_.Groups(4).Groups(1).Name, 'YInc'); - -plotDisplayName = sprintf('P_{cw} = %.3f dBm, P_{PD} = %.3f dBm, f_{sym} = %.3f GBd, M = %d', ... - P_laser, P_pd, fsym / 1e9, M); - -dataRx = double(h5read(filepath, '/Waveforms/Channel 2/Channel 2Data')); % rohdaten des CH4 -bitsTx = h5read(filepath, '/Settings/dataTx'); %Binär -bitsTx = reshape(bitsTx,log2(M),[])'; - - -%%% Build Tx Signal (Bits, Pam Map, Symbols) -Tx_bits = Informationsignal(bitsTx); -Tx_symbols = PAMmapper(M,0,"eth_style",1).map(Tx_bits); -Tx_symbols.fs = fsym; -% Tx_symbols.plot("fignum",1,"displayname",'Rx Signal'); -% Tx_symbols.move_it_spectrum("fignum",2,"displayname",'tx spectrum'); -% Tx_symbols.spectrum("fignum",3,"displayname",'Rx Signal','normalizeTo0dB',0); - - -%%% Build Rx Signal (Rx, normalize,remove mean) -dataRx = dataRx*yInc+yOrg; -Rx_Sig = Informationsignal(dataRx,"fs",fs_rx); -Rx_Sig = Rx_Sig.normalize("mode","rms"); -% Rx_Sig.power(); -% Rx_Sig.eye(fsym,M,"fignum",4,"displayname",'eye diagram'); -% Rx_Sig.plot("fignum",5,"displayname",'Rx Signal'); -% Rx_Sig.move_it_spectrum("fignum",6,"displayname",'tx spectrum'); -Rx_Sig.spectrum("fignum",3,"displayname",'Rx Signal','normalizeTo0dB',0); - -%%%%%% Sample to 2x fsym %%%%%% -Rx_Sig_resamp = Rx_Sig.resample("fs_out",2*fsym); - -%%%%%% Sync Rx signal with reference (S is a cell array with all occurences) %%%%%% -[Rx_Sig_sync,S,isFlipped] = Rx_Sig_resamp.tsynch("reference",Tx_symbols,"fs_ref",fsym,"debug_plots",0); - -eq_vnle_dfe = EQ("Ne",[50,7,7],"Nb",[0,0,0],"training_length",4096*2,"training_loops",5,"dd_loops",5,"K",2,"DCmu",0.05,"DDmu",[0.0004 0.0004 0.0004 0.0004 ],"DFEmu",0.005,"FFEmu",0,"plotfinal",1,"ideal_dfe",0); - -[result] = vnle(eq_vnle_dfe,M,Rx_Sig_sync,Tx_symbols,Tx_bits,"precode_mode",db_mode.no_db,"showAnalysis",1,'eth_style',1); - - - - diff --git a/projects/Messung_Zürich/findFileByCode.m b/projects/Messung_Zürich/findFileByCode.m new file mode 100644 index 0000000..7fd9eb4 --- /dev/null +++ b/projects/Messung_Zürich/findFileByCode.m @@ -0,0 +1,40 @@ +function fileName = findFileByCode(folderPath, code) +% FINDFILEBYCODE Searches for a file in a folder structure by a given code. +% fileName = findFileByCode(folderPath, code) searches recursively in +% folderPath for a file containing 'code' in its name and returns the +% full file name if found. +% +% Inputs: +% folderPath - The root directory to search in +% code - The unique code to search for in file names +% +% Output: +% fileName - The full file name if found, empty if not found + + % Initialize output + fileName = ''; + + % Get list of all files and folders in the folderPath + files = dir(folderPath); + + % Iterate through the list + for i = 1:length(files) + % Skip '.' and '..' + if files(i).isdir + if ~startsWith(files(i).name, '.') % Avoid hidden folders + % Recursive search in subdirectories + subFolder = fullfile(folderPath, files(i).name); + fileName = findFileByCode(subFolder, code); + if ~isempty(fileName) + return; % Stop searching if found + end + end + else + % Check if the file name contains the code + if contains(files(i).name, code) + fileName = fullfile(folderPath, files(i).name); + return; + end + end + end +end diff --git a/projects/Messung_Zürich/pam4.mat b/projects/Messung_Zürich/pam4.mat new file mode 100644 index 0000000..0b9e57d Binary files /dev/null and b/projects/Messung_Zürich/pam4.mat differ diff --git a/projects/Messung_Zürich/pam4_eq.fig b/projects/Messung_Zürich/pam4_eq.fig new file mode 100644 index 0000000..68e2e79 Binary files /dev/null and b/projects/Messung_Zürich/pam4_eq.fig differ diff --git a/projects/Messung_Zürich/submit_handle.m b/projects/Messung_Zürich/submit_handle.m new file mode 100644 index 0000000..2c5e710 --- /dev/null +++ b/projects/Messung_Zürich/submit_handle.m @@ -0,0 +1,69 @@ +function wh = submit_handle(funcHandle, wh, options) + +arguments + funcHandle + wh + options.parallel = 1; +end + +%%% 2) SUBMIT SIMULATION +% Initialize job results +if options.parallel + curpool = gcp('nocreate'); + if isempty(curpool) + parpool; + else + % stop all forgotten or unfetched jobs from queue + if ~isempty(curpool.FevalQueue.QueuedFutures) || ~isempty(curpool.FevalQueue.RunningFutures) + oldq = length(curpool.FevalQueue.QueuedFutures) + length(curpool.FevalQueue.RunningFutures); + curpool.FevalQueue.cancelAll + fprintf('Canceled %d unfetched jobs from old queue.', oldq); + end + end + results = parallel.FevalFuture.empty(); +else + results = []; +end + +fprintf('Requested %d loops\n', wh.getLastLinIndice); + +for lin_idx = 1:wh.getLastLinIndice + optionalVars = struct(); + + if ~isempty(wh.getDimension) + % Build the optionalVars struct + [parametervalues, parameternames] = wh.getPhysIndicesByLinIndex(lin_idx); + for pidx = 1:numel(parameternames) + optionalVars.(parameternames{pidx}) = parametervalues{pidx}; + end + end + + %%% SIMULATION HERE + if options.parallel + numOutputs = 1; + results(lin_idx) = parfeval(funcHandle, numOutputs, optionalVars); + else + finalresults{lin_idx} = feval(funcHandle, optionalVars); + wh.addValueToStorageByLinIdx(finalresults{lin_idx}, 'ber', lin_idx); + end +end + +if options.parallel + %%% 4) Setup waitbar + h = waitbar(0, 'Processing Simulations...'); + updateWaitbar = @(~) waitbar(mean(arrayfun(@(f) strcmp(f.State, 'finished'), results)), h); + + fprintf('Fetching results... \n'); + + updateWaitbarFutures = afterEach(results, updateWaitbar, 0); + afterAll(updateWaitbarFutures, @(~) delete(h), 0); + + %%% 7) Fetch final results after all computations + fetchOutputs(results); + + for ridx = 1:length(results) + wh.addValueToStorageByLinIdx(results(ridx).OutputArguments{1}, 'ber', ridx); + end +end + +end