BCJR implementation
WDM code added (Pol Cont., Opt MUX/DEMUX, Opt Atten, DP_Fiber) -> the codebase is not optimized to always work with dp signals!
This commit is contained in:
@@ -5,6 +5,7 @@ classdef Opticalsignal < Signal
|
||||
properties
|
||||
nase
|
||||
lambda
|
||||
polrot
|
||||
|
||||
end
|
||||
|
||||
@@ -18,6 +19,7 @@ classdef Opticalsignal < Signal
|
||||
options.logbook
|
||||
options.lambda
|
||||
options.nase
|
||||
options.polrot
|
||||
end
|
||||
|
||||
obj = obj@Signal(signal);
|
||||
|
||||
@@ -108,6 +108,7 @@ classdef Signal
|
||||
options.logbook
|
||||
options.nase
|
||||
options.lambda
|
||||
options.polrot
|
||||
end
|
||||
|
||||
fn = fieldnames(options);
|
||||
@@ -122,7 +123,7 @@ classdef Signal
|
||||
|
||||
%convert to optical
|
||||
|
||||
o_sig = Opticalsignal(obj.signal,"fs",obj.fs,"lambda",options.lambda,"logbook",obj.logbook,"nase",options.nase);
|
||||
o_sig = Opticalsignal(obj.signal,"fs",obj.fs,"lambda",options.lambda,"logbook",obj.logbook,"nase",options.nase,"polrot",options.polrot);
|
||||
|
||||
|
||||
elseif isa(obj,'Informationsignal')
|
||||
@@ -141,7 +142,7 @@ classdef Signal
|
||||
|
||||
arguments
|
||||
obj
|
||||
options.fignum = []
|
||||
options.fignum = randi(1000)
|
||||
options.displayname = [];
|
||||
options.timeframe = 0;
|
||||
options.clear = 0;
|
||||
@@ -187,7 +188,7 @@ classdef Signal
|
||||
ylabel('Amplitude');
|
||||
end
|
||||
|
||||
|
||||
|
||||
% Add legend if not already present
|
||||
if isempty(get(gca, 'Legend'))
|
||||
legend;
|
||||
@@ -350,21 +351,30 @@ classdef Signal
|
||||
options.normalizeTo0dB = 0;
|
||||
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]
|
||||
end
|
||||
|
||||
if isempty(options.fft_length)
|
||||
options.fft_length = 2^(nextpow2(length(obj.signal))-9);
|
||||
end
|
||||
|
||||
|
||||
if options.normalizeToNyquist == 0
|
||||
[p_lin,w] = pwelch(obj.signal,hanning(options.fft_length),options.fft_length/2,options.fft_length,obj.fs,"centered","power","mean");
|
||||
w = w.*1e-9;
|
||||
[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,w] = pwelch(obj.signal,hanning(options.fft_length),options.fft_length/2,options.fft_length,"centered","power","mean");
|
||||
[p_lin,f_rad] = pwelch(obj.signal, hanning(options.fft_length), ...
|
||||
options.fft_length/2, options.fft_length, ...
|
||||
"centered", "power", "mean");
|
||||
% In normalized mode, pwelch returns rad/sample centered on 0.
|
||||
% We'll keep f_rad for the x-axis in that mode.
|
||||
end
|
||||
|
||||
if options.normalizeTo0dB
|
||||
p_lin = p_lin./ max(p_lin);
|
||||
p_lin = p_lin ./ max(p_lin);
|
||||
p_dbm = 10*log10(p_lin); % normalized to 0 dB
|
||||
ylab = "Normalized PSD";
|
||||
else
|
||||
@@ -372,36 +382,69 @@ classdef Signal
|
||||
ylab = "Power (dB/Hz)";
|
||||
end
|
||||
|
||||
% --- If requested, build wavelength axis from frequency offset ---
|
||||
if options.useWavelengthAxis && options.normalizeToNyquist == 0
|
||||
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]";
|
||||
|
||||
% Sort to ensure axis is ascending
|
||||
[x_vec, sortIdx] = sort(x_vec, 'ascend');
|
||||
p_dbm = p_dbm(sortIdx, :);
|
||||
else
|
||||
% Frequency or normalized axes
|
||||
if options.normalizeToNyquist == 0
|
||||
x_vec = f_GHz;
|
||||
x_label = "Frequency in GHz";
|
||||
else
|
||||
x_vec = f_rad; % normalized frequency in rad/sample
|
||||
x_label = "Normalized Frequency";
|
||||
end
|
||||
end
|
||||
|
||||
figure(options.fignum);
|
||||
ax = gca;
|
||||
hold on
|
||||
|
||||
if isempty(options.color)
|
||||
hLine = plot(w,p_dbm,'DisplayName',options.displayname,'LineWidth',1);
|
||||
else
|
||||
hLine = plot(w,p_dbm,'DisplayName',options.displayname,'LineWidth',1,'Color',options.color);
|
||||
for s = 1:min(size(p_dbm))
|
||||
if isempty(options.color)
|
||||
plot(x_vec, p_dbm(:,s), 'DisplayName', options.displayname, 'LineWidth', 1);
|
||||
else
|
||||
plot(x_vec, p_dbm(:,s), 'DisplayName', options.displayname, 'LineWidth', 1, 'Color', options.color);
|
||||
end
|
||||
end
|
||||
|
||||
% If user wants to limit the number of lines, check and remove old lines
|
||||
% Limit number of lines if requested
|
||||
if ~isempty(options.max_num_lines) && options.max_num_lines > 0
|
||||
allLines = findall(ax, 'Type', 'Line');
|
||||
if length(allLines) > options.max_num_lines
|
||||
% Sort lines by creation order. Usually, the oldest lines appear first in allLines.
|
||||
% If needed, you can sort by UserData or other criteria.
|
||||
numToRemove = length(allLines) - options.max_num_lines;
|
||||
delete(allLines(1:numToRemove));
|
||||
end
|
||||
end
|
||||
|
||||
if options.normalizeToNyquist == 0
|
||||
xlabel("Frequency in GHz");
|
||||
edgetick = 2^(nextpow2(obj.fs*1e-9));
|
||||
xticks(-edgetick:32:edgetick);
|
||||
xlim([100*round(min(w)/100,1)-10, 100*round(max(w)/100,1)+10])
|
||||
xlim([-128 128]);%256GSa/s
|
||||
% Axis labels and limits
|
||||
xlabel(x_label);
|
||||
|
||||
if options.useWavelengthAxis && options.normalizeToNyquist == 0
|
||||
xlim([min(x_vec) max(x_vec)]);
|
||||
else
|
||||
xlabel("Normalized Frequency");
|
||||
xlim([-pi, pi]);
|
||||
if options.normalizeToNyquist == 0
|
||||
% 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)]);
|
||||
else
|
||||
xlim([-pi, pi]);
|
||||
end
|
||||
end
|
||||
|
||||
ylabel(ylab);
|
||||
@@ -409,24 +452,23 @@ classdef Signal
|
||||
try
|
||||
ylim([max(min(floor(min(p_dbm))-3, ax.YLim(1)),-40), min(max(ceil(max(p_dbm))+3, ax.YLim(2)),10)]);
|
||||
catch
|
||||
ylim([floor(min(p_dbm))-3, ceil(max(p_dbm))+3]);
|
||||
ylim([floor(min(p_dbm,[],'all'))-3, ceil(max(p_dbm,[],'all'))+3]);
|
||||
end
|
||||
|
||||
if options.normalizeTo0dB
|
||||
% ylim([-40, 3]);
|
||||
ylim([floor(min(p_dbm))-3, ceil(max(p_dbm))+3]);
|
||||
ylim([floor(min(p_dbm,[],'all'))-3, ceil(max(p_dbm,[],'all'))+3]);
|
||||
else
|
||||
ylim([floor(min(p_dbm))-3, ceil(max(p_dbm))+3]);
|
||||
ylim([floor(min(p_dbm,[],'all'))-3, ceil(max(p_dbm,[],'all'))+3]);
|
||||
end
|
||||
|
||||
yticks(-200:10:10);
|
||||
grid on;% grid minor;
|
||||
grid on;
|
||||
legend
|
||||
% legend('Interpreter','none');
|
||||
|
||||
end
|
||||
|
||||
|
||||
|
||||
function move_it_spectrum(obj,options)
|
||||
arguments
|
||||
obj
|
||||
@@ -554,7 +596,7 @@ classdef Signal
|
||||
options.unit power_notation = power_notation.dBm
|
||||
end
|
||||
|
||||
pow = mean(abs(obj.signal).^2);
|
||||
pow = sum(mean(abs(obj.signal).^2));
|
||||
|
||||
switch options.unit
|
||||
case power_notation.dBm
|
||||
@@ -669,9 +711,9 @@ classdef Signal
|
||||
options.fs_ref = 0;
|
||||
options.debug_plots = 0;
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
S = {};
|
||||
inverted = -1;
|
||||
sequenceFound = 0;
|
||||
@@ -715,25 +757,25 @@ classdef Signal
|
||||
findpeaks(abs(co./max(co)),'MinPeakDistance',length(b)/2,'MinPeakHeight',0.2,'NPeaks',maxpeaknum,'SortStr','descend')
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
shifts = lags(pkpos);
|
||||
sequenceStarts = shifts;
|
||||
shifts = shifts(shifts>=0);
|
||||
|
||||
if numel(shifts) > 0
|
||||
|
||||
|
||||
%Cut occurences of ref signal from signal (only positive shifts)
|
||||
if all(sign(co(pkpos))==-1)
|
||||
inverted = 1;
|
||||
end
|
||||
|
||||
|
||||
for c = shifts
|
||||
sig = obj.delay(-c,'mode','samples');
|
||||
sig.signal = sig.signal(1:length(b));% .* -inverted;
|
||||
S{end+1,1} = sig;
|
||||
end
|
||||
|
||||
|
||||
% %return/keep the sinal with the highest correlation (only within positive shifts)
|
||||
% [~,idx]=max(pks);
|
||||
% obj.signal = S{idx}.signal;
|
||||
@@ -741,7 +783,7 @@ classdef Signal
|
||||
% swap = S{1};
|
||||
% S{1} = S{idx};
|
||||
% S{idx} = swap;
|
||||
|
||||
|
||||
for c = 1:numel(shifts)
|
||||
S{c}.logbook = [];
|
||||
end
|
||||
@@ -770,10 +812,6 @@ classdef Signal
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
%%
|
||||
function obj = filter(obj,a,b)
|
||||
|
||||
@@ -934,8 +972,8 @@ classdef Signal
|
||||
nn=histcounts(data_ind_y(n,:),1:histpoints+1);
|
||||
hist_data(:,n)=flip(nn.'); %without flip, the eye is upside down :-(
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
plot_data = 20*log10(hist_data);
|
||||
plot_data(plot_data==-Inf) = 0;
|
||||
@@ -970,7 +1008,7 @@ classdef Signal
|
||||
end
|
||||
xlabel('Time in ps')
|
||||
|
||||
|
||||
|
||||
|
||||
% add information
|
||||
|
||||
@@ -1091,7 +1129,7 @@ classdef Signal
|
||||
x_tickstring = sprintfc('%.2f', linspace(0, 2/fsym, 8) .* 1e12);
|
||||
xticklabels(x_tickstring);
|
||||
|
||||
grid off
|
||||
grid off
|
||||
end
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user