Code for Deliverable 05

This commit is contained in:
Silas Oettinghaus
2024-09-02 09:00:41 +02:00
parent 17a1dfbbd5
commit bb228ae2bd
20 changed files with 1094 additions and 73 deletions

View File

@@ -53,19 +53,22 @@ classdef Opticalsignal < Signal
function cspr = cspr(obj)
carrier_power_dbm = pow2db( abs(mean(obj.signal)).^2 )+30; % dB -> +30 -> dBm
carrier_power_dbm = pow2db( abs(mean(obj.signal)).^2 ) +30; % dB -> +30 -> dBm
signal_power_dbm = obj.power;
cspr = carrier_power_dbm-signal_power_dbm;
carr_lin = abs(mean(obj.signal)).^2;
sign_lin = mean(abs(obj.signal).^2);
cspr_lin = pow2db(carr_lin/sign_lin);
%carrier power is the mean value of the overall signal -> dc part
c = abs(mean(obj.signal)).^2;
s = mean(abs(obj.signal).^2);
cspr_ = 10*log10(c / s);
%signal power is now only the "fluctuation"/ i.e. the ac part
s = mean( abs(obj.signal-mean(obj.signal)).^2 );
cspr = 10*log10(c / s);
cspr =carrier_power_dbm-signal_power_dbm;
end

View File

@@ -264,8 +264,7 @@ classdef Signal
% spectrum_plot(obj.signal,options.fsamp,options.figurename,options.displayname);
N = 2^(nextpow2(length(obj.signal))-6);
N = 2^(nextpow2(length(obj.signal))-8);
[p_lin,w] = pwelch(obj.signal,hanning(N),N/2,N,obj.fs,"centered","power","mean");
p_dbm = 10*log10(p_lin)+30; %dB to dBm in case of "power"
@@ -278,7 +277,7 @@ classdef Signal
ylabel("Power (dBm)");
xlim([-obj.fs/2 obj.fs/2].*1e-9)
edgetick = 2^(nextpow2(obj.fs*1e-9));
xticks([-edgetick:16:edgetick]);
% xticks([-edgetick:16:edgetick]);
xlim([-244, 244])
ylim([-120,-0]);
yticks([-200:10:10]);
@@ -329,7 +328,7 @@ classdef Signal
case power_notation.mW
pow_pk = pow_pk .* 1e3; %mW
case power_notation.W
%pow = pow % Watt
pow_pk = pow_pk; % Watt
end
end
@@ -562,6 +561,9 @@ classdef Signal
maxA = max(sig(100:end-100));
minA = min(sig(100:end-100));
% maxA = 0.0015;
% minA = 0;
difference= maxA-minA;
@@ -603,6 +605,7 @@ classdef Signal
min_ = min(obj.signal(100:end-100));
max_ = abs(max(obj.signal(100:end-100)));
end
xlabel('Time in ps')
% add information
@@ -704,8 +707,12 @@ classdef Signal
yticks(linspace(0,histpoints,16));
y_tickstring = sprintfc('%.2f', y_tickstring);
yticklabels(y_tickstring);
xticks(linspace(0,histpoints_horizontal,8))
x_tickstring = sprintfc('%.2f', linspace(0, 2/fsym, 8) .* 1e12);
xticklabels(x_tickstring);
end

View File

@@ -135,6 +135,7 @@ classdef AWG < handle
%%%%%%%%% PRECOMP SINC ROLLOFF %%%%%%%%%
if 1
% X: design FIR filter for sinc precomp
% https://www.dsprelated.com/showarticle/1191.php
ntaps = 13;
npts = 32;
% least-squares FIR design

View File

