WIP - implementation and debugging of 224 Gbd PAM4 system
This commit is contained in:
148
Classes/AWG.m
148
Classes/AWG.m
@@ -18,7 +18,6 @@ classdef AWG
|
|||||||
lpf_active = 0;
|
lpf_active = 0;
|
||||||
lpf_type ;
|
lpf_type ;
|
||||||
f_cutoff ;
|
f_cutoff ;
|
||||||
lowpass ;
|
|
||||||
|
|
||||||
signal_length;
|
signal_length;
|
||||||
H_lpf;
|
H_lpf;
|
||||||
@@ -32,7 +31,7 @@ classdef AWG
|
|||||||
% Detailed explanation goes here
|
% Detailed explanation goes here
|
||||||
|
|
||||||
arguments
|
arguments
|
||||||
options.preset = [] ;
|
options.preset = [] ;
|
||||||
options.kover = 16;
|
options.kover = 16;
|
||||||
options.repetitions = 1;
|
options.repetitions = 1;
|
||||||
options.normalize = 1;
|
options.normalize = 1;
|
||||||
@@ -41,62 +40,57 @@ classdef AWG
|
|||||||
options.dac_min = -0.5;
|
options.dac_min = -0.5;
|
||||||
options.dac_max = 0.5;
|
options.dac_max = 0.5;
|
||||||
options.skew_active = 0;
|
options.skew_active = 0;
|
||||||
options.awg_skew = 0;
|
options.awg_skew = 0;
|
||||||
options.lpf_active = 0;
|
options.lpf_active = 0;
|
||||||
options.lpf_type = 0;
|
options.lpf_type = 0;
|
||||||
options.f_cutoff = 32e9;
|
options.f_cutoff = 32e9;
|
||||||
options.lowpass = 1;
|
|
||||||
end
|
end
|
||||||
|
|
||||||
if isempty(options.preset)
|
fn = fieldnames(options);
|
||||||
obj.skew_active = 0;
|
for n = 1:numel(fn)
|
||||||
obj.lpf_active = 0;
|
try
|
||||||
|
obj.(fn{n}) = options.(fn{n});
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
elseif options.preset == "M8196A"
|
if options.preset == "M8196A"
|
||||||
% M8196A (92GBd) https://www.keysight.com/us/en/product/M8196A/92-gsa-s-arbitrary-waveform-generators.html
|
% M8196A (92GBd) https://www.keysight.com/us/en/product/M8196A/92-gsa-s-arbitrary-waveform-generators.html
|
||||||
obj.dac_max = 0.5;
|
obj.dac_max = 0.5;
|
||||||
obj.dac_min = -.5;
|
obj.dac_min = -.5;
|
||||||
obj.lowpass = 1; %LP
|
|
||||||
obj.f_cutoff = 50e9;
|
obj.f_cutoff = 50e9;
|
||||||
elseif options.preset == "M8199B"
|
elseif options.preset == "M8199B"
|
||||||
%https://www.keysight.com/us/en/assets/3120-1465/data-sheets/M8199A-128-256-GSa-s-Arbitrary-Waveform-Generator.pdf
|
%https://www.keysight.com/us/en/assets/3120-1465/data-sheets/M8199A-128-256-GSa-s-Arbitrary-Waveform-Generator.pdf
|
||||||
|
% obj.fdac = 256e9;
|
||||||
|
obj.dac_max = 0.5;
|
||||||
|
obj.dac_min = -.5;
|
||||||
|
obj.f_cutoff = 80e9;
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
obj.kover = options.kover; %oversampling factor e.g. 16
|
|
||||||
obj.repetitions = options.repetitions; %repeat the signal to generate a longer sequence?
|
|
||||||
obj.fdac = options.fdac;
|
|
||||||
obj.normalize = options.normalize;%want to normalize at first? either 0 or 1
|
|
||||||
obj.bit_resolution = options.bit_resolution;%bit res. of quantizer (e.g. 5 bit)
|
|
||||||
obj.dac_min = options.dac_min;
|
|
||||||
obj.dac_max = options.dac_max;
|
|
||||||
|
|
||||||
obj.lpf_active = options.lpf_active;
|
|
||||||
|
|
||||||
obj.skew_active = options.skew_active;
|
|
||||||
obj.awg_skew = options.awg_skew;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
function signalclass_out = process(obj,signalclass_in)
|
function signalclass_out = process(obj,signalclass_in)
|
||||||
|
|
||||||
% actual processing of the signal (steps 1. - 3.)
|
% actual processing of the signal (steps 1. - 3.)
|
||||||
signalclass_in.signal = obj.process_(signalclass_in.signal);
|
signalclass_in.signal = obj.process_(signalclass_in.signal);
|
||||||
|
|
||||||
% 4. Apply LPF on the signal
|
% 4. Apply LPF on the signal
|
||||||
if obj.lpf_active
|
if obj.lpf_active
|
||||||
lpf = Filter('filtdegree',4,"f_cutoff",obj.f_cutoff,"fsamp",obj.kover*obj.fdac,"filterType",filtertypes.bessel_inp);
|
lpf = Filter('filtdegree',5,"f_cutoff",obj.f_cutoff,"fsamp",obj.kover*obj.fdac,"filterType",obj.lpf_type);
|
||||||
signalclass_in = lpf.process(signalclass_in);
|
signalclass_in = lpf.process(signalclass_in);
|
||||||
end
|
end
|
||||||
|
|
||||||
% cast the inform. signal to electrical signal
|
% cast the inform. signal to electrical signal
|
||||||
signalclass_in = Electricalsignal(signalclass_in,"fs",obj.fdac*obj.kover,"logbook",signalclass_in.logbook);
|
signalclass_in = Electricalsignal(signalclass_in,"fs",obj.fdac*obj.kover,"logbook",signalclass_in.logbook);
|
||||||
|
|
||||||
% append to logbook
|
% append to logbook
|
||||||
signalclass_in = signalclass_in.logbookentry();
|
signalclass_in = signalclass_in.logbookentry();
|
||||||
|
|
||||||
% write to output
|
% write to output
|
||||||
signalclass_out = signalclass_in;
|
signalclass_out = signalclass_in;
|
||||||
|
|
||||||
end
|
end
|
||||||
@@ -106,25 +100,24 @@ classdef AWG
|
|||||||
% Detailed explanation goes here
|
% Detailed explanation goes here
|
||||||
arguments(Input)
|
arguments(Input)
|
||||||
obj
|
obj
|
||||||
data_in
|
data_in
|
||||||
end
|
end
|
||||||
|
|
||||||
arguments(Output)
|
arguments(Output)
|
||||||
elec_out
|
elec_out
|
||||||
end
|
end
|
||||||
|
|
||||||
obj.signal_length = length(data_in);
|
obj.signal_length = length(data_in);
|
||||||
|
|
||||||
if obj.normalize
|
if obj.normalize
|
||||||
% 5.1. Normalize the signal to 1 Vpp and set the amplitude of the signal
|
% 0a Normalize the signal to 1 Vpp and set the amplitude of the signal
|
||||||
data_in = data_in/(max(data_in)-min(data_in));
|
data_in = data_in/(max(data_in)-min(data_in));
|
||||||
else
|
else
|
||||||
% 5.1. Cut the Signal at -1 and 1 and scale to amplitude
|
% 0b Cut the Signal at -1 and 1 and scale to amplitude
|
||||||
data_in(data_in > 1) = 1;
|
data_in(data_in > 1) = 1;
|
||||||
data_in(data_in < -1) = -1;
|
data_in(data_in < -1) = -1;
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
% 1. Quantize the signal
|
% 1. Quantize the signal
|
||||||
if obj.bit_resolution>0
|
if obj.bit_resolution>0
|
||||||
elec_out = obj.quantization(data_in) ;
|
elec_out = obj.quantization(data_in) ;
|
||||||
@@ -139,9 +132,7 @@ classdef AWG
|
|||||||
% 3. Add skew
|
% 3. Add skew
|
||||||
if obj.skew_active
|
if obj.skew_active
|
||||||
elec_out = obj.skew(elec_out);
|
elec_out = obj.skew(elec_out);
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -194,92 +185,5 @@ classdef AWG
|
|||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
function lpf_out = lpf(obj,x_in)
|
|
||||||
lpf_out = ifft(obj.H_lpf.*fft(x_in));
|
|
||||||
end
|
|
||||||
|
|
||||||
function H = buildFilter(obj,filterType)
|
|
||||||
|
|
||||||
filtdegree = 3;
|
|
||||||
fsimu = obj.kover*obj.fdac;
|
|
||||||
|
|
||||||
rp = 0.5; %passband ripple
|
|
||||||
rs = 0.5; %stopband ripple
|
|
||||||
|
|
||||||
switch filterType
|
|
||||||
case 1
|
|
||||||
|
|
||||||
% Bessel filter, impulse invariant transformed
|
|
||||||
|
|
||||||
[B, A] = besself(filtdegree, 2*pi*obj.f_cutoff);
|
|
||||||
[B ,A] = impinvar(B,A,fsimu);
|
|
||||||
|
|
||||||
case 2
|
|
||||||
|
|
||||||
% Bessel filter, impulse bilinear transformed
|
|
||||||
|
|
||||||
[Z, P, K] = besself(filtdegree, 2*pi*obj.f_cutoff);
|
|
||||||
[Z ,P, K] = bilinear(Z,P,K,fsimu);
|
|
||||||
[B ,A] = zp2tf(Z ,P ,K);
|
|
||||||
|
|
||||||
case 3
|
|
||||||
|
|
||||||
% Butterworth filter
|
|
||||||
if obj.lowpass == 1 %lowpass
|
|
||||||
[B, A] = butter(filtdegree, obj.f_cutoff/(fsimu/2),'low');
|
|
||||||
else % highpass
|
|
||||||
[B, A] = butter(filtdegree, obj.f_cutoff/(fsimu/2),'high');
|
|
||||||
end
|
|
||||||
|
|
||||||
case 4
|
|
||||||
|
|
||||||
% Chebyshev 1 filter
|
|
||||||
|
|
||||||
[B, A] = cheby1(filtdegree,rp, obj.f_cutoff/(fsimu/2));
|
|
||||||
|
|
||||||
case 5
|
|
||||||
|
|
||||||
% Chebyshev 2 filter
|
|
||||||
|
|
||||||
[B, A] = cheby2(filtdegree,rs, obj.f_cutoff/(fsimu/2));
|
|
||||||
|
|
||||||
case 6
|
|
||||||
|
|
||||||
% Elliptic filter
|
|
||||||
|
|
||||||
[B, A] = ellip(filtdegree,rp,rs,obj.f_cutoff/(fsimu/2));
|
|
||||||
|
|
||||||
case 7
|
|
||||||
|
|
||||||
% Hamming filter
|
|
||||||
|
|
||||||
g=(filtdegree-1)/2;
|
|
||||||
wc=obj.f_cutoff/(fsimu/2);
|
|
||||||
B = wc*sinc(wc*(-g:g)).*hamming(filtdegree)';
|
|
||||||
A=1;
|
|
||||||
|
|
||||||
case 8
|
|
||||||
|
|
||||||
% Raised Cosine filter
|
|
||||||
|
|
||||||
B = firrcos(filtdegree,obj.f_cutoff,para.df,fsimu);
|
|
||||||
A=1;
|
|
||||||
|
|
||||||
case 9
|
|
||||||
|
|
||||||
% Sinc filter
|
|
||||||
|
|
||||||
g=(filtdegree-1)/2;
|
|
||||||
wc=obj.f_cutoff/(fsimu/2);
|
|
||||||
B = wc*sinc(wc*(-g:g));
|
|
||||||
A=1;
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
H = freqz(B, A, obj.repetitions*obj.kover*obj.signal_length,'whole');
|
|
||||||
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -1,155 +1,162 @@
|
|||||||
classdef Amplifier
|
classdef Amplifier
|
||||||
%UNTITLED Summary of this class goes here
|
%UNTITLED Summary of this class goes here
|
||||||
% Detailed explanation goes here
|
% Detailed explanation goes here
|
||||||
|
|
||||||
properties
|
|
||||||
type
|
|
||||||
amp_mode
|
|
||||||
amplification_db
|
|
||||||
|
|
||||||
|
properties
|
||||||
|
amp_mode
|
||||||
|
gain_mode
|
||||||
nase_mode
|
nase_mode
|
||||||
|
|
||||||
|
amplification_db
|
||||||
noifig
|
noifig
|
||||||
|
|
||||||
saturation_mode
|
|
||||||
saturation_power
|
|
||||||
|
|
||||||
fsimu
|
fsimu
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
methods
|
methods
|
||||||
function obj = Amplifier(options)
|
function obj = Amplifier(options)
|
||||||
%UNTITLED Construct an instance of this class
|
%UNTITLED Construct an instance of this class
|
||||||
% Detailed explanation goes here
|
% Detailed explanation goes here
|
||||||
arguments
|
arguments
|
||||||
options.type
|
options.amp_mode amp_mode = amp_mode.ideal_no_noise
|
||||||
options.amp_mode
|
options.gain_mode gain_mode = gain_mode.output_power
|
||||||
options.amplification_db
|
options.nase_mode nase_mode = nase_mode.pass_ase
|
||||||
|
|
||||||
options.nase_mode = 0;
|
options.amplification_db double = 0
|
||||||
options.noifig = 0;
|
|
||||||
|
options.noifig double = 0;
|
||||||
options.saturation_mode = 0;
|
|
||||||
options.saturation_power = 0;
|
|
||||||
|
|
||||||
options.fsimu = []
|
|
||||||
end
|
end
|
||||||
|
|
||||||
obj.type = options.type;
|
fn = fieldnames(options);
|
||||||
obj.amp_mode = options.amp_mode;
|
for n = 1:numel(fn)
|
||||||
obj.amplification_db = options.amplification_db;
|
obj.(fn{n}) = options.(fn{n});
|
||||||
|
end
|
||||||
obj.nase_mode = options.nase_mode;
|
|
||||||
obj.noifig = options.noifig;
|
|
||||||
|
|
||||||
obj.saturation_mode = options.saturation_mode;
|
|
||||||
obj.saturation_power = options.saturation_power;
|
|
||||||
|
|
||||||
obj.fsimu = options.fsimu;
|
|
||||||
|
|
||||||
|
|
||||||
obj.saturation_power=1/1000*10^(obj.saturation_power/10);
|
|
||||||
|
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
function signalclass_out = process(obj,signalclass_in)
|
|
||||||
|
|
||||||
% actual processing of the signal (steps 1. - 3.)
|
function signalclass_out = process(obj,signalclass_in)
|
||||||
signalclass_in.signal = obj.process_(signalclass_in.signal);
|
|
||||||
|
|
||||||
% append to logbook
|
% actual processing of the signal
|
||||||
lbdesc = ['Amp '];
|
signalclass_in = obj.process_(signalclass_in);
|
||||||
|
|
||||||
|
% append to logbook
|
||||||
|
lbdesc = ['Amp '];
|
||||||
signalclass_in = signalclass_in.logbookentry(lbdesc);
|
signalclass_in = signalclass_in.logbookentry(lbdesc);
|
||||||
|
|
||||||
% write to output
|
% write to output
|
||||||
signalclass_out = signalclass_in;
|
signalclass_out = signalclass_in;
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function [X_out] = process_(obj,X_in)
|
||||||
|
|
||||||
function [y_out,nase] = process_(obj,x_in,optional)
|
|
||||||
|
|
||||||
arguments
|
|
||||||
obj
|
|
||||||
x_in = [];
|
|
||||||
|
|
||||||
optional.nase = 0;
|
|
||||||
end
|
|
||||||
|
|
||||||
%calc gain for output power mode, amp mode and saturated mode
|
%calc gain for output power mode, amp mode and saturated mode
|
||||||
a_lin = obj.calculateGain(x_in);
|
a_lin = obj.calculateGain(X_in.signal);
|
||||||
|
|
||||||
y_out = a_lin * x_in;
|
%apply amplification
|
||||||
|
X_in.signal = a_lin * X_in.signal;
|
||||||
|
|
||||||
|
% now, optical ase noise:
|
||||||
|
if class(X_in) == "Opticalsignal"
|
||||||
|
|
||||||
if obj.type == "ideal"
|
if obj.amp_mode == amp_mode.ideal_no_noise
|
||||||
|
|
||||||
%don't add/ remove noise, but scale it accordingly
|
%don't add/ remove noise, but scale it accordingly
|
||||||
if optional.nase ~= 0
|
X_in.nase = obj.onlyAmplifyAse(X_in.nase, a_lin);
|
||||||
nase=state.a^2*optional.nase;
|
|
||||||
|
elseif obj.amp_mode == amp_mode.edfa_increase_nase
|
||||||
|
|
||||||
|
%calculate ASE-noise
|
||||||
|
X_in.nase = obj.increaseAse(X_in.nase, a_lin, obj.noifig , X_in.lambda );
|
||||||
|
|
||||||
|
elseif obj.amp_mode == amp_mode.edfa_replace_nase
|
||||||
|
|
||||||
|
%calculate ASE-noise
|
||||||
|
X_in.nase = obj.replaceAse(X_in.nase, a_lin, obj.noifig , X_in.lambda );
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
elseif obj.type == "edfa"
|
if obj.nase_mode == nase_mode.generate_ase
|
||||||
|
|
||||||
|
nase = X_in.nase;
|
||||||
|
fs = X_in.fs;
|
||||||
|
dimension = size(X_in.signal);
|
||||||
|
|
||||||
%calculate ASE-noise
|
nase_numeric = obj.generateAseNoise(nase, fs, dimension);
|
||||||
if optional.nase ~= 0
|
|
||||||
Nase_old = state.gain^2*optional.nase ;
|
|
||||||
|
|
||||||
h = Constant.Planck;
|
[X_in.signal, osnr] = obj.applyAseToSignal(X_in.signal, nase_numeric);
|
||||||
c = Constant.LightSpeed;
|
|
||||||
|
|
||||||
Nase_new = 0.5* 10^(obj.noifig/10) * h*c/(lambda_T*1e-9) * (a_lin^2-1) ;
|
X_in.nase = 0;
|
||||||
|
|
||||||
|
elseif obj.nase_mode == nase_mode.pass_ase
|
||||||
|
|
||||||
|
X_in.nase = X_in.nase;
|
||||||
|
|
||||||
nase = Nase_old + Nase_new ;
|
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
pow_in_lin = mean(abs(x_in.^2)) ;
|
X_out = X_in;
|
||||||
pow_in_dbm = 10*log10(pow_in_lin)+30;
|
|
||||||
pow_out_lin = mean(abs(y_out.^2)) ;
|
|
||||||
pow_out_dbm = 10*log10(pow_out_lin)+30;
|
|
||||||
|
|
||||||
if obj.amp_mode == "output_power"
|
|
||||||
seemsright = pow_out_dbm == obj.amplification_db;
|
|
||||||
elseif obj.amp_mode == "gain"
|
|
||||||
seemsright = pow_out_dbm == pow_in_dbm + obj.amplification_db;
|
|
||||||
end
|
|
||||||
|
|
||||||
if ~seemsright
|
|
||||||
% warning("Amplifier output not correct, please check the reason");
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
function a_lin = calculateGain(obj,xin)
|
function a_lin = calculateGain(obj,xin)
|
||||||
|
|
||||||
if obj.amp_mode == "output_power"
|
if obj.gain_mode == gain_mode.output_power
|
||||||
|
|
||||||
%get linear gain for output power mode
|
%get linear gain for output power mode
|
||||||
pow_in = mean(abs(xin.^2)) ; % lin input power
|
pow_in = mean(abs(xin.^2)) ; % lin input power
|
||||||
pow_out = 10^(obj.amplification_db/10 - 3) ; % dBm to lin
|
pow_out = 10^(obj.amplification_db/10 - 3) ; % dBm to lin
|
||||||
a_lin = sqrt(pow_out/pow_in) ;
|
a_lin = sqrt(pow_out/pow_in) ;
|
||||||
|
|
||||||
elseif obj.amp_mode == "gain"
|
elseif obj.gain_mode == gain_mode.gain
|
||||||
|
|
||||||
%get linear gain for classic gain mode
|
%get linear gain for classic gain mode
|
||||||
a_lin=10^(obj.amplification_db/20);
|
a_lin=10^(obj.amplification_db/20);
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
if obj.saturation_mode
|
|
||||||
Pin = sum(mean((abs(xin)).^2, 2)) ;
|
|
||||||
|
|
||||||
gain_power=fzero(inline(['log(G/' num2str(a_lin^2,'%1.16e') ')/(1-G)-log(2)*' num2str(Pin,'%1.16e') '/' ...
|
|
||||||
num2str(obj.saturation_power,'%1.16e')],'G'),[1+eps,a_lin^2]);
|
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
function nase_amped = onlyAmplifyAse(~,nase_old, a_lin)
|
||||||
|
nase_amped = a_lin^2 * nase_old;
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function nase_new = calculateAseFromThisAmp(~, a_lin, noisefig, lambda)
|
||||||
|
h = Constant.Planck;
|
||||||
|
c = Constant.LightSpeed;
|
||||||
|
nase_new = 0.5* 10^(noisefig/10) * h*c/lambda * (a_lin^2-1) ;
|
||||||
|
end
|
||||||
|
|
||||||
|
function ase_increased = increaseAse(obj,nase_old, a_lin, noisefig, lambda)
|
||||||
|
|
||||||
|
nase_fromThisAmp = obj.calculateAseFromThisAmp(a_lin, noisefig, lambda);
|
||||||
|
|
||||||
|
nase_old = a_lin^2 * nase_old;
|
||||||
|
|
||||||
|
ase_increased = nase_old + nase_fromThisAmp;
|
||||||
|
end
|
||||||
|
|
||||||
|
function nase_new = replaceAse(~,a_lin, noisefig, lambda_nm)
|
||||||
|
|
||||||
|
nase_fromThisAmp = obj.calculateAseFromThisAmp(a_lin, noisefig, lambda_nm);
|
||||||
|
|
||||||
|
nase_new = nase_fromThisAmp;
|
||||||
|
end
|
||||||
|
|
||||||
|
function nase_numeric = generateAseNoise(~, nase, fs, dimension)
|
||||||
|
nase_numeric = (randn(dimension) + 1i*randn(dimension))*sqrt(nase/2*fs) ;
|
||||||
|
end
|
||||||
|
|
||||||
|
function [noisy_sig, osnr] = applyAseToSignal(~, opticalsignal, nase_numeric)
|
||||||
|
noisy_sig = opticalsignal + nase_numeric ;
|
||||||
|
osnr = pow2db(mean(abs(opticalsignal.^2))/mean(abs(nase_numeric.^2)));
|
||||||
|
disp(osnr);
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -6,13 +6,15 @@ classdef Filter
|
|||||||
H
|
H
|
||||||
filterType
|
filterType
|
||||||
f_cutoff
|
f_cutoff
|
||||||
|
lowpass
|
||||||
|
|
||||||
signal_length
|
signal_length
|
||||||
filtdegree
|
filtdegree
|
||||||
passband_ripple
|
passband_ripple
|
||||||
stopband_ripple
|
stopband_ripple
|
||||||
fsamp
|
fsamp
|
||||||
|
|
||||||
|
w
|
||||||
end
|
end
|
||||||
|
|
||||||
methods
|
methods
|
||||||
@@ -20,36 +22,34 @@ classdef Filter
|
|||||||
%FILTER Construct an instance of this class
|
%FILTER Construct an instance of this class
|
||||||
% Detailed explanation goes here
|
% Detailed explanation goes here
|
||||||
arguments
|
arguments
|
||||||
options.filterType = 1;
|
options.filterType filtertypes = filtertypes.bessel_inp ;
|
||||||
options.f_cutoff = 0;
|
options.f_cutoff = 0;
|
||||||
options.fsamp = 0;
|
options.fsamp = 0;
|
||||||
options.filtdegree = 3;
|
options.filtdegree = 3;
|
||||||
options.passband_ripple = 0.5;
|
options.passband_ripple = 0.5;
|
||||||
options.stopband_ripple = 0.5;
|
options.stopband_ripple = 0.5;
|
||||||
|
options.lowpass = 1;
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
obj.filterType = options.filterType;
|
|
||||||
|
|
||||||
obj.f_cutoff = options.f_cutoff;
|
fn = fieldnames(options);
|
||||||
obj.filtdegree = options.filtdegree;
|
for n = 1:numel(fn)
|
||||||
obj.passband_ripple = options.passband_ripple;
|
obj.(fn{n}) = options.(fn{n});
|
||||||
obj.stopband_ripple = options.stopband_ripple;
|
end
|
||||||
obj.fsamp = options.fsamp;
|
|
||||||
|
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
function signalclass_out = process(obj,signalclass_in)
|
function signalclass_out = process(obj,signalclass_in)
|
||||||
|
|
||||||
% actual processing of the signal
|
% actual processing of the signal
|
||||||
signalclass_in.signal = obj.process_(signalclass_in.signal);
|
signalclass_in.signal = obj.process_(signalclass_in.signal);
|
||||||
|
|
||||||
% append to logbook
|
% append to logbook
|
||||||
filterdesc = [num2str(obj.filtdegree),'. order ',char(obj.filterType),' filter with f_cutoff at ', num2str(obj.f_cutoff*1e-9), ' GHz.'];
|
filterdesc = [num2str(obj.filtdegree),'. order ',char(obj.filterType),' filter with f_cutoff at ', num2str(obj.f_cutoff*1e-9), ' GHz.'];
|
||||||
signalclass_in = signalclass_in.logbookentry(filterdesc);
|
signalclass_in = signalclass_in.logbookentry(filterdesc);
|
||||||
|
|
||||||
% write to output
|
% write to output
|
||||||
signalclass_out = signalclass_in;
|
signalclass_out = signalclass_in;
|
||||||
|
|
||||||
end
|
end
|
||||||
@@ -58,7 +58,7 @@ classdef Filter
|
|||||||
|
|
||||||
obj.signal_length = length(xin);
|
obj.signal_length = length(xin);
|
||||||
|
|
||||||
obj.H = obj.buildFilter(obj.filterType);
|
[obj.H,obj.w] = obj.buildFilter(obj.filterType);
|
||||||
|
|
||||||
yout = obj.applyFilter(xin);
|
yout = obj.applyFilter(xin);
|
||||||
|
|
||||||
@@ -70,8 +70,8 @@ classdef Filter
|
|||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
function H = buildFilter(obj,filterType)
|
function [H,w] = buildFilter(obj,filterType)
|
||||||
|
w = [];
|
||||||
rp = obj.passband_ripple; %passband ripple
|
rp = obj.passband_ripple; %passband ripple
|
||||||
rs = obj.stopband_ripple; %stopband ripple
|
rs = obj.stopband_ripple; %stopband ripple
|
||||||
|
|
||||||
@@ -143,9 +143,22 @@ classdef Filter
|
|||||||
B = wc*sinc(wc*(-g:g));
|
B = wc*sinc(wc*(-g:g));
|
||||||
A=1;
|
A=1;
|
||||||
|
|
||||||
|
case 10
|
||||||
|
|
||||||
|
% Gaussian Filter
|
||||||
|
%check if order ist multiple of 1/2
|
||||||
|
blocklen=obj.signal_length;
|
||||||
|
|
||||||
|
faxis=linspace(-obj.fsamp/2,obj.fsamp/2,blocklen+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));
|
||||||
|
|
||||||
|
H=exp(-((faxis)/(obj.f_cutoff*2)).^(2*obj.filtdegree)*log(2)*2^(2*obj.filtdegree-1));
|
||||||
end
|
end
|
||||||
|
|
||||||
H = freqz(B, A, obj.signal_length,'whole');
|
% Build Filter from coefficients
|
||||||
|
if filterType ~= 10
|
||||||
|
[H,w] = freqz(B, A, obj.signal_length,'whole');
|
||||||
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -71,7 +71,7 @@ classdef Scope
|
|||||||
function signalclass_out = process(obj,signalclass_in)
|
function signalclass_out = process(obj,signalclass_in)
|
||||||
|
|
||||||
% apply LPF
|
% apply LPF
|
||||||
lpf = Filter('filtdegree',4,"f_cutoff",obj.lpf_bw,"fsamp",obj.fsimu,"filterType",obj.filtertype);
|
lpf = Filter('filtdegree',3,"f_cutoff",obj.lpf_bw,"fsamp",obj.fsimu,"filterType",obj.filtertype);
|
||||||
signalclass_in = lpf.process(signalclass_in);
|
signalclass_in = lpf.process(signalclass_in);
|
||||||
|
|
||||||
% actual processing of the signal
|
% actual processing of the signal
|
||||||
|
|||||||
@@ -91,8 +91,7 @@ classdef Signal
|
|||||||
if isa(obj,'Electricalsignal')
|
if isa(obj,'Electricalsignal')
|
||||||
|
|
||||||
%convert to optical
|
%convert to optical
|
||||||
disp("Convert signal: elec. -> opt.!");
|
|
||||||
|
|
||||||
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);
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
10
Datatypes/amp_mode.m
Normal file
10
Datatypes/amp_mode.m
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
classdef amp_mode < int32
|
||||||
|
|
||||||
|
enumeration
|
||||||
|
ideal_no_noise (1)
|
||||||
|
edfa_increase_nase (2)
|
||||||
|
edfa_replace_nase (3)
|
||||||
|
% edfa_set_osnr (4) TODO: implement mode to achieve desired OSNR
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
@@ -10,6 +10,7 @@ classdef filtertypes < int32
|
|||||||
hamming (7)
|
hamming (7)
|
||||||
racos (8)
|
racos (8)
|
||||||
sinc (9)
|
sinc (9)
|
||||||
|
gaussian (10)
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|||||||
8
Datatypes/gain_mode.m
Normal file
8
Datatypes/gain_mode.m
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
classdef gain_mode < int32
|
||||||
|
|
||||||
|
enumeration
|
||||||
|
gain (1)
|
||||||
|
output_power (2)
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
8
Datatypes/nase_mode.m
Normal file
8
Datatypes/nase_mode.m
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
classdef nase_mode < int32
|
||||||
|
|
||||||
|
enumeration
|
||||||
|
generate_ase (1)
|
||||||
|
pass_ase (2)
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
14
Functions/functionSignatures.json
Normal file
14
Functions/functionSignatures.json
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
{
|
||||||
|
"_schemaVersion": "1.0.0",
|
||||||
|
"myFunc":
|
||||||
|
{
|
||||||
|
"inputs":
|
||||||
|
[
|
||||||
|
{"name":"in1", "kind":"required", "type":["numeric"], "purpose":"ID of item"},
|
||||||
|
{"name":"in2", "kind":"required", "type":["numeric"], "purpose":"# Items"},
|
||||||
|
{"name":"in3", "kind":"ordered", "type":["numeric"], "purpose":"Input Value"},
|
||||||
|
{"name":"Name1", "kind":"namevalue", "type":["logical","scalar"],"purpose":"Option"},
|
||||||
|
{"name":"Name2", "kind":"namevalue", "type":["char", "choices={'Default','Choice1','Choice2'}"]}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
34
Functions/myFunc.m
Normal file
34
Functions/myFunc.m
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
% myFunc Example function
|
||||||
|
% This function is called with any of these syntaxes:
|
||||||
|
%
|
||||||
|
% myFunc(in1, in2) accepts 2 required arguments.
|
||||||
|
% myFunc(in1, in2, in3) also accepts an optional 3rd argument.
|
||||||
|
% myFunc(___, NAME, VALUE) accepts one or more of the following name-value pair
|
||||||
|
% arguments. This syntax can be used in any of the previous syntaxes.
|
||||||
|
% * 'NAME1' with logical value
|
||||||
|
% * 'NAME2' with 'Default', 'Choice1', or 'Choice2'
|
||||||
|
function myFunc(reqA,reqB,varargin)
|
||||||
|
% Initialize default values
|
||||||
|
NV1 = true;
|
||||||
|
NV2 = 'Default';
|
||||||
|
posA = [];
|
||||||
|
|
||||||
|
if nargin > 3
|
||||||
|
if rem(nargin,2)
|
||||||
|
posA = varargin{1};
|
||||||
|
V = varargin(2:end);
|
||||||
|
else
|
||||||
|
V = varargin;
|
||||||
|
end
|
||||||
|
for n = 1:2:size(V,2)
|
||||||
|
switch V{n}
|
||||||
|
case 'Name1'
|
||||||
|
NV1 = V{n+1};
|
||||||
|
case 'Name2'
|
||||||
|
NV2 = V{n+1}
|
||||||
|
otherwise
|
||||||
|
error('Error.')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
clear all
|
%clear all
|
||||||
|
|
||||||
O = 15; %order of prbs
|
O = 17; %order of prbs
|
||||||
N = 2^(O-1); %length of prbs
|
N = 2^(O-1); %length of prbs
|
||||||
[~,seed] = prbs(O,1); %initialize first seed of prbs
|
[~,seed] = prbs(O,1); %initialize first seed of prbs
|
||||||
|
|
||||||
@@ -9,7 +9,7 @@ M = 4; %PAM-M
|
|||||||
bitpattern = zeros(N,log2(M));
|
bitpattern = zeros(N,log2(M));
|
||||||
|
|
||||||
% Symbol Rate
|
% Symbol Rate
|
||||||
fsym = 56e9;
|
fsym = 92e9;
|
||||||
% DAC Rate
|
% DAC Rate
|
||||||
fdac = 120e9;
|
fdac = 120e9;
|
||||||
% Simulation oversampling rate "k";
|
% Simulation oversampling rate "k";
|
||||||
@@ -22,25 +22,33 @@ fsimu = kover * fdac ;
|
|||||||
%CONSTRUCTION
|
%CONSTRUCTION
|
||||||
pam_mapper = PAMmapper(M,0);
|
pam_mapper = PAMmapper(M,0);
|
||||||
|
|
||||||
awg = AWG('preset','M8196A','fdac',fdac,'kover',kover,'lpf_active',0,'f_cutoff',80e9,'lpf_type',filtertypes.bessel_bilin);
|
awg = AWG('preset','M8199B','fdac',fdac,'kover',kover,'lpf_active',1,'f_cutoff',80e9,'lpf_type',filtertypes.gaussian);
|
||||||
|
|
||||||
%fil_tx = Filter('filtdegree',1,"f_cutoff",80e9,"fsamp",fdac,"filterType",filtertypes.bessel_bilin);
|
|
||||||
fil_tx = Filter('filtdegree',1,"f_cutoff",50e9,"fsamp",fdac,"filterType",filtertypes.bessel_bilin);
|
fil_tx = Filter('filtdegree',1,"f_cutoff",50e9,"fsamp",fdac,"filterType",filtertypes.bessel_inp);
|
||||||
|
|
||||||
u_pi = 3.5;
|
u_pi = 3.5;
|
||||||
vbias = (0.5*u_pi)-u_pi;
|
vbias = (0.5*u_pi)-u_pi;
|
||||||
extmodlaser = EML("mode",emlmodes.im_cosinus,"power",10,"fsimu",fsimu,"lambda",1550,"bias",vbias,"u_pi",u_pi,"linewidth",1000);
|
extmodlaser = EML("mode",emlmodes.im_cosinus,"power",5,"fsimu",fsimu,"lambda",1550,"bias",vbias,"u_pi",u_pi,"linewidth",0);
|
||||||
|
|
||||||
amp = Amplifier("amplification_db",10,"amp_mode","gain","type","ideal","saturation_mode",0,'saturation_power',10);
|
amp = Amplifier("amp_mode","ideal_no_noise","amplification_db",0,"gain_mode","output_power");
|
||||||
|
|
||||||
|
fib = Fiber("fsimu",fdac*kover,"fiber_length",0,"alpha",0.2,"D",17,"lambda0",1550);
|
||||||
|
|
||||||
|
%noise loading
|
||||||
|
zeroDB_attenuator = Amplifier("amp_mode","ideal_no_noise","gain_mode","output_power","amplification_db",0);
|
||||||
|
|
||||||
|
edfa_ = Amplifier("amp_mode","edfa_increase_nase","nase_mode","generate_ase","amplification_db",0,"noifig",33,"gain_mode","output_power");
|
||||||
|
|
||||||
|
rop_amplifier = Amplifier("amp_mode","ideal_no_noise","amplification_db",0,"gain_mode","output_power","nase_mode","pass_ase");
|
||||||
|
|
||||||
fib = Fiber("fsimu",fdac*kover,"fiber_length",2,"alpha",0.2,"D",17,"lambda0",1550);
|
|
||||||
|
|
||||||
phdiode = Photodiode("fsimu",fdac*kover,"dark_current",2e-08,"responsivity",1,"temperature",20);
|
phdiode = Photodiode("fsimu",fdac*kover,"dark_current",2e-08,"responsivity",1,"temperature",20);
|
||||||
|
|
||||||
fil_diode = Filter('filtdegree',4,"f_cutoff",70e9,"fsamp",fdac,"filterType",filtertypes.bessel_bilin);
|
fil_diode = Filter('filtdegree',1,"f_cutoff",70e9,"fsamp",fdac,"filterType",filtertypes.bessel_inp);
|
||||||
|
|
||||||
scp = Scope("fsimu",fdac*kover,"fadc",fadc,...
|
scp = Scope("fsimu",fdac*kover,"fadc",fadc,...
|
||||||
"delay",0,"fixed_delay",0,"lpf_bw",120e9,"filtertype",filtertypes.bessel_inp,...
|
"delay",0,"fixed_delay",0,"lpf_bw",113e9,"filtertype",filtertypes.butterworth,...
|
||||||
"samplingdelay",0,"rand_samplingdelay",0,"freq_offset",0,"samp_jitter",0,...
|
"samplingdelay",0,"rand_samplingdelay",0,"freq_offset",0,"samp_jitter",0,...
|
||||||
"adcresolution",6,"quantbuffer",0.1);
|
"adcresolution",6,"quantbuffer",0.1);
|
||||||
|
|
||||||
@@ -48,24 +56,24 @@ eq = EQ("K",2,"plottrain",0,"plotfinal",1,"training_length",2048,"Ne",[25,5,5],"
|
|||||||
|
|
||||||
%SIMULATE
|
%SIMULATE
|
||||||
|
|
||||||
|
|
||||||
% INFORMATION SIGNAL
|
% INFORMATION SIGNAL
|
||||||
for i = 1:log2(M)
|
for i = 1:log2(M)
|
||||||
[bitpattern(:,i),seed] = prbs(O,N,seed);
|
[bitpattern(:,i),seed] = prbs(O,N,seed);
|
||||||
end
|
end
|
||||||
|
|
||||||
X = Informationsignal(bitpattern);
|
bits = Informationsignal(bitpattern);
|
||||||
|
|
||||||
PAMSIG = pam_mapper.map(X);
|
mod_out = pam_mapper.map(bits);
|
||||||
|
reference = mod_out;
|
||||||
X = PAMSIG;
|
mod_out.signal = applyPulseShaping(mod_out.signal,fsym,fdac);
|
||||||
|
|
||||||
X.signal = applyPulseShaping(PAMSIG.signal,fsym,fdac);
|
|
||||||
|
|
||||||
% ELECTRICAL DOMAIN
|
% ELECTRICAL DOMAIN
|
||||||
X = awg.process(X);
|
X = awg.process(mod_out);
|
||||||
|
|
||||||
X = fil_tx.process(X);
|
% X = fil_tx.process(X);
|
||||||
|
%X = fil_tx.process(X);
|
||||||
|
|
||||||
|
X = X.normalize;
|
||||||
|
|
||||||
% OPTICAL DOMAIN
|
% OPTICAL DOMAIN
|
||||||
X = extmodlaser.process(X);
|
X = extmodlaser.process(X);
|
||||||
@@ -74,6 +82,10 @@ X = amp.process(X);
|
|||||||
|
|
||||||
X = fib.process(X);
|
X = fib.process(X);
|
||||||
|
|
||||||
|
% X = zeroDB_attenuator.process(X);
|
||||||
|
% X = edfa_.process(X);
|
||||||
|
% X = rop_amplifier.process(X);
|
||||||
|
|
||||||
X = phdiode.process(X);
|
X = phdiode.process(X);
|
||||||
|
|
||||||
X = fil_diode.process(X);
|
X = fil_diode.process(X);
|
||||||
@@ -84,15 +96,25 @@ X = scp.process(X);
|
|||||||
X = X.resample("fs_out",2*fsym,"fs_in",fadc);
|
X = X.resample("fs_out",2*fsym,"fs_in",fadc);
|
||||||
|
|
||||||
% INFORMATION SIGNAL
|
% INFORMATION SIGNAL
|
||||||
X = eq.process(X,PAMSIG);
|
X = X.normalize;
|
||||||
|
X = eq.process(X,reference);
|
||||||
|
rx_series = X.signal;
|
||||||
|
|
||||||
X = pam_mapper.demap(X);
|
X = pam_mapper.demap(X);
|
||||||
|
|
||||||
|
|
||||||
% BER
|
% BER
|
||||||
[bits,errors,BER] = calc_ber(X.signal(:,10000:end-21),bitpattern(10000:end-20,:)',0);
|
[bits,errors,BER] = calc_ber(X.signal(:,10000:end-20),bitpattern(10000:end-20,:)',0);
|
||||||
|
|
||||||
disp(['BER: ', sprintf('%2E',BER)]);
|
disp(['BER: ', sprintf('%2E',BER)]);
|
||||||
|
|
||||||
|
|
||||||
|
figure()
|
||||||
|
hold on
|
||||||
|
plot(reference.signal);
|
||||||
|
plot(rx_series);
|
||||||
|
hold off
|
||||||
|
|
||||||
disp(X.logbook);
|
disp(X.logbook);
|
||||||
|
|
||||||
function yout = applyPulseShaping(xin,fsym,fdac)
|
function yout = applyPulseShaping(xin,fsym,fdac)
|
||||||
Reference in New Issue
Block a user