diff --git a/Classes/04_DSP/Coding/Partialresponse.m b/Classes/04_DSP/Coding/Partialresponse.m index 4494973..1e91cf3 100644 --- a/Classes/04_DSP/Coding/Partialresponse.m +++ b/Classes/04_DSP/Coding/Partialresponse.m @@ -6,12 +6,12 @@ classdef Partialresponse end methods - function obj = Partialresponse(options) - arguments - options.order (1,1) double = 1 - end + function obj = Partialresponse(varargin) + parser = inputParser; + parser.addParameter("order", 1); + parser.parse(varargin{:}); - obj.order = options.order; + obj.order = parser.Results.order; end function signal = precode(obj, signal, options) diff --git a/Theory/Mapping_Coding/partial_response/duobinary_back2back.m b/Theory/Mapping_Coding/partial_response/duobinary_back2back.m index 94cc818..9e5badd 100644 --- a/Theory/Mapping_Coding/partial_response/duobinary_back2back.m +++ b/Theory/Mapping_Coding/partial_response/duobinary_back2back.m @@ -1,23 +1,21 @@ for M = [2 4 8] - bits = Signalgenerator("form", signalform.prms,"M", M,"order", 15).process(); - + bits = Signalgenerator("form", signalform.prms,"M", M,"order", 16).process(); mapper = PAMmapper(M,0); symbols = mapper.map(bits); - symbols_pre = Duobinary().precode(symbols); - - symbols_db = Duobinary().encode(symbols_pre); - - symbols_rx = Duobinary().decode(symbols_db); + db = Duobinary(); + pr1 = Partialresponse(); + symbols_pre = db.precode(symbols); + symbols_db = db.encode(symbols_pre); + symbols_rx = db.decode(symbols_db); bits_rx = PAMmapper(M,0).demap(symbols_rx); [~,~,ber,~] = calc_ber(bits.signal,bits_rx.signal,"skip_front",0,"skip_end",0,"returnErrorLocation",1); disp(['Class BER: ',sprintf('%.1E',ber),' - PAM-',num2str(M)]); - symbols_pre_pr = Partialresponse("order",1).precode(symbols,"M",M); - symbols_db_pr = Partialresponse("order",1).encode(symbols_pre_pr,"M",M); - symbols_rx_pr = Partialresponse("order",1).decode(symbols_db_pr,"M",M); - + symbols_pre_pr = pr1.precode(symbols,"M",M); + symbols_db_pr = pr1.encode(symbols_pre_pr,"M",M); + symbols_rx_pr = pr1.decode(symbols_db_pr,"M",M); bits_rx_pr = mapper.demap(symbols_rx_pr); [~,~,ber_pr,~] = calc_ber(bits.signal,bits_rx_pr.signal,"skip_front",0,"skip_end",0,"returnErrorLocation",1); disp(['Partialresponse BER: ',sprintf('%.1E',ber_pr),' - PAM-',num2str(M)]); @@ -37,4 +35,43 @@ for M = [2 4 8] disp(['Decode match: ',num2str(dec_match), ... ' | max abs diff: ',sprintf('%.3g',dec_maxdiff)]); disp('---'); + + f = figure("Name",sprintf("PAM-%d Partial-Response Histograms",M)); + t = tiledlayout(f,1,4,"TileSpacing","compact","Padding","compact"); + title(t,sprintf("PAM-%d Symbol Histograms",M)); + + nexttile; + plotDiscreteHistogram(symbols.signal,sprintf("PAM-%d",M)); + + nexttile; + plotDiscreteHistogram(symbols_db_pr.signal,"Duobinary 1st Order"); + + nexttile; + plotDiscreteHistogram(getEncodedSymbols(symbols,M,2),"Duobinary 2nd Order"); + + nexttile; + plotDiscreteHistogram(getEncodedSymbols(symbols,M,3),"Duobinary 3rd Order"); + +end + +function y = getEncodedSymbols(symbols, M, order) + pr = Partialresponse("order",order); + y = pr.encode(pr.precode(symbols,"M",M),"M",M).signal; +end + +function plotDiscreteHistogram(x, plot_title) + levels = unique(x(:)).'; + counts = zeros(size(levels)); + + for idx = 1:numel(levels) + counts(idx) = sum(abs(x - levels(idx)) < 1e-12); + end + + bar(levels, counts, 0.9, "FaceColor", [0.2 0.45 0.75], "EdgeColor", "none"); + grid on; + box on; + xlabel("Level"); + ylabel("Count"); + title(plot_title); + xticks(levels); end diff --git a/Theory/Mapping_Coding/partial_response/duobinary_minimal_example.m b/Theory/Mapping_Coding/partial_response/duobinary_minimal_example.m deleted file mode 100644 index 71e26a3..0000000 --- a/Theory/Mapping_Coding/partial_response/duobinary_minimal_example.m +++ /dev/null @@ -1,122 +0,0 @@ -useprbs = 1; -M = 2; -randkey = 1; -datarate = 448e9; -fsym = round(datarate / log2(M)) ; - -Tx_bits = Signalgenerator( ... - "form", signalform.prms, ... - "M", M, ... - "order", 15).process(); - - -Symbols_tx = PAMmapper(M,0,"eth_style",0).map(Tx_bits); -Symbols_tx.fs = fsym; - -precode = db_mode.db_precoded; - -%%% precode -switch precode - case db_mode.db_precoded - Symbols_tx = Duobinary().precode(Symbols_tx); - case db_mode.db_encoded - Symbols_tx = Duobinary().precode(Symbols_tx); - Symbols_tx = Duobinary().encode(Symbols_tx); - case db_mode.no_db - -end - -for n = 10 - - % Start from the transmitted symbol sequence for this impairment case. - Symbols_rx = Symbols_tx; - - % Insert n deterministic symbol errors near the beginning of the sequence. - % Each replacement is chosen from another symbol position with a different - % amplitude, so this produces actual symbol decisions errors. - pos = 1; - if n~=0 - for pos = 1:n - po = randi(100); - a = Symbols_rx.signal(100+pos) == Symbols_tx.signal(100+po); - while a == 1 - po = po+1; - po = randi(100); - a = Symbols_rx.signal(100+pos) == Symbols_tx.signal(100+po); - end - Symbols_rx.signal(100+pos) = Symbols_tx.signal(100+po); - end - end - - % Keep track of the positions where the artificial symbol errors were - % inserted before duobinary encoding/decoding is applied. - error_positions = ~(Symbols_rx.signal == Symbols_tx.signal); - error_positions = find(error_positions==1); - - % Receiver-side duobinary processing depends on what was already done at - % the transmitter side: - % - db_precoded: the sequence is precoded only, so emulate the channel PR - % encoder first and then apply memoryless duobinary decoding. - % - db_encoded: the sequence already contains duobinary levels, so only - % the memoryless duobinary decoder is applied. - switch precode - - case db_mode.db_precoded - Symbols_rx = Duobinary().encode(Symbols_rx); - Symbols_rx = Duobinary().decode(Symbols_rx); - case db_mode.db_encoded - Symbols_rx = Duobinary().decode(Symbols_rx); - - end - - % Convert the recovered PAM symbols back to bits with the framework mapper. - Rx_bits = PAMmapper(M,0).demap(Symbols_rx); - - %%%%% Check BER of Bit Sequence %%%%% - % Skip a few edge samples because the first/last symbols can include - % state/transient effects from the duobinary recursion. - [~,error_num(n+1),ber,error_pos] = calc_ber(Tx_bits.signal,Rx_bits.signal,"skip_front",10,"skip_end",10,"returnErrorLocation",1); - - % disp(['BER: ',sprintf('%.1E',ber),sprintf(' - Num. Err: %.1d',error_num(n+1)-2),' - - PAM-',num2str(M)]); - fprintf('n: %d - Num. Err: %.1d \n',n,error_num(n+1)); - -end - - - -% Plot bit-level and symbol-level comparisons for a quick visual sanity check. -figure(3); -clf -%sgtitle(['BER: ',num2str(ber),' // Error is at position: ',num2str(error_pos),'']) - -% Compare the first few transmitted and received bits. -subplot(2,2,1) -hold on -title('First Bits') -stairs(Tx_bits.signal(100:150,1),'LineStyle','-','LineWidth',2,'DisplayName','Tx Bits'); -stairs(Rx_bits.signal(100:150,1),'LineWidth',2,'DisplayName','Rx Bits','LineStyle',':') -legend - -% Compare the last few transmitted and received bits. -subplot(2,2,2) -title('Last Bits') -hold on -stairs(Tx_bits.signal(end-50:end,1),'LineStyle','-','LineWidth',2,'DisplayName','Tx Bits'); -stairs(Rx_bits.signal(end-50:end,1),'LineWidth',2,'DisplayName','Rx Bits','LineStyle',':') -legend - -% Compare the first few symbol decisions after the duobinary processing chain. -subplot(2,2,3) -hold on -title('First Symbols Compare') -stairs(Symbols_tx.signal(1:100,1),'LineWidth',2,'DisplayName','Tx Symbols','LineStyle','-') -stairs(Symbols_rx.signal(1:100,1),'LineStyle',':','LineWidth',2,'DisplayName','Rx Symbols'); -legend - -% Compare the last few symbol decisions after the duobinary processing chain. -subplot(2,2,4) -hold on -title('Last Symbols Compare') -stairs(Symbols_tx.signal(end-50:end,1),'LineWidth',2,'DisplayName','Tx Symbols','LineStyle','-') -stairs(Symbols_rx.signal(end-50:end,1),'LineStyle',':','LineWidth',2,'DisplayName','Rx Symbols'); -legend diff --git a/Theory/Mapping_Coding/partial_response/partial_response_precoder.m b/Theory/Mapping_Coding/partial_response/errorburst_pr_precoder.m similarity index 100% rename from Theory/Mapping_Coding/partial_response/partial_response_precoder.m rename to Theory/Mapping_Coding/partial_response/errorburst_pr_precoder.m diff --git a/Theory/Mapping_Coding/partial_response/symbol_mapping_partial_response.m b/Theory/Mapping_Coding/partial_response/symbol_mapping_partial_response.m new file mode 100644 index 0000000..f2feb77 --- /dev/null +++ b/Theory/Mapping_Coding/partial_response/symbol_mapping_partial_response.m @@ -0,0 +1,147 @@ + +M = 4; +useUnitRmsScaling = false; +bits = Signalgenerator("form", signalform.prms,"M", M,"order", 16).process(); +mapper = PAMmapper(M,0); +symbols = mapper.map(bits); + + +[constellation, bitmap] = mapper.getConstellationBitMapping(); +printConstellationBitMapping(M, constellation, bitmap); +printPartialResponseStateTable(M, bitmap, "Duobinary", 1, useUnitRmsScaling); + +db = Duobinary(); +pr1 = Partialresponse(); + +symbols_pre = db.precode(symbols); +symbols_db = db.encode(symbols_pre); +symbols_rx = db.decode(symbols_db); +bits_rx = PAMmapper(M,0).demap(symbols_rx); +[~,~,ber,~] = calc_ber(bits.signal,bits_rx.signal,"skip_front",0,"skip_end",0,"returnErrorLocation",1); +disp(['Class BER: ',sprintf('%.1E',ber),' - PAM-',num2str(M)]); + + + + + +function printConstellationBitMapping(M, constellation, bitmap) +fprintf("\n=== PAM-%d Bit Mapping ===\n", M); + + bitLabels = string(cellstr(char(bitmap + '0'))); + + if size(constellation, 2) == 1 + mappingTable = table(constellation(:), bitLabels, ... + 'VariableNames', {'Symbol', 'Bits'}); + else + mappingTable = table(constellation(:,1), constellation(:,2), bitLabels, ... + 'VariableNames', {'Symbol_1', 'Symbol_2', 'Bits'}); + end + +disp(mappingTable); +fprintf("Number of constellation points: %d\n\n", size(constellation, 1)); +end + +function printPartialResponseStateTable(M, bitmap, label, order, useUnitRmsScaling) +if useUnitRmsScaling + scalingLabel = "unit-RMS scaling"; + encodedScaling = getEncodedScaling(M, order); +else + scalingLabel = "raw encoder levels"; + encodedScaling = 1; +end + +fprintf("=== %s Effective State Table (order = %d, %s) ===\n", label, order, scalingLabel); + +mapper = PAMmapper(M, 0); +h = arrayfun(@(k) nchoosek(order, k), 0:order); +center = ((M - 1) * sum(h)) / 2; + +if useUnitRmsScaling + pamScaling = mapper.scaling; +else + pamScaling = 1; +end + +numStates = M^order; +numInputs = M; + +prevStateLabels = strings(numStates * numInputs, 1); +bitLabels = strings(numStates * numInputs, 1); +aAmp = zeros(numStates * numInputs, 1); +uIdx = zeros(numStates * numInputs, 1); +uAmp = zeros(numStates * numInputs, 1); +yAmp = zeros(numStates * numInputs, 1); +nextStateLabels = strings(numStates * numInputs, 1); + +row = 1; +for stateIdx = 0:(numStates - 1) + state = indexToState(stateIdx, M, order); + + for a = 0:(numInputs - 1) + u = mod(a - sum(h(2:end) .* state), M); + y = (sum(h .* [u, state]) - center) / encodedScaling; + + prevStateLabels(row) = formatState(state); + bitLabels(row) = bitsFromIndex(bitmap, a + 1); + aAmp(row) = indexToPamAmplitude(a, pamScaling, M); + uIdx(row) = u; + uAmp(row) = indexToPamAmplitude(u, pamScaling, M); + yAmp(row) = y; + nextStateLabels(row) = formatState([u, state(1:end-1)]); + row = row + 1; + end +end + +stateTable = table(prevStateLabels, bitLabels, aAmp, uIdx, uAmp, yAmp, nextStateLabels, ... + 'VariableNames', {'PrevState', 'Bits', 'InputSymbol', 'PrecodedIndex', 'PrecodedSymbol', 'EncodedLevel', 'NextState'}); + +disp(stateTable); +fprintf("States: %d, transitions: %d\n\n", numStates, height(stateTable)); +end + +function state = indexToState(stateIdx, M, order) +state = zeros(1, order); +tmp = stateIdx; + +for k = 1:order + state(k) = mod(tmp, M); + tmp = floor(tmp / M); +end +end + +function label = formatState(state) +if isempty(state) + label = "[]"; +else + label = "[" + join(string(state), " ") + "]"; +end +end + +function bitLabel = bitsFromIndex(bitmap, idx) +bitLabel = string(char(bitmap(idx, :) + '0')); +end + +function amplitude = indexToPamAmplitude(a, scaling, M) +amplitude = (2 * a - (M - 1)) / scaling; +end + +function scaling = getEncodedScaling(M, order) +h = arrayfun(@(k) nchoosek(order, k), 0:order); +numCombinations = M^(order + 1); +y = zeros(numCombinations, 1); + +for n = 0:(numCombinations - 1) + state = zeros(1, order + 1); + tmp = n; + + for k = 1:numel(state) + state(k) = mod(tmp, M); + tmp = floor(tmp / M); + end + + y(n + 1) = sum(h .* state); +end + +center = ((M - 1) * sum(h)) / 2; +scaling = sqrt(mean((y - center).^2)); +end diff --git a/Theory/Mapping_Coding/partial_response/test_db_minimal_example.m b/Theory/Mapping_Coding/partial_response/test_db_minimal_example.m deleted file mode 100644 index cfeb77d..0000000 --- a/Theory/Mapping_Coding/partial_response/test_db_minimal_example.m +++ /dev/null @@ -1,55 +0,0 @@ - -M = 8; -apply_precode_at_tx = 1; - -bits = Signalgenerator( ... - "form", signalform.prms, ... - "M", M, ... - "order", 15).process(); - -symbols = PAMmapper(M,0).map(bits); - -if apply_precode_at_tx - symbols_tx = Duobinary().precode(symbols); -else - symbols_tx = symbols; -end - -disp(['Tx Sequenz: -- RMS:',sprintf('%.1f',rms(symbols_tx.signal)),' - - Levels -',num2str(numel(unique(symbols_tx.signal)))]); -unique(symbols_tx.signal) -disp('- - - - - - - - - -'); - -show2Dconstellation(symbols_tx,symbols_tx,"displayname",'VNLE Out','fignum',2241); - -if apply_precode_at_tx - % Entschiedene Symbole codieren: d_DB(n) = d(n) + d(n-1) (im Fall von PAM4 7 level [0 1 2 3 4 5 6]) - symbols_db = Duobinary().encode(symbols_tx); - - disp(['DB encoded -- RMS:',sprintf('%.1f',rms(symbols_db.signal)),' - - Levels -',num2str(numel(unique(symbols_db.signal)))]); - unique(symbols_db.signal) - disp('- - - - - - - - - -'); - - % Entschiedene codierte Symbole decodieren: d_dec(n) = d_DB(n) mod4 - symbols_rx = Duobinary().decode(symbols_db); -else - symbols_db = Duobinary().encode(symbols_tx); - symbols_rx = Duobinary().decode(symbols_db); -end - -% Vergleichen von b(n) und d_dec(n) -bits_rx = PAMmapper(M,0).demap(symbols_rx); -disp(['Wieder normal -- RMS:',sprintf('%.1f',rms(symbols_rx.signal)),' - - Levels -',num2str(numel(unique(symbols_rx.signal)))]); -unique(symbols_rx.signal) -disp('- - - - - - - - - -'); - - -[~,~,ber,~] = calc_ber(bits.signal,bits_rx.signal,"skip_front",10,"skip_end",10,"returnErrorLocation",1); - -disp(['BER: ',sprintf('%.1E',ber),' - - PAM-',num2str(M)]); - -figure() -subplot(1,2,1) -histogram(symbols_tx.signal,100,'Normalization','count') - -subplot(1,2,2) -histogram(symbols_db.signal,100,'Normalization','count') \ No newline at end of file diff --git a/projects/Precoding_analysis/precode_imdd_system.m b/projects/Precoding_analysis/precode_imdd_system.m new file mode 100644 index 0000000..919cd7e --- /dev/null +++ b/projects/Precoding_analysis/precode_imdd_system.m @@ -0,0 +1,182 @@ +% minimal example IM/DD + +M = 4; +fsym = 112e9; + +apply_pulsef = 1; +fdac = 256e9; +fadc = 256e9; +random_key = 1; + +rcalpha = 0.05; +kover = 16; + +duob_mode = db_mode.no_db; + +vbias_rel = 0.5; +u_pi = 3; +vbias = -vbias_rel*u_pi; + +laser_wavelength = 1293; +laser_linewidth = 0; +tx_bw_nyquist = 0.8; + +% Channel +link_length = 1; + +% RX +rop = -9; +rx_bw_nyquist = 0.8; + +vnle_order1 = 50; +vnle_order2 = 7; +vnle_order3 = 7; + +vnle_order=[vnle_order1,vnle_order2,vnle_order3]; +dfe_order = [0 0 0]; + +pf_ncoeffs = 1; + +alpha = 0; + +len_tr = 4096*2; + +mu_ffe1 = 0.0001; +mu_ffe2 = 0.0008; +mu_ffe3 = 0.001; +mu_dc = 0.005; +% mu_dc = 0; + +mu_ffe = [mu_ffe1 mu_ffe3 mu_ffe3]; +mu_dfe = 0.0004; + + +Pform = Pulseformer("fsym",fsym,"fdac",4*fsym,"pulse","rrc","pulselength",16,"alpha",rcalpha); + +[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.spectrum("displayname",'Digi Spectrum','fignum',1,'normalizeTo0dB',1); +xlim([0,130]); +ylim([-30,5]); +% El_sig = El_sig.setPower(0,"dBm"); + +%%%%% 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)); +El_sig = El_sig .* scaling; + +%%%%% MODULATE E/O CONVERSION %%%%%% +[Opt_sig] = EML("mode",eml_mode.im_cosinus,"power",3,"fsimu",El_sig.fs,"lambda",laser_wavelength,"bias",vbias,"u_pi",u_pi,"linewidth",laser_linewidth,"randomkey",random_key+1,"alpha",alpha).process(El_sig); + +Opt_sig.spectrum("displayname",'Opt Spectrum','fignum',10,'normalizeTo0dB',1); + +% Opt_sig.eye(fsym,M,"displayname",'eye adter modulator','fignum',2026); + +Opt_sig = Fiber("fsimu",Opt_sig.fs,"fiber_length",link_length,"alpha",0.3,"D",0,"lambda0",1310,"gamma",0,"Dslope",0.07).process(Opt_sig); + +%%%%%% ROP %%%%%% +Rx_sig = Amplifier("amp_mode","ideal_no_noise","gain_mode","output_power","amplification_db",rop).process(Opt_sig); + +%%%%%% PD Square Law %%%%%% +Rx_sig = Photodiode("fsimu",fdac*kover,"dark_current",2e-08,"responsivity",1,"temperature",20,"nep",1.8e-11).process(Rx_sig); + +%%%%%% Low-pass RX (PD, El. Connectors and Scope %%%%%% +rx_bwl = 80e9; +Rx_sig = Filter('filtdegree',4,"f_cutoff",rx_bwl,"fs",fdac*kover,"filterType",filtertypes.butterworth,"active",true).process(Rx_sig); + +% %%%%%% Low-pass Scope %%%%%% +Lp_scpe = Filter('filtdegree',4,"f_cutoff",110e9,"fs",fadc,"filterType",filtertypes.butterworth,"active",true); + +%%%%%% Scope %%%%%% +Scpe_sig = Scope("fsimu",fdac*kover,"fadc",fadc,... + "delay",0,"fixed_delay",0,"filtertype",filtertypes.butterworth,... + "samplingdelay",0,"rand_samplingdelay",0,"freq_offset",0,"samp_jitter",0,... + "adcresolution",8,"quantbuffer",0.1,'block_dc',1,'lpf_active',1,'H_lpf',Lp_scpe).process(Rx_sig); +%% + +% 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!? +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); +% + +% %% +% %%%%%% Sample to 2x fsym %%%%%% +% 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 = 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)); + +%% + +% -------------------- 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, ... + "K",2,"DCmu",mu_dc,"DDmu",[mu_ffe mu_dfe],"DFEmu",0.005, ... + "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); + + +output.ffe_results = ffe(eq_,M,Scpe_sig,Symbols,Tx_bits, ... + "precode_mode",duob_mode,'showAnalysis',1,"postFFE",[], ... + "eth_style_symbol_mapping",0); + +output.ffe_results.metrics.print("description",'DFE'); + +%% + +% -------------------- 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'); + + +