%%% Run parameters % TX M = 4; m = floor(log2(M)*10)/10; fsym = 224e9; apply_pulsef = 1; fdac = 256e9; fadc = 256e9; random_key = 2; rcalpha = 0.05; kover = 8; vbias_rel = 0.5; u_pi = 3.2; vbias = -vbias_rel*u_pi; laser_wavelength = 1310; laser_linewidth = 1e6; % Channel link_length = 0; vnle_order1 = 50; vnle_order2 = 0; vnle_order3 = 0; vnle_order=[vnle_order1,vnle_order2,vnle_order3]; dfe_order = [0 0 0]; 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; dfe_ = sum(dfe_order)>0; doub_mode = db_mode.no_db; cols = linspecer(6); rop = [-6]; bwl = [0.5:0.1:1.5]; fsym = [192:16:256].*1e9; fsym = 208e9; ber_vnle = []; ber_mlse = []; ber_mlse_burg = []; ber_viterbi = []; ber_db = []; ber_db_diff_precoded = []; gmi_vnle_bitwise = []; gmi_mlse = []; gmi_mlse_db = []; for r = 1:length(fsym) Pform = Pulseformer("fsym",fsym(r),"fdac",4*fsym(r),"pulse","rc","pulselength",16,"alpha",rcalpha); db_precode = 0; db_encode = 0; duob_mode = db_mode.no_db; apply_pulsef = 1; [Digi_sig,Symbols,Tx_bits] = PAMsource(... "fsym",fsym(r),"M",M,"order",19,"useprbs",0,... "fs_out",fdac,... "applyclipping",0,"clipfactor",1.5,... "applypulseform",apply_pulsef,"pulseformer",Pform,... "randkey",random_key,... "db_precode",db_precode,"db_encode",db_encode,... "mrds_code",0,"mrds_blocklength",512,"duobinary_mode",duob_mode).process(); % El_sig = AWG("fdac",fdac,"f_cutoff",fsym(r),"lpf_active",0,"kover",kover,"bit_resolution",12,"upsampling_method","samplehold","precomp_sinc_rolloff",0).process(Digi_sig); El_sig = M8199B("kover",kover).process(Digi_sig); % AWG("fdac",fdac,"f_cutoff",fsym(r),"lpf_active",0,"kover",kover,"bit_resolution",12,"upsampling_method","samplehold","precomp_sinc_rolloff",0).process(Digi_sig); %%%%% Low-pass el. components %%%%%% % tx_bwl = 100e9; % El_sig = Filter('filtdegree',3,"f_cutoff",tx_bwl,"fs",fdac*kover,"filterType",filtertypes.butterworth,"active",true).process(El_sig); %%%%% Electrical Driver Amplifier %%%%%% El_sig = El_sig.normalize("mode","oneone"); % El_sig = El_sig.setPower(1,"dBm"); % figure;histogram(El_sig.signal); %%%%% MODULATE E/O CONVERSION %%%%% u_pi = 3.2; vbias = -u_pi*0.5; [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).process(El_sig); if 0 figure(15); hold on scatter(El_sig.signal(1:100000)+vbias,(abs(Opt_sig.signal(1:100000)).^2)*1e3,0.1,'.','DisplayName','Modulator TF') xlabel('Input in V') ylabel('abs(Eopt)2 in mW','Interpreter','latex') ylim([0 2]); xlim([-3.2 0]); Opt_sig.eye(fsym(r),M,"fignum",103837); end %%%%%% Fiber %%%%%% Opt_sig = Fiber("fsimu",Opt_sig.fs,"fiber_length",link_length/1000,"alpha",0.3,"D",0,"lambda0",1310,"gamma",0,"Dslope",0.07).process(Opt_sig); %%%%%% ROP %%%%%% Opt_sig = Amplifier("amp_mode","ideal_no_noise","gain_mode","output_power","amplification_db",rop).process(Opt_sig); % Opt_sig.eye(fsym(r),M,"fignum",103838); % % Opt_sig.signal = Opt_sig.signal + 5*abs(mean(Opt_sig.signal)); % Opt_sig.move_it_spectrum("displayname",'Opt Sig after Amp','fignum',1223323); % Pc = abs(mean(Opt_sig.signal)).^2; % carrier power % Ptot = mean(abs(Opt_sig.signal).^2); % total power % Ps = max(Ptot - Pc, eps); % Pcdb = 10*log10(Pc); % Psdb = 10*log10(Ps); % % cspr_dB = 10*log10(Pc / Ps); % % % Minimal in-place CSPR set (real, nonnegative field constraint) % E = Opt_sig.signal; % real field samples % target_cspr_dB = 20; % <-- set your target CSPR (dB) % % % Decompose into DC + zero-mean waveform % m = mean(E); % x0 = E - m; % zero-mean modulation % Ps0 = mean(x0.^2); % sideband power (fixed if shape kept) % % % Current CSPR (for reference) % Pc_cur = m^2; % Ptot_cur = mean(E.^2); % Ps_cur = max(Ptot_cur - Pc_cur, eps); % cspr_in = 10*log10(Pc_cur / Ps_cur); % % % Bias needed for target CSPR, and minimal bias to keep E>=0 % R_tgt = 10^(target_cspr_dB/10); % Pc/Ps % a_req = sqrt(R_tgt * Ps0); % required DC bias % a_min = -min(x0); % to avoid negatives everywhere % a = max(a_req, a_min); % if infeasible, lands at CSPR_min % % % Apply bias (preserves waveform shape) % E_new = a + x0; % % % Achieved CSPR % Pc_new = mean(E_new)^2; % Ptot_new = mean(E_new.^2); % Ps_new = max(Ptot_new - Pc_new, eps); % cspr_out = 10*log10(Pc_new / Ps_new); % % % (Optional) show feasibility info % cspr_min = 10*log10((a_min^2)/max(Ps0,eps)); % disp(table(cspr_in, target_cspr_dB, cspr_min, cspr_out)); % % % Use E_new as your adjusted field % Opt_sig.signal = E_new; %%%%%% PD Square Law %%%%%% PD_sig = Photodiode("fsimu",fdac*kover,"dark_current",2e-08,"responsivity",1,"temperature",20,"nep",1.8e-11,"randomkey",random_key).process(Opt_sig); %%%%%% Low-pass RX (PD, El. Connectors and Scope %%%%%% rx_bwl = 70e9; PD_sig = Filter('filtdegree',4,"f_cutoff",rx_bwl,"fs",fdac*kover,"filterType",filtertypes.butterworth,"active",true).process(PD_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(PD_sig); Scpe_sig_2sps = Scpe_sig.resample("fs_out",2*fsym(r)); % Scpe_sig_resampled.signal = Scpe_sig_resampled.signal(1:2*length(Symbols)); [~, Scpe_cell, ~, found_sync] = Scpe_sig_2sps.tsynch("reference", Symbols, "fs_ref", fsym(r), "debug_plots", 0); Rx_sig = Scpe_cell{1}; Rx_sig = Rx_sig.normalize("mode","rms"); if 1 %Duobinary Targeting eq_ = EQ("Ne",[vnle_order1,vnle_order2,vnle_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); db_ref_sequence = Duobinary().encode(Symbols); db_ref_constellation = unique(db_ref_sequence.signal); [eq_signal, eq_noise] = eq_.process(Rx_sig,db_ref_sequence); viterbi = 0; if viterbi mlse_ = MLSE_viterbi("duobinary_output",0,'M',M,'trellis_states',PAMmapper(M,0).levels); mlse_.DIR = [1,1]; [eq_signal_whitened] = mlse_.process(eq_signal); else mlse_ = MLSE("DIR",[1,1],"duobinary_output",0,"M",M,"trellis_states",PAMmapper(M,0).get_levels ./ PAMmapper(M,0).get_scaling); mlse_.DIR = [1,1]; [eq_signal_whitened,LLR,gmi_mlse_db(r)] = mlse_.process(eq_signal,Symbols); end mlse_sig_hd = PAMmapper(M,0,"eth_style",0).quantize(eq_signal_whitened); mlse_sig_hd_precoded = Duobinary().encode(mlse_sig_hd,"M",M); mlse_sig_hd_precoded = Duobinary().decode(mlse_sig_hd_precoded,"M",M); tx_symbols_precoded = Duobinary().encode(Symbols); tx_symbols_precoded = Duobinary().decode(tx_symbols_precoded); tx_bits_precoded = PAMmapper(M,0,"eth_style",0).demap(tx_symbols_precoded); rx_bits_mlse = PAMmapper(M,0,"eth_style",0).demap(mlse_sig_hd_precoded); [~,errors_db_diff_precoded,ber_db_diff_precoded(r),a] = calc_ber(rx_bits_mlse.signal,tx_bits_precoded.signal,"skip_front",100,"skip_end",150,"returnErrorLocation",1); burst_db_pre(r,:) = count_error_bursts(a, 15)./numel(Tx_bits.signal); %B) Just determine BER rx_bits_mlse = PAMmapper(M,0,"eth_style",0).demap(mlse_sig_hd); [bits_mlse,errors_db,ber_db(r),a] = calc_ber(rx_bits_mlse.signal,Tx_bits.signal,"skip_front",100,"skip_end",150,"returnErrorLocation",1); burst_db(r,:) = count_error_bursts(a, 15)./numel(Tx_bits.signal); fprintf('BER ber_db_diff_precoded: %.2e \n',ber_db_diff_precoded(r)); fprintf('BER Vber_dbNLE: %.2e \n',ber_db(r)); % figure();hold on;stem(1:15,burst_db(r,:),'LineWidth',1,'Color',cols(1,:));stem(1:15,burst_db_pre(r,:),'LineWidth',1,'Color',cols(2,:));set(gca, 'yscale', 'log'); end % FFE or VNLE eq_ = EQ("Ne",[vnle_order1,vnle_order2,vnle_order3],"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.00,"FFEmu",0,"plotfinal",0,"ideal_dfe",0); % eq = VNLE("epochs_tr",5,"epochs_dd",5,"len_tr",4096*2,"mu_dd",[0.0004 0.0005 0.0006],"mu_tr",0,"order",[50,2,2],"sps",2,"decide",0); [eq_signal_fullresp, eq_noise] = eq_.process(Rx_sig, Symbols); showEQNoisePSD(eq_noise, "fignum",1273876,"displayname",'noise after EQ'); [mi_gomez(r)] = calc_air(eq_signal_fullresp, Symbols, "skip_front", 100, "skip_end", 100); [gmi_vnle_bitwise(r)] = calc_ngmi(eq_signal_fullresp,Symbols); [gmi_bitwise_2(r)] = calc_gmi_bitwise(eq_signal_fullresp,Symbols); snr_vnle(r) = calc_snr(Symbols, eq_signal_fullresp-Symbols); % eq_signal_fullresp.plot("displayname",'bla','fignum',199); % eq_signal_fullresp.eye(fsym(r),M,"fignum",103837); % Hard decision on VNLE output eq_signal_hd = PAMmapper(M, 0).quantize(eq_signal_fullresp); rx_bits = PAMmapper(M,0,"eth_style",0).demap(eq_signal_hd); [~,tot_err,ber_vnle(r),a] = calc_ber(rx_bits.signal,Tx_bits.signal,"skip_front",100,"skip_end",150,"returnErrorLocation",1); burst_vnle(r,:) = count_error_bursts(a, 10)./tot_err; % showLevelConfusionMatrix(eq_signal_hd,Symbols,"M",M,"fignum",200,"displayname",'bla'); % showLevelScatter(eq_signal_fullresp,Symbols,"displayname",'VNLE Out','f_sym',fsym(r),'fignum',201); % show2Dconstellation(eq_signal_fullresp,Symbols,"displayname",'VNLE Out','fignum',2241); fprintf('BER VNLE: %.2e \n',ber_vnle(r)); fprintf('NGMI VNLE: %.2f \n',gmi_vnle_bitwise(r)./m); if 1 % Process through postfilter and MLSE pf_ncoeffs = 1; if fsym(r) < 200e9 pf_ = Postfilter("ncoeff",pf_ncoeffs,"useBurg",1,"coefficients",[1,0.1]); else pf_ = Postfilter("ncoeff",pf_ncoeffs,"useBurg",1,"coefficients",[1,0.85]); end % showEQNoisePSD(eq_noise,"postfilter_taps",pf_.coefficients,"displayname",'Postfilter Burg based'); alpha(r) = pf_.coefficients(2); alpha_vec = max(0,round(alpha(r),2)-0.2):0.025:round(alpha(r),2)+0.4; alpha_vec = unique(sort([alpha_vec, 1, alpha(r)])); gmi_mlse_ = zeros(size(alpha_vec)); ber_mlse_ = zeros(size(alpha_vec)); parfor a=1:numel(alpha_vec) mlse_ = MLSE("duobinary_output",0,'M',M,'trellis_states',PAMmapper(M,0).get_levels ./ PAMmapper(M,0).get_scaling,'DIR',[1,alpha_vec(a)]); pf_ = Postfilter("ncoeff",1,"useBurg",0,"coefficients",[1,alpha_vec(a)]); [eq_signal_whitened,whitened_noise] = pf_.process(eq_signal_fullresp, eq_noise); [signalclass_hd,LLR,gmi_mlse_(a)] = mlse_.process(eq_signal_whitened,Symbols); mlse_sig_hd = PAMmapper(M, 0, "eth_style", 0).quantize(signalclass_hd); rx_bits = PAMmapper(M,0,"eth_style",0).demap(mlse_sig_hd); [~,tot_err,ber_mlse_(a),errpos] = calc_ber(rx_bits.signal,Tx_bits.signal,"skip_front",100,"skip_end",150,"returnErrorLocation",1); % burst_mlse(r,:) = count_error_bursts(errpos, 10); % if 0 % fprintf('BER MLSE: %.2e \n',ber_mlse(r)); % fprintf('NGMI MLSE: %.5f \n',gmi_mlse(r)./m); % % showLevelConfusionMatrix(mlse_sig_hd,Symbols,"M",M,"fignum",300,"displayname",'bla'); % % levels = sort(unique(Symbols.signal(:)).'); % 1×6 % pairs = reshape(mlse_sig_hd.signal,2,[]).'; % isedge = ismember(pairs, [levels(1) levels(end)]); % isforbidden = sum(isedge,2)==2; % fprintf('Found %d forbidden transitions (even→odd edges).\n', nnz(isforbidden)); % % % % Process through postfilter and MLSE % pf_ncoeffs = 1; % pf_ = Postfilter("ncoeff",pf_ncoeffs,"useBurg",1); % mlse_ = MLSE_viterbi("duobinary_output",0,'M',M,'trellis_states',PAMmapper(M,0).levels); % [eq_signal_whitened,whitened_noise] = pf_.process(eq_signal_fullresp, eq_noise); % mlse_.DIR = pf_.coefficients; % mlse_output = mlse_.process(eq_signal_whitened); % mlse_sig_hd = PAMmapper(M, 0, "eth_style", 0).quantize(mlse_output); % rx_bits = PAMmapper(M,0,"eth_style",0).demap(mlse_sig_hd); % [~,~,ber_viterbi(r),~] = calc_ber(rx_bits.signal,Tx_bits.signal,"skip_front",100,"skip_end",150,"returnErrorLocation",1); % fprintf('Viterbi BER: %.2e \n',ber_viterbi(r)); % end end [ber_mlse(r),idx] = min(ber_mlse_); gmi_mlse(r) = gmi_mlse_(idx); ber_mlse_burg(r) = ber_mlse_(alpha_vec==alpha(r)); best_alpha(r) = alpha_vec(idx); end % IR target in EQ if 1 % alpha_vec = max(0,round(alpha(r),2)-0.1):0.01:min(1,round(alpha(r),2)+0.1); plot_stuff = 0; gmi_mlse_pr_tgt_ = zeros(size(alpha_vec)); ber_mlse_pr_tgt_ = zeros(size(alpha_vec)); for a = 1:numel(alpha_vec) alpha_vec(a) = 0.9; eq_ = EQ("Ne",[vnle_order1,vnle_order2,vnle_order3],"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.00,"FFEmu",0,"plotfinal",0,"ideal_dfe",0); Symbols_filt = Symbols.filter([1,alpha_vec(a)],1); [eq_signal_prtgt, eq_noise] = eq_.process(Rx_sig, Symbols_filt); showLevelHistogram(eq_signal_prtgt,Symbols_filt,"displayname",'VNLE Out','fignum',201); if plot_stuff % Plot the response for respective EQ targets Symbols_filt.spectrum("displayname",'IDEAL Filtered Reference','fignum',240587); eq_signal_whitened.spectrum("displayname",'Full tgt. EQ + PF','fignum',240587); eq_signal_prtgt.spectrum("displayname",'Partial Resp. Target EQ','fignum',240587); noise_pf_out = Symbols_filt-eq_signal_whitened; noise_pr_tgt = Symbols_filt-eq_signal_prtgt; noise_pf_out.spectrum("displayname",'Ideal PR - Whitening Out','fignum',240588); noise_pr_tgt.spectrum("displayname",'Ideal PR - PR Target Out','fignum',240588); end mlse_ = MLSE("duobinary_output",0,'M',M,'trellis_states',PAMmapper(M,0).get_levels ./ PAMmapper(M,0).get_scaling,'DIR',[1,alpha_vec(a)],'debug',0); [signalclass_hd,LLR,gmi_mlse_pr_tgt_(a)] = mlse_.process(eq_signal_prtgt,Symbols); mlse_sig_hd = PAMmapper(M, 0, "eth_style", 0).quantize(signalclass_hd); rx_bits = PAMmapper(M,0,"eth_style",0).demap(mlse_sig_hd); [~,tot_err,ber_mlse_pr_tgt_(a),errpos] = calc_ber(rx_bits.signal,Tx_bits.signal,"skip_front",100,"skip_end",150,"returnErrorLocation",1); % burst_mlse_(a,:) = count_error_bursts(errpos, 10); % fprintf('BER MLSE: %.2e \n',ber_mlse_pr_tgt_(a)); % fprintf('NGMI MLSE: %.5f \n',gmi_mlse_pr_tgt_(a)./m); end [ber_mlse_pr_tgt(r),idx] = min(ber_mlse_pr_tgt_); gmi_mlse_pr_tgt(r) = gmi_mlse_pr_tgt_(idx); best_alpha_pr_tgt(r) = alpha_vec(idx); end cols = cbrewer2('paired',8); figure(); hold on title(sprintf('%d GBd',fsym(r).*1e-9)); scatter(alpha_vec,ber_mlse_,15,'Marker','o','LineWidth',1,'DisplayName','MLSE','MarkerEdgeColor',cols(1,:)); scatter(best_alpha(r),ber_mlse(r),15,'Marker','o','LineWidth',2,'DisplayName','MLSE','MarkerEdgeColor',cols(2,:)); scatter(alpha(r),ber_mlse_burg(r),25,'Marker','+','LineWidth',2,'DisplayName','MLSE','MarkerEdgeColor',cols(2,:)); scatter(1,ber_db_diff_precoded(r),15,'Marker','diamond','LineWidth',2,'DisplayName','Duobinary','MarkerEdgeColor',cols(4,:)); scatter(1,ber_db(r),15,'Marker','diamond','LineWidth',2,'DisplayName','Duobinary','MarkerEdgeColor',cols(4,:)); scatter(alpha_vec,ber_mlse_pr_tgt_,15,'Marker','x','LineWidth',1,'DisplayName','MLSE Partial Resp tgt','MarkerEdgeColor',cols(5,:)); scatter(best_alpha_pr_tgt(r),ber_mlse_pr_tgt(r),25,'Marker','x','LineWidth',2,'DisplayName','MLSE','MarkerEdgeColor',cols(6,:)); set(gca,"YScale","log"); % ylim([1e-6 0.5]); % xlim([0.1 1]); drawnow; end % --- style control (one variable controls both marker size and linewidth) --- STYLE_BASE = 2; % adjust this single number to scale markers & lines MARKER_SIZE = STYLE_BASE; % marker size (MATLAB MarkerSize) LINE_WIDTH = max(1.5, STYLE_BASE/3); % line width (keeps lines reasonable when STYLE_BASE large) % --- color map / method -> color assignment (keeps colors consistent) --- cols = cbrewer2('Paired',8); cols = linspecer(6); d = 0; cm.VNLE = cols(1 + d, :); cm.MLSE = cols(2 + d, :); cm.DB_precode = cols(3 + d, :); cm.DB = cols(4 + d, :); % duobinary % prepare x values in GBd xGHz = fsym .* 1e-9; xticks_vals = xGHz; xtick_labels = arrayfun(@(v) sprintf('%d', round(v)), xticks_vals, 'UniformOutput', false); % common marker settings (filled, same face+edge color) mk.VNLE = {'Marker','none','MarkerFaceColor',cm.MLSE,'MarkerEdgeColor',cm.VNLE,'MarkerSize',MARKER_SIZE}; mk.MLSE = {'Marker','none','MarkerFaceColor',cm.MLSE,'MarkerEdgeColor',cm.MLSE,'MarkerSize',MARKER_SIZE}; mk.DB_precode = {'Marker','none','MarkerFaceColor',cm.DB_precode,'MarkerEdgeColor',cm.DB_precode,'MarkerSize',MARKER_SIZE}; mk.DB = {'Marker','none','MarkerFaceColor',cm.DB,'MarkerEdgeColor',cm.DB,'MarkerSize',MARKER_SIZE}; % ---------------- FIGURE 11 : alpha (VNLE) ---------------- figure(110+M); clf; hold on; plot(xGHz, alpha, ... 'DisplayName','VNLE', ... mk.VNLE{:}, 'LineStyle','-','LineWidth',LINE_WIDTH,'Color',cm.VNLE); xlabel('Baudrate in GBd'); ylabel('alpha'); set(gca, 'XTick', xticks_vals, 'XTickLabel', xtick_labels); grid on; legend('Location','best'); % ---------------- FIGURE 15 : GMI ---------------- figure(111+M); clf; hold on; plot(xGHz, mi_gomez, ... 'DisplayName','MI VNLE', ... mk.VNLE{:}, 'LineStyle',':','LineWidth',LINE_WIDTH,'Color',cm.VNLE); plot(xGHz, gmi_vnle_bitwise, ... 'DisplayName','GMI VNLE', ... mk.VNLE{:}, 'LineStyle','-','LineWidth',LINE_WIDTH,'Color',cm.VNLE); % duobinary has only one GMI curve (DB output) plot(xGHz, gmi_mlse_db, ... 'DisplayName','GMI DB tgt.', ... mk.DB{:}, 'LineStyle','-','LineWidth',LINE_WIDTH,'Color',cm.DB); % MLSE symbol-wise (if present) plot(xGHz, gmi_mlse, ... 'DisplayName','GMI MLSE', ... mk.MLSE{:}, 'LineStyle','-','LineWidth',LINE_WIDTH,'Color',cm.MLSE); ylim([log2(M)-1, log2(M)]); xlabel('Baudrate in GBd'); ylabel('GMI'); set(gca, 'XTick', xticks_vals(1:2:end), 'XTickLabel', xtick_labels(1:2:end)); grid on; legend('Location','best'); % xlim([184, 256]) % ---------------- FIGURE 13 : BER ---------------- figure(312+M); hold on; plot(xGHz, ber_vnle, ... 'DisplayName','VNLE', ... mk.VNLE{:}, 'LineStyle','-','LineWidth',LINE_WIDTH,'Color',cm.VNLE); plot(xGHz, ber_mlse, ... 'DisplayName','MLSE', ... mk.MLSE{:}, 'LineStyle','-','LineWidth',LINE_WIDTH,'Color',cm.MLSE); plot(xGHz, ber_viterbi, ... 'DisplayName','Viterbi', ... mk.MLSE{:}, 'LineStyle','--','LineWidth',LINE_WIDTH,'Color',cm.MLSE); yline(4.85e-3,'LineWidth',1,'HandleVisibility','off'); yline(2.2e-4,'LineWidth',1,'HandleVisibility','off'); plot(xGHz, ber_db, ... 'DisplayName','DB tgt.', ... mk.DB{:}, 'LineStyle','-','LineWidth',LINE_WIDTH,'Color',cm.DB); plot(xGHz, ber_db_diff_precoded, ... 'DisplayName','Prec. + DB tgt.', ... mk.DB{:}, 'LineStyle',':','LineWidth',LINE_WIDTH,'Color',cm.DB); xlabel('Baudrate in GBd'); ylabel('BER'); set(gca, 'yscale', 'log'); set(gca, 'XTick', xticks_vals(1:2:end), 'XTickLabel', xtick_labels(1:2:end)); grid on; legend('Location','best'); % xlim([184, 256]) % ---------------- FIGURE 15 : Information Rates ---------------- tp = TransmissionPerformance; m = floor(log2(M)*10)/10; figure(113+M); clf; hold on; netrates_vnle = tp.calculateNetRate(fsym.* m, ... 'NGMI', gmi_vnle_bitwise./m, ... 'BER', ber_vnle); % plot(xGHz, gmi_vnle_bitwise.*xGHz, ... 'DisplayName','GMI*R VNLE', ... mk.VNLE{:}, 'LineStyle','-','LineWidth',LINE_WIDTH,'Color',cm.VNLE); plot(xGHz, netrates_vnle.SDHD.NetRate.*1e-9, ... 'DisplayName','SD+HD VNLE', ... mk.VNLE{:}, 'LineStyle',':','LineWidth',LINE_WIDTH,'Color',cm.VNLE); plot(xGHz, netrates_vnle.HD.NetRate.*1e-9, ... 'DisplayName','Staircase VNLE', ... mk.VNLE{:}, 'LineStyle','-.','LineWidth',LINE_WIDTH,'Color',cm.VNLE); % % MLSE symbol-wise (if present) plot(xGHz, gmi_mlse.*xGHz, ... 'DisplayName','GMI*R MLSE', ... mk.MLSE{:}, 'LineStyle','-','LineWidth',LINE_WIDTH,'Color',cm.MLSE); netrates_mlse = tp.calculateNetRate(fsym.* m, ... 'NGMI', gmi_mlse./m, ... 'BER', ber_mlse); plot(xGHz, netrates_mlse.SDHD.NetRate.*1e-9, ... 'DisplayName','SD+HD MLSE', ... mk.MLSE{:}, 'LineStyle',':','LineWidth',LINE_WIDTH,'Color',cm.MLSE); plot(xGHz, netrates_mlse.HD.NetRate.*1e-9, ... 'DisplayName','Staircase MLSE', ... mk.MLSE{:}, 'LineStyle','-.','LineWidth',LINE_WIDTH,'Color',cm.MLSE); % duobinary has only one GMI curve (DB output) plot(xGHz, gmi_mlse_db.*xGHz, ... 'DisplayName','GMI*R DB tgt.', ... mk.DB{:}, 'LineStyle','-','LineWidth',LINE_WIDTH,'Color',cm.DB); netrates_db = tp.calculateNetRate(fsym.* m, ... 'NGMI', gmi_mlse_db./m, ... 'BER', ber_db); plot(xGHz, netrates_db.SDHD.NetRate.*1e-9, ... 'DisplayName','SD+HD DB', ... mk.DB{:}, 'LineStyle',':','LineWidth',LINE_WIDTH,'Color',cm.DB); plot(xGHz, netrates_db.HD.NetRate.*1e-9, ... 'DisplayName','Staircase DB', ... mk.DB{:}, 'LineStyle','-.','LineWidth',LINE_WIDTH,'Color',cm.DB); % ylim([log2(M)-1, log2(M)]); xlabel('Baudrate in GBd'); ylabel('AIR in Gbps'); set(gca, 'XTick', xticks_vals(1:2:end), 'XTickLabel', xtick_labels(1:2:end)); grid on; legend('Location','best'); xlim([184, 256]) % Auxiliary nested helper for numerically stable log-sum-exp function s = logsumexp(a) % LOGSUMEXP Compute log(sum(exp(a))) in a numerically stable way m = max(a); s = m + log(sum(exp(a - m))); end