From 2a724b833f7d0ca37ff28bf2d30119ddccee24e9 Mon Sep 17 00:00:00 2001 From: Silas Oettinghaus Date: Thu, 19 Feb 2026 15:11:32 +0100 Subject: [PATCH] Theory stuff from sials work pc; minor stuff here and there --- Classes/03_receive/Photodiode.m | 11 +- Classes/DataBaseHandler/DBHandler.m | 4 +- .../Dissertation/dispersion_around_zdw.m | 17 +- Functions/Theory/Dissertation/photo_diode.m | 124 +++++++ .../Theory/Dissertation/power_fading_gif.m | 68 ++++ .../power_fading_gif_lambda_variation.m | 69 ++++ .../Theory/dispersion_wavelength_notch.m | 16 +- Functions/Theory/power_fading.m | 6 +- Functions/plot_s_parameter.m | 317 ++++++++++++++++++ projects/AWG_characterization/output_power.m | 18 +- .../Auswertung_JLT/final/FIGURE_Spectra.m | 15 +- .../final/bibtex_analyzer_ieee.m | 127 +++++++ projects/IMDD_base_system/minimal_example.m | 10 +- test/m2tikz_examples.m | 47 +++ 14 files changed, 810 insertions(+), 39 deletions(-) create mode 100644 Functions/Theory/Dissertation/photo_diode.m create mode 100644 Functions/Theory/Dissertation/power_fading_gif.m create mode 100644 Functions/Theory/Dissertation/power_fading_gif_lambda_variation.m create mode 100644 Functions/plot_s_parameter.m create mode 100644 projects/HighSpeedExperiment_2024/Auswertung_JLT/final/bibtex_analyzer_ieee.m create mode 100644 test/m2tikz_examples.m diff --git a/Classes/03_receive/Photodiode.m b/Classes/03_receive/Photodiode.m index 6c29fd8..58eda20 100644 --- a/Classes/03_receive/Photodiode.m +++ b/Classes/03_receive/Photodiode.m @@ -22,7 +22,7 @@ classdef Photodiode options.responsivity = 1; options.dark_current = 0; options.temperature = 20; - options.nep = 0; %(Moveit IMDD Standard: 1.8e-11) noise effective power in pA/sqrt(Hz); usually between 10-20 pA; see J.Leibrich Diss/ S. Pachnicke Slides + options.nep = 0; %(Moveit IMDD Standard: 1.8e-11 == current noise density in A/sqrt(Hz)! ); usually between 10-20 pA/sqrt(Hz); see J.Leibrich Diss/ S. Pachnicke Slides options.randomkey = 1; end @@ -72,9 +72,16 @@ classdef Photodiode yout = yout + shot_noise; % Thermal Noise + % 2026 comment: obj.nep is not the correct naming, but math-wise everything is fine! + % (2 * k * T / R ) -> A^2/Hz -> is the psd of thermal noise + % earlier: move it's 1.8e-11 is current noise density -> A/sqrt(Hz) + + % power (of white process) is simple multiplication of PSD(f) and B + + % NEP is noise equivalent power, see Dissertation j. Leibrich % P. 121 or Stephan Pachnicke Optical Comm. Lecture Slides - if obj.nep == 0 + if obj.nep == 0 % nep_squared = (2 * k * T / R ) ; %squared else nep_squared = obj.nep^2; diff --git a/Classes/DataBaseHandler/DBHandler.m b/Classes/DataBaseHandler/DBHandler.m index 607aa1a..4ba8138 100644 --- a/Classes/DataBaseHandler/DBHandler.m +++ b/Classes/DataBaseHandler/DBHandler.m @@ -26,9 +26,7 @@ classdef DBHandler < handle options.server = "134.245.243.254"; options.port = 3306; options.user = "silas"; - options.password = "silas"; - - + options.password = "silas"; end % Assign values to class properties based on input arguments diff --git a/Functions/Theory/Dissertation/dispersion_around_zdw.m b/Functions/Theory/Dissertation/dispersion_around_zdw.m index 4bc43eb..8d82e07 100644 --- a/Functions/Theory/Dissertation/dispersion_around_zdw.m +++ b/Functions/Theory/Dissertation/dispersion_around_zdw.m @@ -23,12 +23,16 @@ D_lin = S0 .* (lambda_nm - lambda0_nm); % plot figure('Color','w'); hold on; -cols = cbrewer2('paired',4); -plot(lambda_nm, D_lin(1,:), '-', 'LineWidth',2, 'DisplayName','Linearized model','Color',[cols(1,:)]); -plot(lambda_nm, D_exact(1,:), 'LineWidth',2, 'DisplayName',sprintf('Exact model'),'Color',[cols(2,:)]); +cols = [0.6510 0.8078 0.8902;... + 0.1216 0.4706 0.7059;... + 0.6980 0.8745 0.5412;... + 0.2000 0.6275 0.1725]; -plot(lambda_nm, D_lin(2,:), '-', 'LineWidth',2, 'HandleVisibility','off','Color',[cols(3,:)]); -plot(lambda_nm, D_exact(2,:), 'LineWidth',2, 'HandleVisibility','off','Color',[cols(4,:)]); +% plot(lambda_nm, D_lin(1,:), '-', 'LineWidth',2, 'DisplayName','Linearized model','Color',[cols(1,:)]); +plot(lambda_nm, D_exact(1,:), 'LineWidth',2, 'DisplayName',sprintf('S_0 = 0.07'),'Color',[cols(2,:)]); + +% plot(lambda_nm, D_lin(2,:), '-', 'LineWidth',2, 'HandleVisibility','off','Color',[cols(3,:)]); +plot(lambda_nm, D_exact(2,:), 'LineWidth',2, 'HandleVisibility','on', 'DisplayName',sprintf('S_0 = 0.09'),'Color',[cols(4,:)]); xlabel('Wavelength $\lambda$ [nm]','Interpreter','latex'); @@ -36,4 +40,7 @@ ylabel('D($\lambda$) [ps/(nm km)]','Interpreter','latex'); title('Chromatic Dispersion Around the ZDW'); legend('Location','best'); grid on; box on; +xlim([min(lambda_nm) max(lambda_nm)]) +ylim([-5 5]); +% mat2tikz_improved('C:\Users\Silas\Documents\6971e0b65b380ca6d71c837f\02_IMDD_System\tikz\dispersion\dispersion') diff --git a/Functions/Theory/Dissertation/photo_diode.m b/Functions/Theory/Dissertation/photo_diode.m new file mode 100644 index 0000000..b720562 --- /dev/null +++ b/Functions/Theory/Dissertation/photo_diode.m @@ -0,0 +1,124 @@ +%% ============================================================ +% SNR vs Optical Input Power (dBm) — Shot vs Thermal vs Combined +% - Generate optical field as sine with target RMS power (verified) +% - Magnitude-square detection -> optical power +% - Photocurrent = Rd * P +% - Add shot noise + thermal noise (white, PSD-based) +% - Compute SNR for: shot-only, thermal-only, combined +% ============================================================ + + +% Constants +k = Constant.Boltzmann; +q = Constant.ElementaryCharge; + +% Receiver / PD parameters +T = 20 + 273.15; % K +R = 50; % Ohm (front-end/load) +Rd = 0.7; % A/W (responsivity) +Be = 100e9; % Hz (electrical noise bandwidth) +Id = 0; % A (dark current, optional) + +% Sampling for time-domain demo (needs to be >> Be) +fs = 1e12; % Hz +N = 2^14; % samples +t = (0:N-1).'/fs; + +% Choose an electrical tone within bandwidth (arbitrary for demo) +f0 = 10e9; % Hz + +% Thermal current PSD (two-sided) and variance in Be +Si_th = 4*k*T/R; % A^2/Hz (two-sided) +sigma2_th = Si_th * Be; % A^2 +sigma_th = sqrt(sigma2_th); % A_rms + +% Optical input power sweep (in dBm) +P_dBm = linspace(-40, 10, 300); +P_W = 10.^((P_dBm - 30)/10); % W + +% Pre-allocate results +SNR_shot_dB = zeros(size(P_dBm)); +SNR_th_dB = zeros(size(P_dBm)); +SNR_tot_dB = zeros(size(P_dBm)); + +% --- Main loop over optical input power +for ii = 1:numel(P_W) + Pavg = P_W(ii); + + % Optical field with RMS power = Pavg: + % Let x(t) be the optical field amplitude such that |x|^2 has mean Pavg. + % Use a sinusoid: x(t) = A*sin(2*pi*f0*t), then mean(|x|^2)=A^2/2. + A = sqrt(2*Pavg); % -> mean(|x|^2) = Pavg + + x = A * sin(2*pi*f0*t); % "optical field" (real for simplicity) + + % Verify RMS/mean power numerically (optional) + P_meas = mean(abs(x).^2); % should be ~ Pavg + + a = P_meas - Pavg; + assert(a<1); + + % Magnitude-square detection -> optical power waveform + Popt = abs(x).^2; % W (instantaneous) + + % Photocurrent waveform (includes DC + 2f0 component for this demo) + I_sig = Rd * Popt; % A + + % Define "signal power" as the mean-squared photocurrent due to signal + % (for this sine-squared waveform, it's OK for a demo SNR definition) + P_sig = mean(I_sig.^2); + + % -------- Shot noise (white) -------- + % Two-sided PSD: Si_shot = 2*q*(I_photo + I_dark) + % For this demo, use average current to set the white-noise level: + Ibar = mean(I_sig) + Id; + Si_shot = 2*q*Ibar; % A^2/Hz + sigma2_sh = Si_shot * Be; % A^2 + sigma_sh = sqrt(sigma2_sh); % A_rms + + n_sh = sigma_sh * randn(N,1); % time-domain shot noise + + % -------- Thermal noise (white Gaussian) -------- + n_th = sigma_th * randn(N,1); % time-domain thermal noise + + % Noise powers (mean-square) in time domain + Pn_sh = mean(n_sh.^2); + Pn_th = mean(n_th.^2); + Pn_tot = mean((n_sh + n_th).^2); % ~ Pn_sh + Pn_th (independent) + + % SNRs + SNR_shot = P_sig / Pn_sh; + SNR_th = P_sig / Pn_th; + SNR_tot = P_sig / Pn_tot; + + SNR_shot_dB(ii) = 10*log10(SNR_shot); + SNR_th_dB(ii) = 10*log10(SNR_th); + SNR_tot_dB(ii) = 10*log10(SNR_tot); + + % Optional sanity check (can comment out) + % if ii == 1 + % fprintf('Check Pavg target/meas: %.3g W / %.3g W\n', Pavg, P_meas); + % end +end + +% Plot comparison +figure(1); clf; hold on; +plot(P_dBm, SNR_shot_dB, 'LineWidth', 1.5); +plot(P_dBm, SNR_th_dB, 'LineWidth', 1.5); +plot(P_dBm, SNR_tot_dB, 'LineWidth', 1.5); +grid on; +xlabel('Optical input power [dBm]'); +ylabel('SNR [dB]'); +title('SNR vs Optical Input Power: Shot vs Thermal vs Combined'); +legend('Shot-noise only','Thermal-noise only','Shot + Thermal','Location','best'); + +% Print example at 0 dBm +[~,idx0] = min(abs(P_dBm - 0)); +fprintf('At 0 dBm:\n'); +fprintf(' SNR (shot only) = %.2f dB\n', SNR_shot_dB(idx0)); +fprintf(' SNR (thermal only) = %.2f dB\n', SNR_th_dB(idx0)); +fprintf(' SNR (combined) = %.2f dB\n', SNR_tot_dB(idx0)); + +% Also print NEP based on thermal PSD (constant NEP_th) +NEP_th = sqrt(Si_th)/Rd; % W/sqrt(Hz) +fprintf('Thermal NEP = %.3g W/sqrt(Hz)\n', NEP_th); diff --git a/Functions/Theory/Dissertation/power_fading_gif.m b/Functions/Theory/Dissertation/power_fading_gif.m new file mode 100644 index 0000000..144361b --- /dev/null +++ b/Functions/Theory/Dissertation/power_fading_gif.m @@ -0,0 +1,68 @@ +%% ============================================================ +% IM/DD Power Fading Evolution GIF (1 km -> 20 km) +% Uses the provided GifWriter (serial mode) +% ============================================================ + +clear; close all; clc; + +%% Fiber and system parameters +lambda0 = 1310e-9; % zero-dispersion wavelength [m] +lambda = 1275e-9; % operating wavelength [m] +S0 = 0.09; % dispersion slope [ps/(nm^2·km)] +c = physconst('lightspeed'); + +%% Derived quantities (length-independent) +D_lambda = (S0/4) * (lambda*1e9 - (lambda0*1e9)^4/(lambda*1e9)^3); % ps/(nm·km) +D_si = D_lambda * 1e-6; % s/m^2 +b2 = -D_si * lambda^2 / (2*pi*c); % s^2/m + +%% Frequency grid +f_max = 150e9; +f = linspace(0, f_max, 4000); % [Hz] + +%% Figure setup (keep it stable for nicer GIFs) +fig = figure('Color','w'); +ax = axes(fig); %#ok +hold(ax,'on'); grid(ax,'on'); box(ax,'on'); +xlabel(ax,'Frequency [GHz]'); +ylabel(ax,'Magnitude [dB]'); +ylim(ax,[-30 0]); +xlim(ax,[0 f_max/1e9]); + +%% GIF writer (serial mode; simplest) +g = GifWriter('Name','power_fading_evolution', 'DelayTime',0.12, 'Parallel',false); + +%% Loop: 1 km to 20 km +L = [1:20,19:-1:1]; +for L_km = L + L_meter = L_km * 1e3; % [m] + + % IM/DD transfer function (power fading) + phi = 2*pi^2 * b2 * f.^2 * L_meter; + H = abs(cos(phi)); + HdB = 10*log10(max(H, 1e-12)); % avoid -Inf for deep notches + + % Clear and redraw (stable axes) + cla(ax); + + plot(ax, f/1e9, HdB, 'LineWidth', 1.8, 'Color','black'); + + % Analytic first-null frequency marker + f_null = sqrt(c*(0.5)/(abs(D_si)*lambda^2*L_meter)); + xline(ax, f_null/1e9, 'r--', 'LineWidth', 1.2, ... + 'Label', sprintf('f_{null}=%.1f GHz', f_null/1e9), ... + 'LabelOrientation','horizontal', ... + 'LabelVerticalAlignment','bottom'); + + title(ax, sprintf('Power Fading for: %.0f km @ 1275 nm', L_km)); + + drawnow; + + % Add frame to GIF + g.addFrame(fig); +end + +%% Done +g.compile(fig.Number); + +disp(fullfile(g.OutputDir, sprintf('%s_fig_%d.gif', g.Name, fig.Number))); diff --git a/Functions/Theory/Dissertation/power_fading_gif_lambda_variation.m b/Functions/Theory/Dissertation/power_fading_gif_lambda_variation.m new file mode 100644 index 0000000..b381483 --- /dev/null +++ b/Functions/Theory/Dissertation/power_fading_gif_lambda_variation.m @@ -0,0 +1,69 @@ +%% ============================================================ +% IM/DD Power Fading Evolution vs Wavelength (L = 10 km) +% ============================================================ + +clear; close all; clc; + +%% Fixed fiber parameters +lambda0 = 1310e-9; % zero-dispersion wavelength [m] +S0 = 0.09; % dispersion slope [ps/(nm^2·km)] +L = 10e3; % fiber length FIXED [m] +c = physconst('lightspeed'); + +%% Frequency grid +f_max = 150e9; +f = linspace(0, f_max, 4000); % [Hz] + +%% Figure setup (stable axes for clean GIF) +fig = figure('Color','w'); +ax = axes(fig); +hold(ax,'on'); grid(ax,'on'); box(ax,'on'); +xlabel(ax,'Frequency [GHz]'); +ylabel(ax,'Magnitude [dB]'); +ylim(ax,[-30 0]); +xlim(ax,[0 f_max/1e9]); + +%% GIF writer +g = GifWriter('Name','power_fading_vs_wavelength', ... + 'DelayTime',0.12, ... + 'Parallel',false); + +%% Wavelength sweep (around ZDW) +lambda_vec = linspace(1260e-9, 1360e-9, 25); % 1260–1360 nm + +for k = 1:length(lambda_vec) + + lambda = lambda_vec(k); + + %% Dispersion for current wavelength + D_lambda = (S0/4) * (lambda*1e9 - (lambda0*1e9)^4/(lambda*1e9)^3); % ps/(nm·km) + D_si = D_lambda * 1e-6; % s/m^2 + b2 = -D_si * lambda^2 / (2*pi*c); % s^2/m + + %% Power fading transfer function + phi = 2*pi^2 * b2 * f.^2 * L; + H = abs(cos(phi)); + HdB = 10*log10(max(H, 1e-12)); + + cla(ax) + plot(ax, f/1e9, HdB, 'LineWidth',1.8,'Color','black'); + + %% First-null frequency + if abs(D_si) > 0 + f_null = sqrt(c*(0.5)/(abs(D_si)*lambda^2*L)); + xline(ax, f_null/1e9, 'r--', 'LineWidth',1.2, ... + 'Label', sprintf('f_{null}=%.1f GHz', f_null/1e9), ... + 'LabelOrientation','horizontal', ... + 'LabelVerticalAlignment','bottom'); + end + + title(ax, sprintf('Power Fading for: 10 km @ %.0f nm', lambda*1e9)); + + drawnow; + g.addFrame(fig); +end + +%% Compile GIF +g.compile(fig.Number); + +disp(fullfile(g.OutputDir, sprintf('%s_fig_%d.gif', g.Name, fig.Number))); diff --git a/Functions/Theory/dispersion_wavelength_notch.m b/Functions/Theory/dispersion_wavelength_notch.m index 4c9c1e7..f9bebae 100644 --- a/Functions/Theory/dispersion_wavelength_notch.m +++ b/Functions/Theory/dispersion_wavelength_notch.m @@ -8,17 +8,16 @@ c = physconst('lightspeed'); S0_si = S0 * 1e3; % s/m³ Delta_lambda = linspace(5e-9, 80e-9, 300); % [m] detuning -f_null_2 = sqrt( c * 0.5 ./ (S0_si .* abs(Delta_lambda) .* lambda0.^2 .* L) ); -L = 2e3; % m -f_null_10 = sqrt( c * 0.5 ./ (S0_si .* abs(Delta_lambda) .* lambda0.^2 .* L) ); -cols = cbrewer2('Paired',10); +cols = [0.3467 0.5360 0.6907;... + 0.9153 0.2816 0.2878;... + 0.4416 0.7490 0.4322]; figure('Color','w');hold on -cnt = 2; -for L = 10%[2,5,10] +cnt = 1; +for L = [2,10,40] f_null_10 = sqrt( c * 0.5 ./ (S0_si .* abs(Delta_lambda) .* lambda0.^2 .* L*1e3) ); plot(1310-Delta_lambda*1e9, f_null_10/1e9, 'LineWidth',2,'DisplayName',sprintf('%d km',L),'Color',cols(cnt,:)); - cnt = cnt+2; + cnt = cnt+1; end % yticks([56,75,90,112]) % tickse = 1310-[7.5, 12, 17, 31.5]; @@ -29,4 +28,5 @@ ylabel('$F_{null}$ [GHz]'); grid on; box on; lim=1310-[5,60]; xlim([lim(2) lim(1)]); -ylim([40,130]) \ No newline at end of file +ylim([10,130]) +legend \ No newline at end of file diff --git a/Functions/Theory/power_fading.m b/Functions/Theory/power_fading.m index 2465dd7..b2d2355 100644 --- a/Functions/Theory/power_fading.m +++ b/Functions/Theory/power_fading.m @@ -5,7 +5,7 @@ %% Fiber and system parameters lambda0 = 1310e-9; % zero-dispersion wavelength [m] -lambda = 1275e-9; % operating wavelength [m] +lambda = 1290e-9; % operating wavelength [m] S0 = 0.09; % dispersion slope [ps/(nm²·km)] L = 10e3; % fiber length [m] c = physconst('lightspeed'); @@ -30,7 +30,7 @@ plot(f/1e9, 10*log10(H), 'LineWidth', 1.8,'Color','black'); grid on; box on; xlabel('Frequency [GHz]'); ylabel('Magnitude [dB]'); -title(sprintf('IM/DD Power Fading: 10 km; 1275nm', lambda*1e9, L/1000),"Interpreter","latex"); +% title(sprintf('IM/DD Power Fading: 10 km; 1275nm', lambda*1e9, L/1000),"Interpreter","latex"); ylim([-30 0]); %% Mark analytic first-null frequency @@ -38,3 +38,5 @@ f_null = sqrt(c*(0.5)/(abs(D_si)*lambda^2*L)); xline(f_null/1e9, 'r--', 'LineWidth', 1.2, ... 'Label', sprintf('f_{null}=%.1f GHz', f_null/1e9), ... 'LabelOrientation', 'horizontal', 'LabelVerticalAlignment', 'bottom'); + +mat2tikz_improved('C:\Users\Silas\Documents\6971e0b65b380ca6d71c837f\02_IMDD_System\tikz\dispersion\power_fading.tikz') \ No newline at end of file diff --git a/Functions/plot_s_parameter.m b/Functions/plot_s_parameter.m new file mode 100644 index 0000000..f33e56b --- /dev/null +++ b/Functions/plot_s_parameter.m @@ -0,0 +1,317 @@ +%% Plot S-parameters from Touchstone S2P or S4P (schema-aware, no RF Toolbox) +clear; clc; + +[file,path] = uigetfile({"*.s2p;*.S2P;*.s4p;*.S4P","Touchstone (*.s2p, *.s4p)"}); +if isequal(file,0); return; end +filename = fullfile(path,file); +%% +% Decide port count by extension (minimal-invasive, robust) +[~,~,ext] = fileparts(file); +ext = upper(ext); + +if strcmp(ext,'.S4P') + [matrix, meta] = loads4p_schema(filename); + N = 4; +elseif strcmp(ext,'.S2P') + [matrix, meta] = loads2p(filename); % your original loader kept (below) + N = 2; +else + error("Unsupported extension: %s", ext); +end + +% Frequency in GHz +frex = matrix(:,1); +if isfield(meta,'freqScaleHz') && ~isempty(meta.freqScaleHz) + frex = frex * meta.freqScaleHz / 1e9; % convert to GHz +else + % fallback heuristic (your original) + for i = 1:numel(frex) + if frex(i) > 1e4 + frex(i) = frex(i).*1e-9; + end + end +end + +figure(101); +hold on; +% overlay indexing: count lines already there +if N == 2 + lines = numel(findall(gcf, 'type','line'))/4 + 1; +else + lines = numel(findall(gcf, 'type','line'))/16 + 1; +end + +% styles (kept) +[CC, LL, MM] = ndgrid({1,2,3,4}, {'-', ':', '-.', '--'}, {'none','+', 'o', '*', 'square', 'diamond'}); +combinations = [CC(:), LL(:), MM(:)]; +cols = [0.3467 0.5360 0.6907 + 0.9153 0.2816 0.2878 + 0.4416 0.7490 0.4322 + 1.0000 0.5984 0.2000]; + +% -------------------- Plotting -------------------- +if N == 2 + heads = ["S11","S12","S22","S21"]; + % matrix layout from loads2p: + % col pairs: + % 2-3 S11, 4-5 S21, 6-7 S12, 8-9 S22 + colPairs = [2 3; 6 7; 8 9; 4 5]; % order matches heads above + subplots = 1; + + for k = 1:4 + if subplots, subplot(2,2,k); else, figure('Color','w'); end + hold on; grid on; + + reCol = colPairs(k,1); + imCol = colPairs(k,2); + + % S-parameter magnitude in dB: 20*log10(|S|) + response = 20*log10(abs(matrix(:,reCol) + 1i.*matrix(:,imCol))); + response = movmean(response,1); + + plot(frex, response, ... + "Color", cols(combinations{lines,1},:), ... + "DisplayName", file, ... + "LineStyle", combinations{lines,2}, ... + "Marker", combinations{lines,3}, ... + "MarkerSize", 3); + + if k == 2 || k == 3 + ylim([-6 2]); + else + ylim([-30 2]); + end + xlim([0 100]); + title(heads(k)); + xlabel('Frequency in GHz'); + ylabel('|S| (dB)'); + legend('Location','best'); + end + sgtitle(sprintf('S-Parameters (2-port) [%s]', meta.headerLine)); + +elseif N == 4 + % For s4p schema we plot all Sij in a 4x4 grid + % matrix layout from loads4p_schema: + % columns: 1=f, then pairs in order: + % S11,S12,S13,S14, S21..S24, S31..S34, S41..S44 + subplots = 1; + + for i = 1:4 + for j = 1:4 + sp = (i-1)*4 + j; + if subplots, subplot(4,4,sp); else, figure('Color','w'); end + hold on; grid on; + + idx = (i-1)*4 + j; % 1..16 for Sij in row-major + reCol = 1 + 2*(idx-1) + 1; % after freq col + imCol = 1 + 2*(idx-1) + 2; + + response = 20*log10(abs(matrix(:,reCol) + 1i.*matrix(:,imCol))); + plot(frex, response, ... + "Color", cols(combinations{lines,1},:), ... + "DisplayName", file, ... + "LineStyle", combinations{lines,2}, ... + "Marker", combinations{lines,3}, ... + "MarkerSize", 2); + + xlim([0 100]); + title(sprintf("S%d%d", i, j)); + set(gca,'FontSize',8); + + % reduce clutter + if j ~= 1, yticklabels([]); end + if i ~= 4, xticklabels([]); end + if j == 1, ylabel('|S| (dB)'); end + if i == 4, xlabel('GHz'); end + end + end + sgtitle(sprintf('S-Parameters (4-port) [%s]', meta.headerLine)); +end + + +%% ======================================================================== +% Loader for S4P with the EXACT provided schema (4 lines per frequency) +% ======================================================================== +function [matrix, meta] = loads4p_schema(filepath) + meta = struct(); + meta.headerLine = ""; + meta.freqScaleHz = []; % Hz per file unit (e.g., GHz -> 1e9) + + fid = fopen(filepath,'r'); + if fid < 0, error("Cannot open file: %s", filepath); end + cleaner = onCleanup(@() fclose(fid)); + + % Parse header: find "#" + freUnit = ""; + while true + t = fgetl(fid); + if ~ischar(t), break; end + ts = strtrim(t); + if startsWith(ts,'#') + meta.headerLine = ts; + parts = split(upper(string(ts))); + if numel(parts) >= 2, freUnit = parts(2); end + + switch freUnit + case "HZ", meta.freqScaleHz = 1; + case "KHZ", meta.freqScaleHz = 1e3; + case "MHZ", meta.freqScaleHz = 1e6; + case "GHZ", meta.freqScaleHz = 1e9; + otherwise, meta.freqScaleHz = []; + end + break; + end + end + + data = []; + + while true + l1 = nextNumericLine(fid); + if strlength(l1) == 0 + break; + end + + % IMPORTANT: sscanf wants char for robust behavior + v1 = sscanf(char(l1), '%f').'; + if numel(v1) < 9 + error("S4P schema mismatch: expected 9 numbers on first line of a block, got %d.\nLine: %s", numel(v1), char(l1)); + end + + l2 = nextNumericLine(fid); if strlength(l2)==0, error("Unexpected EOF after first S4P line."); end + l3 = nextNumericLine(fid); if strlength(l3)==0, error("Unexpected EOF after second S4P line."); end + l4 = nextNumericLine(fid); if strlength(l4)==0, error("Unexpected EOF after third S4P line."); end + + v2 = sscanf(char(l2), '%f').'; + v3 = sscanf(char(l3), '%f').'; + v4 = sscanf(char(l4), '%f').'; + + if numel(v2) < 8 || numel(v3) < 8 || numel(v4) < 8 + error("S4P schema mismatch: expected 8 numbers on continuation lines.\nL2: %s\nL3: %s\nL4: %s", char(l2), char(l3), char(l4)); + end + + f = v1(1); + s1 = v1(2:9); % S11..S14 (re/im pairs) + s2 = v2(1:8); % S21..S24 + s3 = v3(1:8); % S31..S34 + s4 = v4(1:8); % S41..S44 + + row = [f, s1, s2, s3, s4]; % 1 + 32 = 33 columns + data = [data; row]; %#ok + end + + matrix = data; +end + + +function ln = nextNumericLine(fid) + ln = ""; + + while true + t = fgetl(fid); + if ~ischar(t) + ln = ""; + return; + end + + ts = strtrim(t); + + % Skip blanks and comments and header lines + if ts=="" || startsWith(ts,'!') || startsWith(ts,'#') + continue; + end + + % Remove inline comment after '!' if present + excl = strfind(ts,'!'); + if ~isempty(excl) + ts = strtrim(extractBefore(ts, excl(1))); + if ts==""; continue; end + end + + % Keep only if there's at least one numeric token + if ~isempty(regexp(ts,'[-+]?\d*\.?\d+(?:[eEdD][-+]?\d+)?','once')) + ln = string(ts); + return; + end + end +end + + + +%% ======================================================================== +% Your original loads2p (kept as-is, but returns meta too) +% ======================================================================== +function [matrix, meta] = loads2p(filepath) + meta = struct(); + meta.headerLine = ""; + meta.freqScaleHz = []; + + % Try to read # line for unit scaling (minimal invasive) + fid = fopen(filepath,'r'); + if fid >= 0 + cleaner = onCleanup(@() fclose(fid)); + while true + t = fgetl(fid); + if ~ischar(t), break; end + ts = strtrim(t); + if startsWith(ts,'#') + meta.headerLine = ts; + parts = split(upper(string(ts))); + if numel(parts) >= 2 + switch parts(2) + case "HZ", meta.freqScaleHz = 1; + case "KHZ", meta.freqScaleHz = 1e3; + case "MHZ", meta.freqScaleHz = 1e6; + case "GHZ", meta.freqScaleHz = 1e9; + end + end + break; + end + end + end + + startRow = 2; + formatSpec = '%20s%25s%23s%23s%23s%23s%23s%23s%23s%s%[^\n\r]'; + + fileID = fopen(filepath,'r'); + dataArray = textscan(fileID, formatSpec, 'Delimiter', '', 'WhiteSpace', '', ... + 'TextType', 'string', 'HeaderLines' ,startRow-1, 'ReturnOnError', false, 'EndOfLine', '\r\n'); + fclose(fileID); + + raw = repmat({''},length(dataArray{1}),length(dataArray)-1); + for col=1:length(dataArray)-1 + raw(1:length(dataArray{col}),col) = mat2cell(dataArray{col}, ones(length(dataArray{col}), 1)); + end + numericData = NaN(size(dataArray{1},1),size(dataArray,2)); + + for col=[1,2,3,4,5,6,7,8,9,10] + rawData = dataArray{col}; + for row=1:size(rawData, 1) + regexstr = '(?.*?)(?([-]*(\d+[\,]*)+[\.]{0,1}\d*[eEdD]{0,1}[-+]*\d*[i]{0,1})|([-]*(\d+[\,]*)*[\.]{1,1}\d+[eEdD]{0,1}[-+]*\d*[i]{0,1}))(?.*)'; + try + result = regexp(rawData(row), regexstr, 'names'); + numbers = result.numbers; + + invalidThousandsSeparator = false; + if numbers.contains(',') + thousandsRegExp = '^[-/+]*\d+?(\,\d{3})*\.{0,1}\d*$'; + if isempty(regexp(numbers, thousandsRegExp, 'once')) + numbers = NaN; + invalidThousandsSeparator = true; + end + end + if ~invalidThousandsSeparator + numbers = textscan(char(strrep(numbers, ',', '')), '%f'); + numericData(row, col) = numbers{1}; + raw{row, col} = numbers{1}; + end + catch + raw{row, col} = rawData{row}; + end + end + end + + R = cellfun(@(x) ~isnumeric(x) && ~islogical(x),raw); + raw(R) = {NaN}; + + matrix = cell2mat(raw); +end diff --git a/projects/AWG_characterization/output_power.m b/projects/AWG_characterization/output_power.m index 9fca42b..a31acdc 100644 --- a/projects/AWG_characterization/output_power.m +++ b/projects/AWG_characterization/output_power.m @@ -78,7 +78,7 @@ for i = 1:length(fsym) %%%%% Pulseforming %%%%%% rrca=0.3; - X = Pulseformer("fsym",fsym(i),"fdac",256e9,"pulse","rrc","pulselength",16,"rrcalpha",rrca).process(digimod_out); + X = Pulseformer("fsym",fsym(i),"fdac",256e9,"pulse","rc","pulselength",16,"alpha",rrca).process(digimod_out); % % %%%%% Clip to PAM range %%%%%% min_ = min(digimod_out.signal).*1.3; @@ -89,7 +89,7 @@ for i = 1:length(fsym) X2 = M8199A("kover",kover).process(X); - X = Pulseformer("fsym",fsym(i),"fdac",92e9,"pulse","rrc","pulselength",16,"rrcalpha",rrca).process(digimod_out); + X = Pulseformer("fsym",fsym(i),"fdac",92e9,"pulse","rc","pulselength",16,"alpha",rrca).process(digimod_out); % % %%%%% Clip to PAM range %%%%%% min_ = min(digimod_out.signal).*1.3; @@ -117,7 +117,7 @@ for i = 1:length(fsym) end end - +%% cols = linspecer(3); figure(6) @@ -130,7 +130,7 @@ xlabel("Baudrate in GBaud"); ylabel("Vpp in V") legend ylim([0.3 1.4]) -thickenfigure; + figure(7) hold on @@ -142,7 +142,7 @@ xlabel("Baudrate in GBaud"); ylabel("Output Power in dBm") legend ylim([-12 4]) -thickenfigure; + figure(8) hold on @@ -154,7 +154,7 @@ xlabel("Baudrate in GBaud"); ylabel("PAPR linear") legend ylim([3 10]) -thickenfigure; + figure(9) @@ -167,7 +167,7 @@ xlabel("Baudrate in GBaud"); ylabel("Vpp in V") legend ylim([0.3 1.4]) -thickenfigure; + figure(10) hold on @@ -179,7 +179,7 @@ xlabel("Baudrate in GBaud"); ylabel("Output Power in dBm") legend ylim([-12 4]) -thickenfigure; + figure(11) hold on @@ -191,6 +191,6 @@ xlabel("Baudrate in GBaud"); ylabel("PAPR linear") legend ylim([3 10]) -thickenfigure; + autoArrangeFigures diff --git a/projects/HighSpeedExperiment_2024/Auswertung_JLT/final/FIGURE_Spectra.m b/projects/HighSpeedExperiment_2024/Auswertung_JLT/final/FIGURE_Spectra.m index 97dc7a9..e819327 100644 --- a/projects/HighSpeedExperiment_2024/Auswertung_JLT/final/FIGURE_Spectra.m +++ b/projects/HighSpeedExperiment_2024/Auswertung_JLT/final/FIGURE_Spectra.m @@ -2,7 +2,7 @@ dsp_options.storage_path = 'Z:\2024\sioe_labor\'; dsp_options.max_occurences = 1; database = DBHandler("dataBase", 'labor_highspeed', "type", 'mysql' ); -rates = [300e9]; +rates = [420e9]; cols = cbrewer2('BuPu',25); cols = [cols(end-10:2:end,:)]; cols = cbrewer2('Set1',6); @@ -10,7 +10,7 @@ cols = cbrewer2('Set1',6); fignum = 200; fig=figure(fignum);clf; -for dbmode = 0:1%length(rates) +for dbmode = 1%length(rates) if 0 @@ -59,8 +59,8 @@ for dbmode = 0:1%length(rates) M = 4; fp.where('Runs', 'pam_level','EQUALS', M); fp.where('Runs', 'bitrate','EQUALS', rates);%360,390 - fp.where('Runs', 'fiber_length','EQUALS', 10); - fp.where('Runs', 'wavelength','EQUALS', 1322.7); %1327.4 + fp.where('Runs', 'fiber_length','EQUALS', 2); + fp.where('Runs', 'wavelength','EQUALS', 1310); %1327.4 fp.where('Runs', 'db_mode','EQUALS', dbmode); fp.where('Runs', 'rop_attenuation','EQUAL', 0); @@ -85,7 +85,7 @@ for dbmode = 0:1%length(rates) %%% 4) Plot RX Signal Scpe_sig.spectrum("fignum",fignum+dbmode,"normalizeTo0dB",1,"displayname",'Rx','addDCoffset',1,'color',[0,0,0],'normalizeToNyquist',0,'linestyle',':'); -Scpe_sig.eye(fsym,M,"fignum",47,"displayname",' Eye of AVG Signal'); + Scpe_sig.eye(fsym,M,"fignum",47,"displayname",' Eye of AVG Signal'); % xline(Symbols.fs/2.*1e-9,'Color',cols(r,:),'HandleVisibility','off'); average_signals = 1; @@ -98,7 +98,10 @@ Scpe_sig.eye(fsym,M,"fignum",47,"displayname",' Eye of AVG Signal'); scope_mean = scope_mean ./ n; Scpe_sig_avg.signal = scope_mean; - Scpe_sig_avg.spectrum("displayname","Scope PSD","fignum",20,"normalizeTo0dB",1); + figure(20);hold on + Symbols.spectrum("fignum",20,"normalizeTo0dB",1,"displayname",'Full Response','addDCoffset',0,'color',clr.Set1.red,'normalizeToNyquist',0,'linestyle','--'); + DB_Symbols.spectrum("fignum",20,"normalizeTo0dB",1,"displayname",'DB-Response','addDCoffset',0,'color',clr.Set1.blue,'normalizeToNyquist',0,'linestyle','--'); + Scpe_sig_avg.spectrum("displayname","Scope PSD","fignum",20,"normalizeTo0dB",1,"addDCoffset",5); Scpe_sig_avg.plot("displayname","Scope raw signal","fignum",27,"clear",1); Scpe_sig_avg.eye(fsym,M,"fignum",48,"displayname",' Eye of AVG Signal'); end diff --git a/projects/HighSpeedExperiment_2024/Auswertung_JLT/final/bibtex_analyzer_ieee.m b/projects/HighSpeedExperiment_2024/Auswertung_JLT/final/bibtex_analyzer_ieee.m new file mode 100644 index 0000000..69fd224 --- /dev/null +++ b/projects/HighSpeedExperiment_2024/Auswertung_JLT/final/bibtex_analyzer_ieee.m @@ -0,0 +1,127 @@ +%% Main Script: Compare Bibliographies +% This script loads two .bbl files, parses them into tables, and compares +% them to find missing citations and duplicates. + +clc; clear; close all; + +% --- STEP 0: Create Dummy Files for Demonstration --- +% (You can remove this step if you have actual files on disk) + +file1 = 'C:\Users\Silas\Documents\latex\JLT_400G_submission\Advanced_DSP_for_400G_IMDD.bbl'; % The file based on your input +file2 = 'C:\Users\Silas\Documents\latex\JLT_400G_submission\Advanced_DSP_for_400G_IMDD_v1.bbl'; % A modified version to show differences + +% --- STEP 1: Load and Parse Files --- +fprintf('Loading files...\n'); +try + tab1 = parse_bbl_file(file1); + tab2 = parse_bbl_file(file2); +catch ME + error('Error loading files: %s', ME.message); +end + +fprintf('File 1 (%s): %d citations found.\n', file1, height(tab1)); +fprintf('File 2 (%s): %d citations found.\n', file2, height(tab2)); +disp('------------------------------------------------------------'); + +% --- STEP 2: Check for Duplicates within files --- +check_duplicates(tab1, file1); +check_duplicates(tab2, file2); +disp('------------------------------------------------------------'); + +% --- STEP 3: Compare Files (Set Differences) --- +% Find keys in A that are NOT in B +[~, idx1] = setdiff(tab1.Key, tab2.Key); +missing_in_B = tab1(idx1, :); + +% Find keys in B that are NOT in A +[~, idx2] = setdiff(tab2.Key, tab1.Key); +missing_in_A = tab2(idx2, :); + +% --- STEP 4: Display Comparison Results --- + +if isempty(missing_in_B) + fprintf('All citations from %s are present in %s.\n', file1, file2); +else + fprintf('Citations in %s but MISSING in %s (%d):\n', file1, file2, height(missing_in_B)); + disp(missing_in_B.Key); +end +fprintf('\n'); + +if isempty(missing_in_A) + fprintf('All citations from %s are present in %s.\n', file2, file1); +else + fprintf('Citations in %s but MISSING in %s (%d):\n', file2, file1, height(missing_in_A)); + disp(missing_in_A.Key); +end + +%% --------------------------------------------------------- +% HELPER FUNCTIONS +% --------------------------------------------------------- + +function check_duplicates(T, filename) + % Checks if the 'Key' column has non-unique entries + [uKeys, ~, idx] = unique(T.Key); + counts = accumarray(idx, 1); + + dup_indices = find(counts > 1); + + if isempty(dup_indices) + fprintf('No duplicates found in %s.\n', filename); + else + fprintf('** WARNING: Duplicates found in %s! **\n', filename); + for i = 1:length(dup_indices) + key_idx = dup_indices(i); + fprintf(' Key "%s" appears %d times.\n', uKeys{key_idx}, counts(key_idx)); + end + end +end + + +function bibTable = parse_bbl_file(filename) +% PARSE_BBL_FILE Loads a .bbl file and extracts citations using Regex. +% +% bibTable = PARSE_BBL_FILE(filename) returns a table with columns: +% - Key: The citation key (e.g., 'dambrosiaAug2025Progress') +% - RawContent: The full text of the citation entry +% - Line: Approximate line number where it starts + + % 1. Read the file content + if ~isfile(filename) + error('File "%s" not found.', filename); + end + str = fileread(filename); + + % 2. Define Regex Structure + % Explanation: + % \\bibitem\{ -> Match literal "\bibitem{" + % (?[^}]+) -> Capture Group 'Key': match anything except '}' + % \} -> Match literal "}" + % \s* -> Match optional whitespace + % (?.*?) -> Capture Group 'Content': match any character lazily... + % (?=(\\bibitem|\\end\{thebibliography\})) -> ...until looking ahead sees "\bibitem" or end of env. + + % Note: 'dotexceptnewline' is usually default, but we need dot to match newlines + % for multi-line citations. We handle this using the '(?s)' flag or explicit loop. + % Here we use standard pattern matching. + + pattern = '\\bibitem\{(?[^}]+)\}\s*(?.*?)(?=(\\bibitem|\\end\{thebibliography\}))'; + + % 3. Execute Regex + % 'warnings' turned off for empty matches if file is malformed + [matches] = regexp(str, pattern, 'names'); + + % 4. Convert to Table + if isempty(matches) + warning('No citations found in %s using standard regex.', filename); + bibTable = table({}, {}, 'VariableNames', {'Key', 'RawContent'}); + return; + end + + % Clean up content (remove leading/trailing spaces/newlines) + keys = {matches.Key}'; + content = {matches.Content}'; + content = strtrim(content); + + bibTable = table(keys, content, 'VariableNames', {'Key', 'RawContent'}); + +end \ No newline at end of file diff --git a/projects/IMDD_base_system/minimal_example.m b/projects/IMDD_base_system/minimal_example.m index 32e1ef8..8576e3e 100644 --- a/projects/IMDD_base_system/minimal_example.m +++ b/projects/IMDD_base_system/minimal_example.m @@ -1,14 +1,14 @@ % minimal example IM/DD M = 4; -fsym = 180e9; +fsym = 112e9; apply_pulsef = 1; fdac = 256e9; fadc = 256e9; random_key = 1; -rcalpha = 0.6; +rcalpha = 0.05; kover = 16; duob_mode = db_mode.no_db; @@ -63,9 +63,11 @@ Pform = Pulseformer("fsym",fsym,"fdac",4*fsym,"pulse","rrc","pulselength",16,"al "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,"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 %%%%%% diff --git a/test/m2tikz_examples.m b/test/m2tikz_examples.m new file mode 100644 index 0000000..00ca91b --- /dev/null +++ b/test/m2tikz_examples.m @@ -0,0 +1,47 @@ +x = -10:2:25; % Input power [dBm] + +y1 = 1e-5 * 10.^(0.12*x); % Dispersion-only +y2 = 1e0 ./ (1 + exp(-0.4*(x-12))); % NLPN +y3 = 1e-6 * 10.^(0.45*x); % RP on gamma +y4 = 1e-2 * 10.^(0.18*(x-8)); % RP on beta2 + +cmap = WesPalette.AsteroidCity1.rgb(4); +cmap = linspecer(4); +figure1=figure(202998);clf;hold on +lw = 0.8; ms = 3; +plot(x,y1,'LineWidth',lw,'Color',cmap(1,:),'Marker','o','MarkerEdgeColor',cmap(1,:),'MarkerFaceColor',[1,1,1],'MarkerSize',ms); +plot(x,y2,'LineWidth',lw,'Color',cmap(2,:),'Marker','square','MarkerEdgeColor',cmap(2,:),'MarkerFaceColor',[1,1,1],'MarkerSize',ms); +plot(x,y3,'LineWidth',lw,'Color',cmap(3,:),'Marker','o','MarkerEdgeColor',cmap(3,:),'MarkerFaceColor',[1,1,1],'MarkerSize',ms); +plot(x,y4,'LineWidth',lw,'Color',cmap(4,:),'Marker','o','MarkerEdgeColor',cmap(4,:),'MarkerFaceColor',[1,1,1],'MarkerSize',ms); +yline(3.8e-3,'HandleVisibility','off') + +grid on +xlabel('Input power [dBm]') +ylabel('NSD ($\%$)') +legend({'Dispersion','NLPN','RP','RP on $\beta_2$'}, ... + 'Location','best') + +grid off +set(gca,'MinorGridLineWidth',0.5); +set(gca,'GridLineWidth',0.5,'GridLineStyle','--','GridColor',[0.9,0.9,0.9]); + +set(gca,'FontSize',12,'YScale','log'); +ylim([1e-6 1e3]) +xlim([-10 23]) + + + +fig_path = 'C:\Users\Silas\Documents\Dissertation\00_Examples\tikz\textfig.tikz'; +matlab2tikz(fig_path, ... + 'width','\fwidth', ... + 'height','\fheight', ... + 'showInfo',false, ... + 'extraAxisOptions',{ ... + 'legend style={font=\footnotesize}', ... + 'xlabel style={font=\color{white!15!black},font=\small},',... + 'ylabel style={font=\color{white!15!black},font=\small},',... + 'legend columns=1', ... + 'every axis/.append style={font=\scriptsize}',... + 'legend columns=2',... + 'legend style={at={(0.02,0.98)},font=\footnotesize,draw=black!60,rounded corners=2pt,inner sep=1pt,fill=white,column sep=6pt,anchor= north west}',... + }); \ No newline at end of file