From 56b48095db6ea32fb6276304ecc04cef36553c80 Mon Sep 17 00:00:00 2001 From: Silas Oettinghaus Date: Wed, 29 Apr 2026 10:17:09 +0200 Subject: [PATCH] PR stuff --- .vscode/launch.json | 12 ++ Classes/01_transmit/PAMsource.m | 10 +- Classes/01_transmit/Signalgenerator.m | 22 +-- Classes/04_DSP/Coding/Partialresponse.m | 23 ++- Functions/EQ_visuals/showLevelHistogram.m | 2 +- .../signalgenerator_pam_ber_minimal_example.m | 8 +- .../Auswertung_JLT/run_dsp_from_db.m | 10 +- .../Precoding_analysis/precode_imdd_system.m | 139 +++++++++++------- 8 files changed, 142 insertions(+), 84 deletions(-) create mode 100644 .vscode/launch.json diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..ee7370d --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,12 @@ +{ + // Verwendet IntelliSense zum Ermitteln möglicher Attribute. + // Zeigen Sie auf vorhandene Attribute, um die zugehörigen Beschreibungen anzuzeigen. + // Weitere Informationen finden Sie unter https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "type": "matlab", + "name": "Debug MATLAB" + } + ] +} \ No newline at end of file diff --git a/Classes/01_transmit/PAMsource.m b/Classes/01_transmit/PAMsource.m index d29f7f7..90eccbd 100644 --- a/Classes/01_transmit/PAMsource.m +++ b/Classes/01_transmit/PAMsource.m @@ -136,6 +136,7 @@ classdef PAMsource %%%%%% Duobinary %%%%%%%%%%% + % this is translation from user input to db_mode which was added later... "precode" und "encode" sind auch besser zu verstehen an dieser stelle daher hab ichs gelassen if obj.db_precode obj.duobinary_mode = db_mode.db_precoded; end @@ -148,10 +149,13 @@ classdef PAMsource case db_mode.no_db case db_mode.db_precoded - symbols = Duobinary().precode(symbols); + % symbols = Duobinary().precode(symbols); + symbols = Partialresponse().precode(symbols); case db_mode.db_encoded - symbols = Duobinary().precode(symbols); - symbols = Duobinary().encode(symbols); + % symbols = Duobinary().precode(symbols); + % symbols = Duobinary().encode(symbols); + symbols = Partialresponse().precode(symbols); + symbols = Partialresponse().encode(symbols); end diff --git a/Classes/01_transmit/Signalgenerator.m b/Classes/01_transmit/Signalgenerator.m index 63e2005..74df24e 100644 --- a/Classes/01_transmit/Signalgenerator.m +++ b/Classes/01_transmit/Signalgenerator.m @@ -191,8 +191,9 @@ classdef Signalgenerator % PAMsource behavior. If length is omitted, it sets the % output length. Internally it is converted to the PRMS % order per stream. - % Default output length is 2^(order-1), except for - % PAM-6-style dimension = 5 where it is 2^(order-2). + % Default output length is 2^(order-1) for all mapper + % shapes. PAM-6 still reduces the internal PRMS order + % to keep the register length manageable. % skip Number of PRMS symbols to advance before output. This % is useful when different blocks should use shifted % sections of the same deterministic sequence. @@ -275,6 +276,10 @@ classdef Signalgenerator switch obj.form case {signalform.random, signalform.prms} if obj.is_pam6_shape() + % PAM-6 consumes 5 input bits for 2 output symbols. + % To keep the symbol count aligned with the other + % PAM formats, reduce the number of generated rows + % before flattening to the mapper-ready bit vector. length = 2^max(0, obj.order - 2); else length = 2^max(0, obj.order - 1); @@ -291,19 +296,16 @@ classdef Signalgenerator end function prms_order = internal_prms_order(obj) - bits_per_symbol = obj.prms_bits_per_symbol(); + bits_per_symbol = obj.prms_parallel_width(); prms_order = max(1, floor(obj.order / bits_per_symbol)); end - function bits_per_symbol = prms_bits_per_symbol(obj) - if (~isempty(obj.M) && obj.M == 6) || (isempty(obj.M) && obj.dimension == 5) - % PAM-6 mapping in this repo consumes 5 bits for 2 symbols. - bits_per_symbol = 2.5; - elseif ~isempty(obj.M) - bits_per_symbol = log2(obj.M); + function width = prms_parallel_width(obj) + if ~isempty(obj.M) + width = obj.mapper_bit_dimension(); else - bits_per_symbol = obj.dimension; + width = obj.dimension; end end diff --git a/Classes/04_DSP/Coding/Partialresponse.m b/Classes/04_DSP/Coding/Partialresponse.m index 1e91cf3..0854d1c 100644 --- a/Classes/04_DSP/Coding/Partialresponse.m +++ b/Classes/04_DSP/Coding/Partialresponse.m @@ -2,16 +2,21 @@ classdef Partialresponse %PARTIALRESPONSE Generalized symbol-domain partial-response coding. properties + M = [] order = 1 end methods - function obj = Partialresponse(varargin) - parser = inputParser; - parser.addParameter("order", 1); - parser.parse(varargin{:}); + function obj = Partialresponse(options) + arguments + options.M = []; + options.order = 1; + end - obj.order = parser.Results.order; + fn = fieldnames(options); + for n = 1:numel(fn) + obj.(fn{n}) = options.(fn{n}); + end end function signal = precode(obj, signal, options) @@ -134,13 +139,19 @@ classdef Partialresponse end end - function M = resolveM(~, data, M) + function M = resolveM(obj, data, M) + if isempty(M) + M = obj.M; + end if isempty(M) M = numel(unique(round(data, 12))); end end function M = resolveEncodedM(obj, data, M) + if isempty(M) + M = obj.M; + end if isempty(M) I = numel(unique(round(data, 12))); if obj.order == 1 diff --git a/Functions/EQ_visuals/showLevelHistogram.m b/Functions/EQ_visuals/showLevelHistogram.m index 50fedc4..5d96767 100644 --- a/Functions/EQ_visuals/showLevelHistogram.m +++ b/Functions/EQ_visuals/showLevelHistogram.m @@ -36,7 +36,7 @@ end received_sd(lvl,ref_symbols==constellation(lvl)) = eq_signal(ref_symbols==constellation(lvl)); end - scaling = PAMmapper(numel(constellation),0).get_scaling; + % scaling = PAMmapper(numel(constellation),0).get_scaling; %%% FFE histogram clf diff --git a/Theory/Mapping_Coding/signalgenerator_pam_ber_minimal_example.m b/Theory/Mapping_Coding/signalgenerator_pam_ber_minimal_example.m index 559a844..8de0c4b 100644 --- a/Theory/Mapping_Coding/signalgenerator_pam_ber_minimal_example.m +++ b/Theory/Mapping_Coding/signalgenerator_pam_ber_minimal_example.m @@ -6,10 +6,10 @@ repoRoot = fileparts(fileparts(fileparts(mfilename("fullpath")))); addpath(genpath(repoRoot)); orders = [2 4 6 8]; -userOrder = 7; +userOrder = 18; -fprintf("PAM | bits checked | errors | BER\n"); -fprintf("----+--------------+--------+-----\n"); +fprintf("PAM | bits shape |symbols shape | bits checked | errors | BER\n"); +fprintf("----+--------------+----------------+--------------+------\n"); for M = orders bitSignal = Signalgenerator( ... @@ -23,5 +23,5 @@ for M = orders [checkedBits, errors, ber] = calc_ber(rxBits.signal, bitSignal.signal); - fprintf("%3d | %12d | %6d | %.1e\n", M, checkedBits, errors, ber); + fprintf("%3d | %3d x %3d |%3d x %3d | %12d | %6d | %.1e\n", M, size(bitSignal.signal, 1),size(bitSignal.signal, 2),size(txSymbols.signal, 1),size(txSymbols.signal, 2), checkedBits, errors, ber); end diff --git a/projects/Advanced_DSP_for_400G_IMDD_experiments/Auswertung_JLT/run_dsp_from_db.m b/projects/Advanced_DSP_for_400G_IMDD_experiments/Auswertung_JLT/run_dsp_from_db.m index 4c5b040..730c410 100644 --- a/projects/Advanced_DSP_for_400G_IMDD_experiments/Auswertung_JLT/run_dsp_from_db.m +++ b/projects/Advanced_DSP_for_400G_IMDD_experiments/Auswertung_JLT/run_dsp_from_db.m @@ -2,7 +2,7 @@ dsp_options.append_to_db = 0; dsp_options.max_occurences = 1; -experiment = "highspeed_2024"; +experiment = "highspeed_2024"; dsp_options.mode = "load_run_id"; % 'simulate' & 'load_files' dsp_options.load_file_path = struct(); @@ -11,10 +11,12 @@ if dsp_options.mode == "load_run_id" if experiment == "highspeed_2024" dsp_options.database_type = "mysql"; - dsp_options.dataBase = 'labor_highspeed';%'C:\Users\Silas\Documents\MATLAB\Datensätze\sioe_labor\silas_labor_newdsp_newstructure.db'; - dsp_options.storage_path = 'Z:\2024\sioe_labor\'; + dsp_options.dataBase = 'labor_highspeed';%'C:\Users\Silas\Documents\MATLAB\Datensätze\sioe_labor\silas_labor_newdsp_newstructure.db'; + dsp_options.storage_path = 'W:\labdata\sioe_labor\'; db = DBHandler("dataBase", [dsp_options.dataBase],... - "type", dsp_options.database_type,"server","134.245.243.254","user","silas","password","silas"); + "type", dsp_options.database_type,... + "server","192.168.178.192",...% "server","134.245.243.254",... + "user","silas","password","silas"); elseif experiment == "mpi_ecoc_2025" diff --git a/projects/Precoding_analysis/precode_imdd_system.m b/projects/Precoding_analysis/precode_imdd_system.m index 919cd7e..0df9c14 100644 --- a/projects/Precoding_analysis/precode_imdd_system.m +++ b/projects/Precoding_analysis/precode_imdd_system.m @@ -1,7 +1,7 @@ % minimal example IM/DD M = 4; -fsym = 112e9; +fsym = 160e9; apply_pulsef = 1; fdac = 256e9; @@ -50,21 +50,34 @@ mu_dc = 0.005; mu_ffe = [mu_ffe1 mu_ffe3 mu_ffe3]; mu_dfe = 0.0004; +sf = signalform.prms; +Tx_bits = Signalgenerator( ... + "form", sf, ... + "M", M, ... + "order", 16).process(); -Pform = Pulseformer("fsym",fsym,"fdac",4*fsym,"pulse","rrc","pulselength",16,"alpha",rcalpha); +Symbols = PAMmapper(M,0).map(Tx_bits); +Symbols.fs = fsym; + +Symbols_plain = Symbols; + +pr = Partialresponse("order", 1,"M",M); +Symbols = pr.precode(Symbols); + +pform = Pulseformer("fsym",fsym,"fdac",4*fsym,"pulse","rc","pulselength",16,"alpha",rcalpha); +Digi_sig = pform.process(Symbols); + +n = 10; +Digi_sig = Digi_sig.resample("fs_in",Digi_sig.fs,"fs_out",fdac,"n",n,"beta",5); -[Digi_sig,Symbols,Tx_bits] = PAMsource(... - "fsym",fsym,"M",M,"order",18,"useprbs",0,... - "fs_out",fdac,... - "applyclipping",0,"clipfactor",1.5,... - "applypulseform",apply_pulsef,"pulseformer",Pform,... - "randkey",random_key,... - 'duobinary_mode',duob_mode,... - "mrds_code",0,"mrds_blocklength",512).process(); %%%%% AWG -% El_sig = M8199A("kover",kover).process(Digi_sig); -El_sig = AWG("fdac",fdac,"f_cutoff",fsym,"lpf_active",0,"kover",kover,"bit_resolution",12,"upsampling_method","samplehold","precomp_sinc_rolloff",1).process(Digi_sig); +El_sig = M8199A("kover",kover).process(Digi_sig); +% El_sig = AWG("fdac",fdac,"f_cutoff",fsym*0.4,"lpf_active",1,"kover",kover,"bit_resolution",12,"upsampling_method","samplehold","precomp_sinc_rolloff",1).process(Digi_sig); +tx_bwl = fsym*0.3; +El_sig = Filter('filtdegree',4,"f_cutoff",tx_bwl,"fs",fdac*kover,"filterType",filtertypes.butterworth,"active",true).process(El_sig); + + El_sig.spectrum("displayname",'Digi Spectrum','fignum',1,'normalizeTo0dB',1); xlim([0,130]); ylim([-30,5]); @@ -73,7 +86,7 @@ ylim([-30,5]); %%%%% Electrical Driver Amplifier %%%%%% % El_sig = Amplifier("amp_mode","ideal_no_noise","gain_mode","gain","amplification_db",3).process(El_sig); El_sig = El_sig.normalize("mode","oneone"); -scaling = 0.6*(u_pi/2-abs(vbias-u_pi/2)); +scaling = 0.8*(u_pi/2-abs(vbias-u_pi/2)); El_sig = El_sig .* scaling; %%%%% MODULATE E/O CONVERSION %%%%%% @@ -109,29 +122,63 @@ Scpe_sig = Scope("fsimu",fdac*kover,"fadc",fadc,... % 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!? -Pform = Pulseformer("fsym",fsym,"fdac",2*fsym,"pulse","rrc","pulselength",16,"alpha",rcalpha,"matched",1); -Scpe_sig = Pform.process(Scpe_sig); -Scpe_sig.spectrum("displayname",'Signal after matched filter','fignum',1,'normalizeTo0dB',1); +if 0 + Pform = Pulseformer("fsym",fsym,"fdac",2*fsym,"pulse","rrc","pulselength",16,"alpha",rcalpha,"matched",1); + Scpe_sig = Pform.process(Scpe_sig); +end +% Scpe_sig.spectrum("displayname",'Signal after matched filter','fignum',1,'normalizeTo0dB',1); % % %% % %%%%%% Sample to 2x fsym %%%%%% -% Scpe_sig = Scpe_sig.resample("fs_out",2*fsym); -% Scpe_sig.signal = Scpe_sig.signal(1:2*length(Symbols)); +Scpe_sig = Scpe_sig.resample("fs_out",2*fsym); +Scpe_sig.signal = Scpe_sig.signal(1:2*length(Symbols)); %% %%%%%% Sync Rx signal with reference %%%%%% -[Scpe_sig,~] = Scpe_sig.tsynch("reference",Symbols,"fs_ref",fsym,"debug_plots",1); -Scpe_sig.spectrum("displayname",'Opt Spectrum','fignum',11,'normalizeTo0dB',1); +[Scpe_sig,~] = Scpe_sig.tsynch("reference",Symbols,"fs_ref",fsym,"debug_plots",0); +% Scpe_sig.spectrum("displayname",'Opt Spectrum','fignum',11,'normalizeTo0dB',1); % 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); Scpe_sig.signal = Scpe_sig.signal(1:2*length(Symbols)); -%% +%% -------------------- MLSE -------------------- +mlse_ = MLSE("DIR",[1,1],"duobinary_output",0,"M",M,'trellis_states',PAMmapper(M,0).levels); +ffe_order = [50, 2, 2]; +eq_ = EQ("Ne",ffe_order,"Nb",[0,0,0],"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); -% -------------------- FFE -------------------- +%Duobinary Targeting +db_ref_sequence = Duobinary().encode(Symbols); + +[eq_signal, eq_noise] = eq_.process(Scpe_sig,db_ref_sequence); + +showLevelHistogram(eq_signal,db_ref_sequence) + +[mlse_sig_sd,LLR,GMI_MLSE] = mlse_.process(eq_signal,Symbols); + +Rx_bits = PAMmapper(M,0).demap(mlse_sig_sd); + +Tx_bits_omitprecode = PAMmapper(M,0).demap(Symbols); +[bits,errors,ber_wo,errorIndice] = calc_ber(Rx_bits.signal,Tx_bits_omitprecode.signal); +fprintf(["BER w/o precode: %.2d \n"],ber_wo); +showErrorBurstCount(mlse_sig_sd, Symbols,"displayname",'MLSE DB w/o Precode','fignum',4); % prior to coding + +%% +mlse_sig_sd = pr.encode(mlse_sig_sd); +mlse_sig_sd = pr.decode(mlse_sig_sd); +Rx_bits = PAMmapper(M,0).demap(mlse_sig_sd); + +[bits,errors,ber,errorIndice] = calc_ber(Rx_bits.signal,Tx_bits.signal); +fprintf(["BER w/ precode: %.2d \n"],ber); + +showErrorBurstCount(mlse_sig_sd, Symbols_plain,"displayname",'MLSE DB w/ Precode','fignum',5); + + + +%% -------------------- FFE -------------------- ffe_order = [50, 0, 0]; eq_ = EQ("Ne",ffe_order,"Nb",[2,0,0], ... "training_length",len_tr,"training_loops",5,"dd_loops",5, ... @@ -139,44 +186,24 @@ eq_ = EQ("Ne",ffe_order,"Nb",[2,0,0], ... "FFEmu",0,"plotfinal",0,"ideal_dfe",0); % eq_ = FFE("epochs_tr",4,"epochs_dd",5,"len_tr",4096,"mu_dd",0.01,"mu_tr",0.01,"order",50,"sps",2,"decide",0, "adaption",adaption_method.nlms,"dd_mode",1); -eq_ = FFE_DFE("epochs_tr",5,"epochs_dd",5,"len_tr",512,"ffe_mu_dd",1e-4,"dfe_mu_dd",5e-4,"ffe_mu_tr",0,"dfe_mu_tr",0,"ffe_order",99,"dfe_order",99,"sps",2,"decide",0); +% eq_ = FFE_DFE("epochs_tr",5,"epochs_dd",5,"len_tr",512,"ffe_mu_dd",1e-4,"dfe_mu_dd",5e-4,"ffe_mu_tr",0,"dfe_mu_tr",0,"ffe_order",99,"dfe_order",99,"sps",2,"decide",0); +[eq_signal_sd, eq_noise] = eq_.process(Scpe_sig, Symbols); -output.ffe_results = ffe(eq_,M,Scpe_sig,Symbols,Tx_bits, ... - "precode_mode",duob_mode,'showAnalysis',1,"postFFE",[], ... - "eth_style_symbol_mapping",0); +eq_signal_hd = PAMmapper(M,0).quantize(eq_signal_sd); -output.ffe_results.metrics.print("description",'DFE'); +Rx_bits = PAMmapper(M,0).demap(eq_signal_hd); +Tx_bits_omitprecode = PAMmapper(M,0).demap(Symbols); +[bits,errors,ber_wo,errorIndice] = calc_ber(Rx_bits.signal,Tx_bits_omitprecode.signal); +fprintf(["BER w/o precode: %.2d \n"],ber_wo); -%% - -% -------------------- VNLE + MLSE -------------------- -pf_ncoeffs = 1; -ffe_order3 = [50, 5, 5]; -eq_v = EQ("Ne",ffe_order3,"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); -pf_ = Postfilter("ncoeff",pf_ncoeffs,"useBurg",1); - -mlse_ = MLSE("duobinary_output",0,'M',M,'trellis_states',PAMmapper(M,0).levels); - -[output.vnle_results, output.mlse_results] = vnle_postfilter_mlse(eq_v, pf_, mlse_, M, Scpe_sig, Symbols, Tx_bits, ... - "precode_mode", duob_mode, 'showAnalysis', 1, "postFFE", [], "eth_style_symbol_mapping", 0); - -output.mlse_results.metrics.print("description",'MLSE'); - -%% - -% -------------------- DB target -------------------- -mlse_db_ = MLSE("DIR",[1,1],"duobinary_output",0,"M",M,'trellis_states',PAMmapper(M,0).levels); -ffe_order = [50, 5, 5]; -eq_ = EQ("Ne",ffe_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); -output.dbt_results = duobinary_target(eq_,mlse_db_, M, Scpe_sig, Symbols, Tx_bits, ... - "precode_mode", duob_mode, 'showAnalysis', 0, "postFFE", []); - -output.dbt_results.metrics.print("description",'Duobinary'); +showErrorBurstCount(eq_signal_hd, Symbols,"displayname",'No Precode','fignum',8); % prior to coding +eq_signal_hd = pr.encode(eq_signal_hd); +eq_signal_hd = pr.decode(eq_signal_hd); +Rx_bits = PAMmapper(M,0).demap(eq_signal_hd); +[bits,errors,ber,errorIndice] = calc_ber(Rx_bits.signal,Tx_bits.signal); +fprintf(["BER w/ precode: %.2d \n"],ber); +showErrorBurstCount(eq_signal_hd, Symbols_plain,"displayname",'Incl. Precode','fignum',7);