@@ -9,6 +9,9 @@ classdef PAMsource
fsym
randkey
mrds_code
mrds_blocklength
applypulseform
pulseformer
@@ -30,6 +33,9 @@ classdef PAMsource
options.fsym = 112e9;
options.randkey = 0;
options.mrds_code = 0;
options.mrds_blocklength = 512;
options.applypulseform = 1;
options.pulseformer Pulseformer;
@@ -84,22 +90,28 @@ classdef PAMsource
symbols = PAMmapper(obj.M,0).map(bits);
symbols.fs = obj.fsym;
if obj.mrds_code
symbols = MRDS_coding("blocklength",obj.mrds_blocklength).encode(symbols);
end
if obj.applyclipping
sym_min = min(symbols.signal);
sym_max = max(symbols.signal);
end
%%%%% Pulseforming %%%%%%
%%%%% Pulse-forming %%%%%%
if obj.applypulseform
digi_sig = obj.pulseformer.process(symbols);
else
digi_sig = symbols;
end
%%%%% Resample to f DAC %%%%%%
%%%%% Re-sample to f DAC %%%%%%
digi_sig = digi_sig.resample("fs_in",digi_sig.fs,"fs_out",obj.fs_out,"n",10,"beta",5);
% digi_sig.spectrum("fignum",111,"displayname","after pulseforming");
%%%%% Hard clip digital signal to PAM range before DAC %%%%%%
if obj.applyclipping
try

View File

@@ -136,7 +136,7 @@ classdef FFE_DCremoval < handle
%Update the dc estimation every n-th symbol. This is a
%trivial implementation of parallel EQ´s where the
%errors are not apparent in every step. See Silas OFC
%2023 "MPI mitigation adaptive DC removal"
%2023 "MPI mitigation adaptive DC removal
if mod(symbol,length(e_dc_buffer)) == 0
e_dc_buffer(1) = e_dc_est - obj.mu_dc * err(symbol);
e_dc_buffer = circshift(e_dc_buffer,1);

View File

@@ -129,7 +129,7 @@ classdef FFE_FFDCAVG < handle
for epoch = 1 : epochs
symbol = 0;
err_buffer = zeros(numel(obj.constellation),90);
err_buffer = zeros(numel(obj.constellation),112);
dc_err = zeros(numel(obj.constellation),1);
dc_sto = NaN(numel(obj.constellation),N);

View File

