Files
imdd_silas/Classes/02_optical/Optical_Multiplex.m

183 lines
6.4 KiB
Matlab
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
classdef Optical_Multiplex < handle
% Takes a cell array of signals
% returns a total field signal
% WDM spacing is given in wavelength plan OR via delta_F
% The grid is stored in the output signal -> the demux will ideally
% look this up and use this as the demux frequencies...
% signal_cell = {Opt_sig_1, Opt_sig_2};
% Opt_sig_wdm = Optical_Multiplex("fs_in",Opt_sig.fs,"fs_out",4*Opt_sig.fs,...
% "lambda_center",1310,"random_key",0,"filtype",1,"B",200e9,"delta_f",400e9).process(signal_cell);
properties(Access=public)
fs_in
fs_out
lambda_center
delta_f
random_key
attenuation
B
mgauss
filtype
c = physconst('lightspeed')
f_center
f_T
lambda_T
df_T
end
methods (Access=public)
function obj = Optical_Multiplex(options)
%NAME Construct an instance of this class
% Detailed explanation goes here
arguments
options.fs_in
options.fs_out
options.lambda_center
options.B = 200e9
options.mgauss = 3
options.filtype = 2
options.delta_f = 0
options.random_key
options.attenuation = 0;
end
%
fn = fieldnames(options);
for n = 1:numel(fn)
try
obj.(fn{n}) = options.(fn{n});
end
end
end
function signalclass_out = process(obj,signalclasses_in)
% actual processing of the signal (steps 1. - 3.)
signalclass_out = obj.process_(signalclasses_in);
% append to logbook
lbdesc = ['Opt. Mux. '];
signalclass_out = signalclass_out.logbookentry(lbdesc);
end
function data_out = process_(obj,data_in)
%METHOD1 Summary of this method goes here
% Detailed explanation goes here
arguments(Input)
obj
data_in cell
end
% assert(data_in{1}.fs == obj.fs_in,'Sampling rate');
att = 1/10^(obj.attenuation/10);
N = numel(data_in);
w = obj.fs_out/data_in{1}.fs;
blocklen_in = length(data_in{1});
blocklen_out = w*blocklen_in;
freqaxis = linspace(-obj.fs_out/2, obj.fs_out/2, blocklen_out+1);
obj.f_center = obj.c/(obj.lambda_center.*1e-9);
if obj.random_key ~= 0
res = freqaxis(2)-freqaxis(1);
R = RandStream("twister","Seed",obj.random_key);
laser_frequency_imperfection = res .* round(R.randn(N,1)*10); %in mutliples of the fft resolution, i.e. the distance between two freq. bins
else
laser_frequency_imperfection = zeros(blocklen_in,1);
end
obj.f_T = [];
obj.df_T = [];
polrots = [];
for o = 1:N
if obj.delta_f ~= 0
% user defined a channel spacing in GHz. Build plan
% left and right from zero
obj.df_T(o) = (-length(data_in)/2-0.5+o) .* obj.delta_f;
obj.df_T(o) = obj.df_T(o)+ laser_frequency_imperfection(o);
obj.f_T = [obj.f_T obj.f_center+obj.df_T(o)];
else
%center frequencies of channels
obj.f_T = [obj.f_T obj.c/(data_in{o}.lambda)];
obj.lambda_T = [obj.lambda_T data_in{o}.lambda];
%difference between mid frequency of MUX and channels
obj.df_T = [obj.df_T obj.f_center - obj.f_T(o)];
end
% adapt frequency shifts to match the FFT grid! Find nearest grid point
[glitch(o),pos] = min(abs( freqaxis-obj.df_T(o) ));
obj.df_T(o) = freqaxis(pos);
polrots = [polrots, data_in{o}.polrot];
end
obj.lambda_T = obj.c ./ (obj.f_center-obj.df_T);
obj.B = 200e9; %200GHz
faxis = linspace(-obj.fs_out/2,obj.fs_out/2, blocklen_out+1);%generates arow vector faxis of blocklen+1 points linearly spaced between and including -para.fs/2 and para.fs/2
faxis = ifftshift(faxis(1:end-1));
switch obj.filtype
case 1
H =exp(-(faxis/obj.B).^(2*obj.mgauss)*log(2)*2^(2*obj.mgauss-1)).';
case 2
H=zeros(length(faxis),1);
H(find(abs(faxis)<=obj.B/2))=1;
case 3
H = 1;
end
x_envelopes = NaN([blocklen_out N]);
y_envelopes = x_envelopes;
% ---- OPTIMIZED: Pre-compute all LO phases as [blocklen_out × N] matrix ----
time_idx = (0:blocklen_out-1).'; % [blocklen_out × 1]
lo_phases = mod(2*pi * time_idx * obj.df_T / obj.fs_out, 2*pi); % [blocklen_out × N]
lo_all = cos(lo_phases) + 1i*sin(lo_phases); % [blocklen_out × N]
% Collect all resampled signals first (still requires loop due to cell array)
x_signals = zeros(blocklen_out, N);
y_signals = zeros(blocklen_out, N);
for o = 1:N
data_in_resampled = data_in{o}.resample("fs_out", obj.fs_out);
x_signals(:, o) = data_in_resampled.signal(:, 1);
y_signals(:, o) = data_in_resampled.signal(:, 2);
end
% ---- VECTORIZED: Batched FFT/IFFT for all channels ----
% Apply filter to all channels at once
x_filtered = ifft(fft(x_signals) .* H); % [blocklen_out × N]
y_filtered = ifft(fft(y_signals) .* H); % [blocklen_out × N]
% Apply attenuation and LO shift to all channels
x_envelopes = att .* x_filtered .* lo_all; % [blocklen_out × N]
y_envelopes = att .* y_filtered .* lo_all; % [blocklen_out × N]
data_out = data_in_resampled;
data_out.signal = [sum(x_envelopes,2), sum(y_envelopes,2)];
data_out.lambda = obj.lambda_T;
data_out.polrot = polrots;
end
end
methods (Access=private)
% Cant be seen from outside! So put all your functions here that can/
% shall not be called from outside
end
end