Scattered stuff from Silas during Dissertation

This commit is contained in:
Silas Oettinghaus
2026-06-03 09:05:33 +02:00
parent a91da3b97c
commit 5c2e27687d
37 changed files with 1726 additions and 1338 deletions

View File

@@ -198,44 +198,65 @@ classdef Signal
end
%% Add signals from one signal to another, the first object will sustain
function Sum = plus(X,y)
if isa(y,'Signal')
Sum = X;
Sum.signal = X.signal + y.signal;
elseif isnumeric(y)
Sum = X;
Sum.signal = X.signal + y;
end
end
function Sum = plus(X,y)
if isa(X,'Signal') && isa(y,'Signal')
Sum = X;
Sum.signal = X.signal + y.signal;
elseif isa(X,'Signal') && isnumeric(y)
Sum = X;
Sum.signal = X.signal + y;
elseif isnumeric(X) && isa(y,'Signal')
Sum = y;
Sum.signal = X + y.signal;
end
end
%% Add signals from one signal to another, the first object will sustain
function Diff = minus(X,y)
if isa(y,'Signal')
Diff = X;
Diff.signal = X.signal - y.signal;
elseif isnumeric(y)
Diff = X;
Diff.signal = X.signal - y;
end
end
function Product = times(X,y)
if isa(y,'Signal')
Product = X;
Product.signal = X.signal .* y.signal;
elseif isnumeric(y)
Product = X;
Product.signal = X.signal .* y;
end
end
%% Display length
function Diff = minus(X,y)
if isa(X,'Signal') && isa(y,'Signal')
Diff = X;
Diff.signal = X.signal - y.signal;
elseif isa(X,'Signal') && isnumeric(y)
Diff = X;
Diff.signal = X.signal - y;
elseif isnumeric(X) && isa(y,'Signal')
Diff = y;
Diff.signal = X - y.signal;
end
end
function Product = times(X,y)
if isa(X,'Signal') && isa(y,'Signal')
Product = X;
Product.signal = X.signal .* y.signal;
elseif isa(X,'Signal') && isnumeric(y)
Product = X;
Product.signal = X.signal .* y;
elseif isnumeric(X) && isa(y,'Signal')
Product = y;
Product.signal = X .* y.signal;
end
end
function Product = mtimes(X,y)
if (isa(X,'Signal') && isnumeric(y) && isscalar(y)) || ...
(isnumeric(X) && isscalar(X) && isa(y,'Signal'))
Product = times(X,y);
else
error('Signal:mtimes:UnsupportedOperands', ...
'Use element-wise .* for Signal multiplication, or scalar * Signal for scaling.');
end
end
%% Display length
function return_length = length(obj)
%METHOD1 Summary of this method goes here
% Detailed explanation goes here
@@ -325,7 +346,8 @@ classdef Signal
else
obj.signal = resample(obj.signal,options.fs_out,options.fs_in,options.n,options.beta);
[p, q] = rat(options.fs_out / options.fs_in);
obj.signal = resample(obj.signal,p,q,options.n,options.beta);
desc = ['resample signal from ', num2str(options.fs_in*1e-9), ' GHz to ', num2str(options.fs_out*1e-9), ' GHz' ];
@@ -344,16 +366,17 @@ classdef Signal
obj
options.fignum = 2025
options.displayname = "";
options.color = [];
options.linestyle = '-';
options.normalizeToNyquist = 0;
options.normalizeToSamplingRate = 0;
options.addDCoffset = 0;
options.normalizeToDC = 0;
options.normalizeTo0dB = 0;
options.show_onesided = false;
options.max_num_lines = []; % Leave empty or omit to disable line rotation
options.fft_length = [];
options.color = [];
options.linestyle = '-';
options.HandleVisibility (1,1) string {mustBeMember(options.HandleVisibility, ["on","off"])} = "on";
options.normalizeToNyquist = 0;
options.normalizeToSamplingRate = 0;
options.addDCoffset = 0;
options.normalizeToDC = 0;
options.normalizeTo0dB = 0;
options.show_onesided = false;
options.max_num_lines = []; % Leave empty or omit to disable line rotation
options.fft_length = [];
% --- NEW options ---
options.useWavelengthAxis (1,1) logical = false % plot x-axis in wavelength
options.lambda0_nm (1,1) double = 1310 % center wavelength [nm]
@@ -364,23 +387,23 @@ classdef Signal
end
useSamplingRateAxis = options.normalizeToSamplingRate ~= 0;
useRadPerSampleAxis = options.normalizeToNyquist ~= 0 && ~useSamplingRateAxis;
if ~useRadPerSampleAxis && ~useSamplingRateAxis
[p_lin,f_Hz] = pwelch(obj.signal, hanning(options.fft_length), ...
options.fft_length/2, options.fft_length, ...
obj.fs, "centered", "power", "mean");
f_GHz = f_Hz*1e-9; % keep frequency vector for frequency axis
else
[p_lin,f_rad] = pwelch(obj.signal, hanning(options.fft_length), ...
options.fft_length/2, options.fft_length, ...
"centered", "power", "mean");
% In normalized modes, pwelch returns rad/sample centered on 0.
% Divide by 2*pi for the f/fs axis where Nyquist is 0.5.
end
useSamplingRateAxis = options.normalizeToSamplingRate ~= 0;
useRadPerSampleAxis = options.normalizeToNyquist ~= 0 && ~useSamplingRateAxis;
% p_lin = movmean(p_lin,4);
if ~useRadPerSampleAxis && ~useSamplingRateAxis
[p_lin,f_Hz] = pwelch(obj.signal, hanning(options.fft_length), ...
options.fft_length/2, options.fft_length, ...
obj.fs, "centered", "power", "mean");
f_GHz = f_Hz*1e-9; % keep frequency vector for frequency axis
else
[p_lin,f_rad] = pwelch(obj.signal, hanning(options.fft_length), ...
options.fft_length/2, options.fft_length, ...
"centered", "power", "mean");
% In normalized modes, pwelch returns rad/sample centered on 0.
% Divide by 2*pi for the f/fs axis where Nyquist is 0.5.
end
p_lin = movmean(p_lin,10);
if options.normalizeTo0dB
p_lin = p_lin ./ max(p_lin);
@@ -392,67 +415,67 @@ classdef Signal
end
% --- If requested, build wavelength axis from frequency offset ---
if options.useWavelengthAxis && ~useRadPerSampleAxis && ~useSamplingRateAxis
c = physconst('LightSpeed'); % [m/s]
lambda0_m = options.lambda0_nm*1e-9; % center wavelength [m]
f_c = c / lambda0_m; % carrier frequency [Hz]
if options.useWavelengthAxis && ~useRadPerSampleAxis && ~useSamplingRateAxis
c = physconst('LightSpeed'); % [m/s]
lambda0_m = options.lambda0_nm*1e-9; % center wavelength [m]
f_c = c / lambda0_m; % carrier frequency [Hz]
% exact mapping
f_abs = f_c + f_Hz; % absolute frequency [Hz]
lambda_m = c ./ f_abs; % wavelength [m]
lambda_nm = lambda_m * 1e9; % wavelength [nm]
% assign axis
x_vec = lambda_nm(:);
x_label = "Wavelength [nm]";
dc_axis = f_Hz;
% Sort to ensure axis is ascending
[x_vec, sortIdx] = sort(x_vec, 'ascend');
p_dbm = p_dbm(sortIdx, :);
dc_axis = dc_axis(sortIdx);
else
% Frequency or normalized axes
if ~useRadPerSampleAxis && ~useSamplingRateAxis
x_vec = f_GHz;
x_label = "Frequency in GHz";
dc_axis = f_GHz;
elseif useSamplingRateAxis
x_vec = f_rad ./ (2*pi);
x_label = "Normalized Frequency f/fs";
dc_axis = x_vec;
else
x_vec = f_rad; % normalized frequency in rad/sample
x_label = "Normalized Frequency [rad/sample]";
dc_axis = x_vec;
end
end
if options.show_onesided
keep_idx = dc_axis >= 0;
x_vec = x_vec(keep_idx);
dc_axis = dc_axis(keep_idx);
p_dbm = p_dbm(keep_idx, :);
end
figure(options.fignum);
ax = gca;
% assign axis
x_vec = lambda_nm(:);
x_label = "Wavelength [nm]";
dc_axis = f_Hz;
% Sort to ensure axis is ascending
[x_vec, sortIdx] = sort(x_vec, 'ascend');
p_dbm = p_dbm(sortIdx, :);
dc_axis = dc_axis(sortIdx);
else
% Frequency or normalized axes
if ~useRadPerSampleAxis && ~useSamplingRateAxis
x_vec = f_GHz;
x_label = "Frequency in GHz";
dc_axis = f_GHz;
elseif useSamplingRateAxis
x_vec = f_rad ./ (2*pi);
x_label = "Normalized Frequency f/fs";
dc_axis = x_vec;
else
x_vec = f_rad; % normalized frequency in rad/sample
x_label = "Normalized Frequency [rad/sample]";
dc_axis = x_vec;
end
end
if options.show_onesided
keep_idx = dc_axis >= 0;
x_vec = x_vec(keep_idx);
dc_axis = dc_axis(keep_idx);
p_dbm = p_dbm(keep_idx, :);
end
figure(options.fignum);
ax = gca;
hold on
p_dbm = p_dbm+options.addDCoffset;
if options.normalizeToDC
[~,min_idx]=min(abs(dc_axis));
pow_at_dc = p_dbm(min_idx);
p_dbm = p_dbm-pow_at_dc;
end
p_dbm = p_dbm+options.addDCoffset;
if options.normalizeToDC
[~,min_idx]=min(abs(dc_axis));
pow_at_dc = p_dbm(min_idx);
p_dbm = p_dbm-pow_at_dc;
end
% p_dbm = movmean(p_dbm,10);
for s = 1:min(size(p_dbm))
if isempty(options.color)
plot(x_vec, p_dbm(:,s), 'DisplayName', options.displayname, 'LineWidth', 1);
plot(x_vec, p_dbm(:,s), 'DisplayName', options.displayname, 'LineWidth', 1, 'LineStyle', options.linestyle, 'HandleVisibility', options.HandleVisibility);
else
plot(x_vec, p_dbm(:,s), 'DisplayName', options.displayname, 'LineWidth', 1, 'Color', options.color,'LineStyle',options.linestyle);
plot(x_vec, p_dbm(:,s), 'DisplayName', options.displayname, 'LineWidth', 1, 'Color', options.color,'LineStyle',options.linestyle, 'HandleVisibility', options.HandleVisibility);
end
end
@@ -468,27 +491,27 @@ classdef Signal
% Axis labels and limits
xlabel(x_label);
if options.useWavelengthAxis && ~useRadPerSampleAxis && ~useSamplingRateAxis
xlim([min(x_vec) max(x_vec)]);
else
if ~useRadPerSampleAxis && ~useSamplingRateAxis
% Keep your existing freq handling (you can fine-tune as needed)
% xlim([-128 128]); % example for 256 GSa/s if desired
xlim([min(x_vec) max(x_vec)]);
elseif useSamplingRateAxis
if options.show_onesided
xlim([0, 0.5]);
else
xlim([-0.5, 0.5]);
end
else
if options.show_onesided
xlim([0, pi]);
else
xlim([-pi, pi]);
end
end
end
if options.useWavelengthAxis && ~useRadPerSampleAxis && ~useSamplingRateAxis
xlim([min(x_vec) max(x_vec)]);
else
if ~useRadPerSampleAxis && ~useSamplingRateAxis
% Keep your existing freq handling (you can fine-tune as needed)
% xlim([-128 128]); % example for 256 GSa/s if desired
xlim([min(x_vec) max(x_vec)]);
elseif useSamplingRateAxis
if options.show_onesided
xlim([0, 0.5]);
else
xlim([-0.5, 0.5]);
end
else
if options.show_onesided
xlim([0, pi]);
else
xlim([-pi, pi]);
end
end
end
ylabel(ylab);
@@ -1007,15 +1030,47 @@ classdef Signal
elseif mode == 1
% generate eye diagram using histogram
maxA = max(sig(100:end-100))*1.3;
minA = min(sig(100:end-100))*1.3;
finite_eye = eye_mat(isfinite(eye_mat));
if isempty(finite_eye)
finite_eye = sig(isfinite(sig));
end
amp_min = min(finite_eye);
amp_max = max(finite_eye);
amp_center = (amp_max + amp_min) / 2;
amp_span = amp_max - amp_min;
if amp_span == 0
amp_span = max(abs(amp_center),1);
end
amp_margin = 0.08 * amp_span;
maxA = amp_center + amp_span/2 + amp_margin;
minA = amp_center - amp_span/2 - amp_margin;
if ~isa(obj,'Opticalsignal') && minA < 0 && maxA > 0
targetStep = max(abs([minA maxA])) / 2;
if targetStep > 0
stepMagnitude = 10^floor(log10(targetStep));
normalizedStep = targetStep / stepMagnitude;
if normalizedStep <= 1
tickStep = stepMagnitude;
elseif normalizedStep <= 2
tickStep = 2 * stepMagnitude;
elseif normalizedStep <= 5
tickStep = 5 * stepMagnitude;
else
tickStep = 10 * stepMagnitude;
end
axisLimit = 2 * tickStep;
maxA = axisLimit;
minA = -axisLimit;
end
end
% maxA = 0.12;
% minA = -0.08;
difference= maxA-minA;
data_ind_y=round((eye_mat-minA)/difference*(histpoints-1)) +1;
data_ind_y=round((eye_mat-minA)/difference*(histpoints-1)) +1;
data_ind_y = min(max(data_ind_y,1),histpoints);
for n=1:size(data_ind_y,1)
nn=histcounts(data_ind_y(n,:),1:histpoints+1);
@@ -1041,22 +1096,22 @@ classdef Signal
if isa(obj,'Opticalsignal')
title(['Optical Eye ',options.displayname])
ylabel("Power in mW");
y_tickstring = string(linspace(maxA.*1e3,minA.*1e3,6));
min_ = min(abs(obj.signal(100:end-100)).^2);
max_ = abs(max(obj.signal(100:end-100)).^2);
elseif isa(obj,'Electricalsignal')
title(['Electrical Eye ',options.displayname])
ylabel("Voltage in V");
y_tickstring = string(linspace(maxA,minA,6));
min_ = min(obj.signal(100:end-100));
max_ = abs(max(obj.signal(100:end-100)));
else
title(['Digital Eye ',options.displayname])
ylabel("Digital Signal Amplitude");
y_tickstring = string(linspace(maxA,minA,6));
min_ = min(obj.signal(100:end-100));
max_ = abs(max(obj.signal(100:end-100)));
end
yTickValues = linspace(maxA.*1e3,minA.*1e3,5);
min_ = min(abs(obj.signal(100:end-100)).^2);
max_ = abs(max(obj.signal(100:end-100)).^2);
elseif isa(obj,'Electricalsignal')
title(['Electrical Eye ',options.displayname])
ylabel("Voltage in V");
yTickValues = linspace(maxA,minA,5);
min_ = min(obj.signal(100:end-100));
max_ = abs(max(obj.signal(100:end-100)));
else
title(['Digital Eye ',options.displayname])
ylabel("Digital Signal Amplitude");
yTickValues = linspace(maxA,minA,5);
min_ = min(obj.signal(100:end-100));
max_ = abs(max(obj.signal(100:end-100)));
end
xlabel('Time in ps')
@@ -1094,7 +1149,14 @@ classdef Signal
hist_interest_smoth = smooth(hist_interest,20);
a = scatter(hist_interest_smoth+posxall,1:length(hist_interest_smoth),4,'.','MarkerEdgeColor','red');
[pk,loc] = findpeaks(hist_interest_smoth,"MinPeakDistance",10,"NPeaks",M,"MinPeakHeight",30,"MinPeakProminence",10);
minPeakDistance = max(10, floor(histpoints / (2*M)));
minPeakProminence = max(3, 0.05 * max(hist_interest_smoth));
[pk,loc] = findpeaks(hist_interest_smoth, ...
"MinPeakDistance",minPeakDistance, ...
"NPeaks",M, ...
"MinPeakProminence",minPeakProminence, ...
"SortStr","descend");
loc = sort(loc);
scatter(posxall,loc,'red','Marker','x','LineWidth',2);
@@ -1177,13 +1239,14 @@ classdef Signal
end
yticks(linspace(0,histpoints,6));
y_tickstring = sprintfc('%.2f', y_tickstring);
yticklabels(y_tickstring);
xticks(linspace(0,histpoints_horizontal,6))
x_tickstring = sprintfc('%.2f', linspace(0, 2/fsym, 8) .* 1e12);
xticklabels(x_tickstring);
yTickPositions = linspace(1,histpoints,numel(yTickValues));
yticks(yTickPositions);
yticklabels(sprintfc('%.2f', yTickValues));
xTickValues = linspace(0, 2/fsym, 6) .* 1e12;
xticks(linspace(1,histpoints_horizontal,numel(xTickValues)))
x_tickstring = sprintfc('%.2f', xTickValues);
xticklabels(x_tickstring);
%
end