@@ -0,0 +1,269 @@
classdef MRDS_coding
%MRDS implementation according to:
% Optical Multi-Path Interference Mitigation for PAM4-IMDD Systems Using Balanced Coding
% Journal of Lightwave Technology; 2024
properties(Access=public)
blocklength
delta
end
methods (Access=public)
function obj = MRDS_coding(options)
%NAME Construct an instance of this class
% Detailed explanation goes here
arguments
options.blocklength = 8;
end
%
fn = fieldnames(options);
for n = 1:numel(fn)
try
obj.(fn{n}) = options.(fn{n});
end
end
end
function process(~)
error("MRDS_coding has no process function. Use .encode(signal) and .dc_remove(signal) and .decode(signal)");
end
function signalclass_out = encode(obj,signalclass_in)
data_in = signalclass_in.signal';
if mean(unique(data_in)) < 0.01 % --> check for bipolar
data_in = int32(data_in.*sqrt(5));
data_in = double(data_in);
else % unipolar
data_in = int32(data_in.*sqrt(5)*2-3); % make bipolar [-3, -1, 1, 3]
data_in = double(data_in);
end
data_out = obj.mrds_encoding(data_in, obj.blocklength);
data_out = data_out./sqrt(5); % normalized to Power=1
signalclass_in.signal = data_out';
% append to logbook
lbdesc = ['MRDS Coded'];
signalclass_in = signalclass_in.logbookentry(lbdesc);
% write to output
signalclass_out = signalclass_in;
end
function signalclass_out = decode(obj,signalclass_in)
data_in = signalclass_in.signal';
if mean(unique(data_in)) < 0.01 % --> check for bipolar
data_in = int32(data_in.*sqrt(5));
data_in = double(data_in);
else % unipolar
data_in = int32(data_in.*sqrt(5)*2-3); % make bipolar [-3, -1, 1, 3]
data_in = double(data_in);
end
data_oh = obj.oh_decider(data_in, obj.blocklength); % decider for overhead
data_out = obj.mrds_decoding(data_oh, obj.blocklength);
data_out = data_out./sqrt(5); % normalized to Power=1
signalclass_in.signal = data_out';
% append to logbook
lbdesc = ['MRDS Coded'];
signalclass_in = signalclass_in.logbookentry(lbdesc);
% write to output
signalclass_out = signalclass_in;
end
function signalclass_out = dc_remove(obj,signalclass_in,options)
arguments
obj
signalclass_in
options.oversampling_factor = 1;
end
signalclass_in.signal = obj.dcr(signalclass_in.signal, obj.blocklength, options.oversampling_factor);
% append to logbook
lbdesc = ['MRDS DC Removed'];
signalclass_in = signalclass_in.logbookentry(lbdesc);
% write to output
signalclass_out = signalclass_in;
end
end
methods (Access=private)
% Cant be seen from outside! So put all your functions here that can/
% shall not be called from outside
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Function 1 - encoding
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function [data_out] = mrds_encoding(~,data_in, blocklength)
% data_in: bipolar PAM4 sequence with levels [-3, -1, 1, 3]
% with length power of two
% blocklength: power of two <= length of data_in
oh_length = log2(blocklength);
data_out = zeros(1,length(data_in)+length(data_in)/blocklength*oh_length);
l = 0;
for j = 1:blocklength:length(data_in)
data = data_in(j:j+blocklength-1);
z_N = zeros(1,blocklength); % RDS
z_rds = 0;
for i = 1:blocklength
z_rds = z_rds + data(i);
z_N(i) = z_rds;
end
z = z_rds/2; % find inversion point k
k = find(z_N == z);
[~, index] = min(abs(blocklength/2 - k));
k = k(index);
if isempty(k) == 1
k = blocklength;
end
if k == blocklength
overhead = ones(1,oh_length)*3;
else
overhead = (decimalToBinaryVector(k-1,log2(blocklength))-0.5)*6; % calculate OH
data(k+1:end) = data(k+1:end)*(-1); % invert
end
data_oh = [data overhead];
data_out(l*(blocklength+oh_length)+1:(l+1)*(blocklength+oh_length)) = data_oh;
l = l+1;
end
end
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Function 2 - decoding
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function [data_out] = mrds_decoding(~,data_in, blocklength)
oh_length = log2(blocklength);
data_out = zeros(1,length(data_in)-length(data_in)/(blocklength+oh_length)*oh_length);
l = 1;
for j = 1:(blocklength+oh_length):length(data_in)
data = data_in(j:j+blocklength+oh_length-1);
overhead = data(blocklength+1:end)/6+0.5;
k = binaryVectorToDecimal(overhead)+1;
if k == blocklength
data = data(1:blocklength);
else
data = data(1:blocklength);
data(k+1:end) = data(k+1:end)*(-1); % invert
end
data_out(l:l+blocklength-1) = data;
l = l+blocklength;
end
end
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Function 3 - decider for overhead values
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function [data_out] = oh_decider(~,data_in, blocklength)
oh_length = log2(blocklength);
threshold = 0;
data_out = data_in;
for j = 1:length(data_in)/(blocklength+oh_length)
for k = 1:oh_length
if data_in(j*blocklength+(j-1)*oh_length+k) >= threshold
data_out(j*blocklength+(j-1)*oh_length+k) = 3;
else
data_out(j*blocklength+(j-1)*oh_length+k) = -3;
end
end
end
end
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Function 4 - matched DC removal (DCR)
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function [data_out] = dcr(~,data_in, blocklength, oversampling_factor)
oh_length = log2(blocklength);
winlength = blocklength+oh_length;
if oversampling_factor > 1
winlength = winlength*oversampling_factor;
end
for j = 1:winlength:length(data_in)
try
data = data_in(j:j+winlength-1);
rmean = mean(data);
data_out(j:j+winlength-1) = data - rmean;
catch
if j+winlength > length(data_in)
data = data_in(j:length(data_in));
else
error('indice problem.')
end
rmean = mean(data);
data_out(j:length(data_in)) = data - rmean;
end
end
data_out = data_out';
end
end
end

View File

@@ -3,6 +3,9 @@ classdef VNLE < handle
% 1) Training mode (stable performance when you use NLMS)
% 2) Decision directed mode
% Eq = VNLE("epochs_tr",5,"epochs_dd",5,"len_tr",4096*2,"mu_dd",[0.0004 0.0005 0.0006],"mu_tr",0,"order",[25,2,2],"sps",2,"decide",1);
% Somehow it is not possible to use only 1 nonlinear order
properties
sps % usually 2
order