WDM code added (Pol Cont., Opt MUX/DEMUX, Opt Atten, DP_Fiber) -> the codebase is not optimized to always work with dp signals!
172 lines
5.6 KiB
Matlab
172 lines
5.6 KiB
Matlab
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;
|
|
|
|
for o = 1:N
|
|
|
|
pha = mod(2*pi*(0:blocklen_out-1)*obj.df_T(o)/obj.fs_out,2*pi).';
|
|
lo = cos(pha)+1i*sin(pha);
|
|
data_in_resampled = data_in{o}.resample("fs_out",obj.fs_out);
|
|
|
|
res_env = ifft(fft(data_in_resampled.signal(:,1)).*H);
|
|
x_envelopes(:,o) = att.*res_env.*lo;
|
|
|
|
res_env = ifft(fft(data_in_resampled.signal(:,2)).*H);
|
|
y_envelopes(:,o) = att.*res_env.*lo;
|
|
|
|
end
|
|
|
|
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
|