Compare commits

1 Commits

Author SHA1 Message Date
Silas Oettinghaus
18ccaf8c12 duobinary cleanup (currently it is a mess) 2026-02-23 09:17:26 +01:00
9 changed files with 364 additions and 251 deletions

View File

@@ -462,10 +462,19 @@ classdef PAMmapper
end end
function [Signal_out] = quantize(obj,Signal_in) function [Signal_out] = quantize(obj,Signal_in,options)
arguments
obj
Signal_in
options.custom_const = []
end
constellation = obj.get_levels(); if isempty(options.custom_const)
constellation = constellation ./ obj.scaling; constellation = obj.get_levels();
constellation = constellation ./ obj.scaling;
else
constellation = options.custom_const;
end
issignalclass = 0; issignalclass = 0;
if isa(Signal_in,'Signal') if isa(Signal_in,'Signal')

View File

@@ -7,11 +7,11 @@ classdef Metricstruct
eqParam_id (1,1) double {mustBeNumeric} = NaN eqParam_id (1,1) double {mustBeNumeric} = NaN
date_of_processing (1,1) datetime = datetime('now') date_of_processing (1,1) datetime = datetime('now')
numBits (1,1) double {mustBeInteger, mustBeNonnegative} = 0 numBits (1,1) double = 0
BER (1,1) double {mustBeNumeric, mustBeNonnegative} = 0 BER (1,1) double = 0
numBitErr (1,1) double {mustBeInteger, mustBeNonnegative} = 0 numBitErr (1,1) double = 0
BER_precoded (1,1) double {mustBeNumeric, mustBeNonnegative} = 0 BER_precoded (1,1) double = 0
numBitErr_precoded (1,1) double {mustBeInteger, mustBeNonnegative} = 0 numBitErr_precoded (1,1) double = 0
SNR (1,1) double {mustBeNumeric} = NaN SNR (1,1) double {mustBeNumeric} = NaN
SNR_level (:,1) double {mustBeNumeric} = [] SNR_level (:,1) double {mustBeNumeric} = []

8
Datatypes/db_decoder.m Normal file
View File

@@ -0,0 +1,8 @@
classdef db_decoder < int32
enumeration
sequencedetection (0) % use MLSE for decoding
memoryless (1) % use modulo
end
end

View File

@@ -1,153 +1,171 @@
function [db_results] = duobinary_target(eq_, mlse_,M, rx_signal, tx_symbols, tx_bits, options) function [db_results] = duobinary_target(eq_, mlse_,M, rx_signal, tx_symbols, tx_bits, options)
arguments arguments
eq_ eq_
mlse_ mlse_
M M
rx_signal rx_signal
tx_symbols tx_symbols
tx_bits tx_bits
options.precode_mode db_mode options.precode_mode db_mode
options.showAnalysis = 0; options.showAnalysis = 0;
options.eth_style_symbol_mapping = 0; options.eth_style_symbol_mapping = 0;
options.postFFE = []; options.postFFE = [];
end options.decoding_mode db_decoder = db_decoder.sequencedetection;
end
%Duobinary Targeting
db_ref_sequence = Duobinary().encode(tx_symbols);
db_ref_constellation = unique(db_ref_sequence.signal);
[eq_signal, eq_noise] = eq_.process(rx_signal,db_ref_sequence);
if ~isempty(options.postFFE)
[eq_signal,eq_noise] = options.postFFE.process(eq_signal,db_ref_sequence);
end
%
switch options.decoding_mode
case db_decoder.sequencedetection %MLSE
mlse_.DIR = [1,1];
if isa(mlse_,'MLSE_viterbi')
pam_sig_sd = mlse_.process(eq_signal);
else
[pam_sig_sd,LLR,GMI_MLSE] = mlse_.process(eq_signal,tx_symbols);
end
pam_sig_hd = PAMmapper(M,0,"eth_style",options.eth_style_symbol_mapping).quantize(pam_sig_sd);
case db_decoder.memoryless %DB Target FFE
% Hard decision on FFE output
eq_signal_hd = PAMmapper(M, 0).quantize(eq_signal,'custom_const',db_ref_constellation.');
eq_signal_hd = Duobinary().decode(eq_signal_hd);
pam_sig_hd = eq_signal_hd;
end
% precoding to mitigate error propagation, most prominently used in
% combination with duobinary signaling to avoid catastrophic error
% behavior (see J.W.M. Bergmans, Digital Baseband Transmission and Recording -> partial response signaling)
switch options.precode_mode
case db_mode.no_db
% TX Data is not precoded:
% A) Emulate diff precoding
if options.decoding_mode == db_decoder.sequencedetection
pam_sig_hd_precoded = Duobinary().encode(pam_sig_hd,"M",M);
pam_sig_hd_precoded = Duobinary().decode(pam_sig_hd_precoded,"M",M);
else
pam_sig_hd_precoded = pam_sig_hd;
end
%Duobinary Targeting tx_symbols_precoded = Duobinary().encode(tx_symbols);
db_ref_sequence = Duobinary().encode(tx_symbols); tx_symbols_precoded = Duobinary().decode(tx_symbols_precoded);
db_ref_constellation = unique(db_ref_sequence.signal); tx_bits_precoded = PAMmapper(M,0,"eth_style",options.eth_style_symbol_mapping).demap(tx_symbols_precoded);
[eq_signal, eq_noise] = eq_.process(rx_signal,db_ref_sequence);
if ~isempty(options.postFFE) rx_bits_mlse = PAMmapper(M,0,"eth_style",options.eth_style_symbol_mapping).demap(pam_sig_hd_precoded);
[eq_signal,eq_noise] = options.postFFE.process(eq_signal,db_ref_sequence);
end [bits_db,errors_db_diff_precoded,ber_db_diff_precoded,~] = calc_ber(rx_bits_mlse.signal,tx_bits_precoded.signal,"skip_front",100,"skip_end",150,"returnErrorLocation",1);
%B) Just determine BER
if options.decoding_mode == db_decoder.sequencedetection
rx_bits_mlse = PAMmapper(M,0,"eth_style",options.eth_style_symbol_mapping).demap(pam_sig_hd);
tx_bits = PAMmapper(M,0,"eth_style",options.eth_style_symbol_mapping).demap(tx_symbols);
[bits_mlse,errors_mlse,ber_db,~] = calc_ber(rx_bits_mlse.signal,tx_bits.signal,"skip_front",100,"skip_end",150,"returnErrorLocation",1);
else
ber_db = NaN;
errors_db = NaN;
end
case db_mode.db_precoded
% Daten SIND TATSÄCHLICH precoded auf TX Seite:
% A) Decode at Rx if no DB targeting was applied (we are in VNLE or MLSE EQ structure here!
if options.decoding_mode == db_decoder.sequencedetection
pam_sig_hd_decoded = Duobinary().encode(pam_sig_hd,"M",M);
pam_sig_hd_decoded = Duobinary().decode(pam_sig_hd_decoded,"M",M);
else
pam_sig_hd_decoded = pam_sig_hd;
end
mlse_.DIR = [1,1]; rx_bits_mlse_decoded = PAMmapper(M,0,"eth_style",options.eth_style_symbol_mapping).demap(pam_sig_hd_decoded);
% [bits_db,errors_db_diff_precoded,ber_db_diff_precoded,a] = calc_ber(rx_bits_mlse_decoded.signal,tx_bits.signal,"skip_front",100,"skip_end",150,"returnErrorLocation",1);
burst_db_precoded = count_error_bursts(a, 40);
if isa(mlse_,'MLSE_viterbi') % B) Omit the Coding by comparing with demapped TX symbol sequence
mlse_sig_sd = mlse_.process(eq_signal); if options.decoding_mode == db_decoder.sequencedetection
else tx_bits = PAMmapper(M,0,"eth_style",options.eth_style_symbol_mapping).demap(tx_symbols);
[mlse_sig_sd,LLR,GMI_MLSE] = mlse_.process(eq_signal,tx_symbols); rx_bits_mlse = PAMmapper(M,0,"eth_style",options.eth_style_symbol_mapping).demap(pam_sig_hd);
end [bits_db,errors_db,ber_db,a] = calc_ber(rx_bits_mlse.signal,tx_bits.signal,"skip_front",100,"skip_end",150,"returnErrorLocation",1);
burst_db = count_error_bursts(a, 40);
mlse_sig_hd = PAMmapper(M,0,"eth_style",options.eth_style_symbol_mapping).quantize(mlse_sig_sd); else
ber_db = NaN;
% precoding to mitigate error propagation, most prominently used in errors_db = NaN;
% combination with duobinary signaling to avoid catastrophic error end
% behavior (see J.W.M. Bergmans, Digital Baseband Transmission and Recording -> partial response signaling) end
switch options.precode_mode
case db_mode.no_db switch options.decoding_mode
% TX Data is not precoded: case db_decoder.sequencedetection %MLSE
if isa(mlse_,'MLSE_viterbi')
% A) Emulate diff precoding gmi_mlse = NaN;
mlse_sig_hd_precoded = Duobinary().encode(mlse_sig_hd,"M",M); air_mlse = NaN;
mlse_sig_hd_precoded = Duobinary().decode(mlse_sig_hd_precoded,"M",M); else
gmi_mlse = GMI_MLSE;
tx_symbols_precoded = Duobinary().encode(tx_symbols); air_mlse = tx_symbols.fs .* floor(log2(double(M))*10)/10 .* gmi_mlse ./ log2(double(M));
tx_symbols_precoded = Duobinary().decode(tx_symbols_precoded); end
case db_decoder.memoryless %DB Target FFE
tx_bits_precoded = PAMmapper(M,0,"eth_style",options.eth_style_symbol_mapping).demap(tx_symbols_precoded); % [gmi] = calc_air(eq_signal_sd, tx_symbols, "skip_front", 10000, "skip_end", 10000);
rx_bits_mlse = PAMmapper(M,0,"eth_style",options.eth_style_symbol_mapping).demap(mlse_sig_hd_precoded); [gmi] = calc_ngmi(eq_signal,tx_symbols);
gmi_mlse = NaN;
[~,errors_db_diff_precoded,ber_db_diff_precoded,~] = calc_ber(rx_bits_mlse.signal,tx_bits_precoded.signal,"skip_front",100,"skip_end",150,"returnErrorLocation",1); air_mlse = NaN;
end
%B) Just determine BER
rx_bits_mlse = PAMmapper(M,0,"eth_style",options.eth_style_symbol_mapping).demap(mlse_sig_hd); db_results = struct();
[bits_mlse,errors_mlse,ber_db,~] = calc_ber(rx_bits_mlse.signal,tx_bits.signal,"skip_front",100,"skip_end",150,"returnErrorLocation",1); db_results.metrics = Metricstruct;
db_results.metrics.result_id = NaN;
case db_mode.db_precoded db_results.metrics.run_id = NaN;
db_results.metrics.eqParam_id = NaN;
% Daten SIND TATSÄCHLICH precoded auf TX Seite: db_results.metrics.date_of_processing = datetime('now');
db_results.metrics.BER = ber_db;
% A) Decode at Rx if no DB targeting was applied (we are in VNLE or MLSE EQ structure here! db_results.metrics.numBits = bits_db;
mlse_sig_hd_decoded = Duobinary().encode(mlse_sig_hd,"M",M); db_results.metrics.numBitErr = errors_db;
mlse_sig_hd_decoded = Duobinary().decode(mlse_sig_hd_decoded,"M",M); db_results.metrics.BER_precoded = ber_db_diff_precoded;
rx_bits_mlse_decoded = PAMmapper(M,0,"eth_style",options.eth_style_symbol_mapping).demap(mlse_sig_hd_decoded); db_results.metrics.numBitErr_precoded = errors_db_diff_precoded;
[~,errors_db_diff_precoded,ber_db_diff_precoded,a] = calc_ber(rx_bits_mlse_decoded.signal,tx_bits.signal,"skip_front",100,"skip_end",150,"returnErrorLocation",1); db_results.metrics.GMI = gmi_mlse;
burst_db_precoded = count_error_bursts(a, 40); db_results.metrics.AIR = air_mlse;
% B) Omit the Coding by comparing with demapped TX symbol sequence db_results.metrics.MLSE_dir = mlse_.DIR;
db_results.metrics.Alpha = NaN;
tx_bits = PAMmapper(M,0,"eth_style",options.eth_style_symbol_mapping).demap(tx_symbols);
rx_bits_mlse = PAMmapper(M,0,"eth_style",options.eth_style_symbol_mapping).demap(mlse_sig_hd); % Create DB results structure
[bits_db,errors_db,ber_db,a] = calc_ber(rx_bits_mlse.signal,tx_bits.signal,"skip_front",100,"skip_end",150,"returnErrorLocation",1); db_results.config = Equalizerstruct();
burst_db = count_error_bursts(a, 40); eq_.e = [];
eq_.e2 = [];
cols = linspecer(8); eq_.e3 = [];
figure();hold on; db_results.config.eq = jsonencode(eq_);
stem(1:40,burst_db,'LineWidth',1,'Color',cols(4,:),'Marker','_','DisplayName','w/o diff. precoder'); % mlse_.DIR = [];
stem(1:40,burst_db_precoded,'LineWidth',1,'Color',cols(3,:),'Marker','.','LineStyle','-','DisplayName','w diff. precoder'); db_results.config.mlse = jsonencode(mlse_);
xlabel('Bit Error Burst Length') db_results.config.equalizer_structure = int32(equalizer_structure.vnle_db_mlse);
ylabel('Occurence') db_results.config.comment = 'function: Duobinary tgt. (VNLE -> MLSE)';
set(gca, 'yscale', 'log');
end if options.showAnalysis
% M = numel(unique(tx_symbols.signal)); eq_signal.eye(eq_signal.fs,M,"fignum",249);
rx_bits = PAMmapper(M,0,"eth_style",options.eth_style_symbol_mapping).demap(mlse_sig_hd);
[bits_db,errors_db,ber_db,errorIndice_db] = calc_ber(rx_bits.signal,tx_bits.signal,"skip_front",100,"skip_end",150,"returnErrorLocation",1); eq_noise = eq_noise - mean(eq_noise.signal);
rx_signal.spectrum("normalizeTo0dB",1,"fignum",250,"displayname","Rx Spectrum");
Duobinary().encode(tx_symbols).spectrum("normalizeTo0dB",1,"fignum",10,"displayname","DB encoded reference");
alpha = arburg(eq_noise.signal,1);%pf_.coefficients(2); showEQNoisePSD(eq_noise,"fignum",250,"displayname",'Duobinary Target Noise after Equalization');
alpha = alpha(2);
if isa(mlse_,'MLSE_viterbi') fprintf('DB tgt BER: %.2e \n',ber_db);
gmi_mlse = NaN;
air_mlse = NaN; figure(341); clf;
else showLevelHistogram(eq_signal, db_ref_sequence, "fignum", 341);
gmi_mlse = GMI_MLSE;
air_mlse = tx_symbols.fs .* floor(log2(double(M))*10)/10 .* gmi_mlse ./ log2(double(M)); end
end
db_results = struct();
db_results.metrics = Metricstruct;
db_results.metrics.result_id = NaN;
db_results.metrics.run_id = NaN;
db_results.metrics.eqParam_id = NaN;
db_results.metrics.date_of_processing = datetime('now');
db_results.metrics.BER = ber_db;
db_results.metrics.numBits = bits_db;
db_results.metrics.numBitErr = errors_db;
db_results.metrics.BER_precoded = ber_db_diff_precoded;
db_results.metrics.numBitErr_precoded = errors_db_diff_precoded;
db_results.metrics.GMI = gmi_mlse;
db_results.metrics.AIR = air_mlse;
db_results.metrics.MLSE_dir = mlse_.DIR;
db_results.metrics.Alpha = alpha;
% Create DB results structure
db_results.config = Equalizerstruct();
eq_.e = [];
eq_.e2 = [];
eq_.e3 = [];
db_results.config.eq = jsonencode(eq_);
% mlse_.DIR = [];
db_results.config.mlse = jsonencode(mlse_);
db_results.config.equalizer_structure = int32(equalizer_structure.vnle_db_mlse);
db_results.config.comment = 'function: Duobinary tgt. (VNLE -> MLSE)';
if options.showAnalysis
eq_signal.eye(eq_signal.fs,M,"fignum",249);
eq_noise = eq_noise - mean(eq_noise.signal);
rx_signal.spectrum("normalizeTo0dB",1,"fignum",250,"displayname","Rx Spectrum");
Duobinary().encode(tx_symbols).spectrum("normalizeTo0dB",1,"fignum",10,"displayname","DB encoded reference");
showEQNoisePSD(eq_noise,"fignum",250,"displayname",'Duobinary Target Noise after Equalization');
fprintf('DB tgt BER: %.2e \n',ber_db);
figure(341); clf;
showLevelHistogram(eq_signal, db_ref_sequence, "fignum", 341);
end
end end

View File

@@ -4,11 +4,11 @@ if 1
uloops = struct; uloops = struct;
uloops.precomp = [1]; uloops.precomp = [1];
uloops.bitrate = [300].*1e9; %[300,330,360,390,420,450,480] [224,336,360,390,420,448] for MPI uloops.bitrate = [360].*1e9; %[300,330,360,390,420,450,480] [224,336,360,390,420,448] for MPI
% uloops.laser_wavelength = [1293,1297.5,1302,1306.5,1310,1313.4,1318,1322.7,1327.4]; % uloops.laser_wavelength = [1293,1297.5,1302,1306.5,1310,1313.4,1318,1322.7,1327.4];
uloops.laser_wavelength = [1293]; uloops.laser_wavelength = [1290];
uloops.M = [4]; uloops.M = [4];
uloops.link_length = [0:2:10]; % 1,2,3,5,6,8,10 uloops.link_length = [0]; % 1,2,3,5,6,8,10
uloops.alpha = [0]; uloops.alpha = [0];
wh = DataStorage(uloops); wh = DataStorage(uloops);
@@ -19,21 +19,23 @@ if 1
end end
%% %%
figure % figure
hold on % hold on
for alpha = uloops.alpha %
a=wh.getStoValue('ber',1, [300].*1e9 , 1293, 4, uloops.link_length,alpha); % a=wh.getStoValue('ber',1, [360].*1e9 , 1290, 4, uloops.link_length,alpha);
ffe = cellfun(@(x) x.ffe_results.metrics.BER, a); % ffe = cellfun(@(x) x.ffe_results.metrics.BER, a);
plot(uloops.link_length,ffe,'DisplayName',sprintf('Alpha: %d',alpha),'LineStyle','-','HandleVisibility','on'); % plot(uloops.link_length,ffe,'DisplayName',sprintf('FFE'),'LineStyle','-','HandleVisibility','on');
end % dbt = cellfun(@(x) x.dbt_results.metrics.BER, a);
% plot(uloops.link_length,dbt,'DisplayName',sprintf('DBt'),'LineStyle','-','HandleVisibility','on');
set(gca, 'YScale', 'log'); %
ylim([5e-5 0.4]); %
yline([3.8e-3, 2e-2],'HandleVisibility','off'); % set(gca, 'YScale', 'log');
legend % ylim([5e-5 0.4]);
beautifyBERplot() % yline([3.8e-3, 2e-2],'HandleVisibility','off');
ylabel('BER'); % legend
% beautifyBERplot()
% ylabel('BER');
%

View File

@@ -3,66 +3,59 @@ function [output] = imdd_model(varargin)
simulation_mode = 1; simulation_mode = 1;
%%% Change folder %%% Change folder
curFolder = pwd; % curFolder = pwd;
funcFolder=fileparts(mfilename('fullpath')); % funcFolder=fileparts(mfilename('fullpath'));
if ~isempty(funcFolder) % if ~isempty(funcFolder)
cd(funcFolder); % cd(funcFolder);
end % end
%%% Run parameters %%% Run parameters
% TX
M = 4;
fsym = 180e9;
apply_pulsef = 1; % --- TX Architecture ---
fdac = 256e9; M = 4; % PAM order
fadc = 256e9; fsym = 180e9; % Symbol rate
apply_pulsef = 1; % Pulse shaping flag
fdac = 256e9; % DAC sampling rate
fadc = 256e9; % ADC sampling rate
random_key = 1; random_key = 1;
rcalpha = 0.05; % Roll-off factor
kover = 16; % Oversampling factor
duob_mode = db_mode.db_precoded;
rcalpha = 0.05; % --- TX Optics (EML / Laser) ---
kover = 16;
vbias_rel = 0.5; vbias_rel = 0.5;
u_pi = 3; u_pi = 3;
vbias = -vbias_rel*u_pi; vbias = -vbias_rel * u_pi;
laser_wavelength = 1293; laser_wavelength = 1293;
laser_linewidth = 0; laser_linewidth = 0;
tx_bw_nyquist = 0.8; tx_bw_nyquist = 0.8;
% Channel % --- Channel ---
link_length = 1; link_length = 1;
alpha = 0;
% RX % --- RX & Equalization ---
rop = -8; rop = -2;
rx_bw_nyquist = 0.8; rx_bw_nyquist = 0.8;
len_tr = 4096 * 2;
vnle_order1 = 50; % VNLE / FFE / DFE Orders
vnle_order2 = 7; vnle_order1 = 50;
vnle_order3 = 7; vnle_order2 = 7;
vnle_order3 = 7;
vnle_order = [vnle_order1, vnle_order2, vnle_order3];
dfe_order = [0, 0, 0];
dfe_ = sum(dfe_order) > 0;
vnle_order=[vnle_order1,vnle_order2,vnle_order3]; pf_ncoeffs = 1;
dfe_order = [0 0 0];
pf_ncoeffs = 1; % Equalizer Step Sizes
mu_ffe1 = 0.0001;
alpha = 0; mu_ffe2 = 0.0008;
mu_ffe3 = 0.001;
len_tr = 4096*2; mu_ffe = [mu_ffe1, mu_ffe3, mu_ffe3];
mu_dfe = 0.0004;
mu_ffe1 = 0.0001; mu_dc = 0.005;
mu_ffe2 = 0.0008;
mu_ffe3 = 0.001;
mu_dc = 0.005;
% mu_dc = 0;
mu_ffe = [mu_ffe1 mu_ffe3 mu_ffe3];
mu_dfe = 0.0004;
dfe_ = sum(dfe_order)>0;
duob_mode = db_mode.no_db;
%%% change specific parameter if given in varargin %%% change specific parameter if given in varargin
% Parse optional input arguments % Parse optional input arguments
@@ -109,12 +102,12 @@ Pform = Pulseformer("fsym",fsym,"fdac",4*fsym,"pulse","rc","pulselength",1
'duobinary_mode',duob_mode,... 'duobinary_mode',duob_mode,...
"mrds_code",0,"mrds_blocklength",512).process(); "mrds_code",0,"mrds_blocklength",512).process();
Digi_sig.spectrum("displayname",'Digi Spectrum','fignum',10,'normalizeTo0dB',1); % Digi_sig.spectrum("displayname",'Digi Spectrum','fignum',10,'normalizeTo0dB',1);
%%%%% AWG %%%%% AWG
% El_sig = M8199A("kover",kover).process(Digi_sig); % El_sig = M8199A("kover",kover).process(Digi_sig);
El_sig = AWG("fdac",fdac,"f_cutoff",fsym,"lpf_active",0,"kover",kover,"bit_resolution",12,"upsampling_method","samplehold","precomp_sinc_rolloff",1).process(Digi_sig); El_sig = AWG("fdac",fdac,"f_cutoff",fsym,"lpf_active",0,"kover",kover,"bit_resolution",12,"upsampling_method","samplehold","precomp_sinc_rolloff",1).process(Digi_sig);
% El_sig.spectrum("displayname",'Digi Spectrum','fignum',100,'normalizeTo0dB',0); El_sig.spectrum("displayname",'Digi Spectrum','fignum',100,'normalizeTo0dB',1);
% El_sig = El_sig.setPower(0,"dBm"); % El_sig = El_sig.setPower(0,"dBm");
%%%%% Low-pass el. components %%%%%% %%%%% Low-pass el. components %%%%%%
@@ -132,7 +125,7 @@ El_sig = El_sig .* scaling;
%%%%% MODULATE E/O CONVERSION %%%%%% %%%%% MODULATE E/O CONVERSION %%%%%%
[Opt_sig] = EML("mode",eml_mode.im_cosinus,"power",3,"fsimu",El_sig.fs,"lambda",laser_wavelength,"bias",vbias,"u_pi",u_pi,"linewidth",laser_linewidth,"randomkey",random_key+1,"alpha",alpha).process(El_sig); [Opt_sig] = EML("mode",eml_mode.im_cosinus,"power",3,"fsimu",El_sig.fs,"lambda",laser_wavelength,"bias",vbias,"u_pi",u_pi,"linewidth",laser_linewidth,"randomkey",random_key+1,"alpha",alpha).process(El_sig);
Opt_sig.spectrum("displayname",'Opt Spectrum','fignum',10,'normalizeTo0dB',1); % Opt_sig.spectrum("displayname",'Opt Spectrum','fignum',10,'normalizeTo0dB',1);
Opt_sig = Fiber("fsimu",Opt_sig.fs,"fiber_length",link_length,"alpha",0.3,"D",0,"lambda0",1310,"gamma",0,"Dslope",0.07).process(Opt_sig); Opt_sig = Fiber("fsimu",Opt_sig.fs,"fiber_length",link_length,"alpha",0.3,"D",0,"lambda0",1310,"gamma",0,"Dslope",0.07).process(Opt_sig);
@@ -150,7 +143,6 @@ Rx_sig = Filter('filtdegree',4,"f_cutoff",rx_bwl,"fs",fdac*kover,"filterType",fi
% %%%%%% Low-pass Scope %%%%%% % %%%%%% Low-pass Scope %%%%%%
Lp_scpe = Filter('filtdegree',4,"f_cutoff",110e9,"fs",fadc,"filterType",filtertypes.butterworth,"active",true); Lp_scpe = Filter('filtdegree',4,"f_cutoff",110e9,"fs",fadc,"filterType",filtertypes.butterworth,"active",true);
% Rx_sig.spectrum("displayname",'Analog Rx Spectrum','fignum',100,'normalizeTo0dB',1);
%%%%%% Scope %%%%%% %%%%%% Scope %%%%%%
Scpe_sig = Scope("fsimu",fdac*kover,"fadc",fadc,... Scpe_sig = Scope("fsimu",fdac*kover,"fadc",fadc,...
@@ -165,15 +157,18 @@ Scpe_sig = Scpe_sig.resample("fs_out",2*fsym);
Scpe_sig.signal = Scpe_sig.signal(1:2*length(Symbols)); Scpe_sig.signal = Scpe_sig.signal(1:2*length(Symbols));
%%%%%% Sync Rx signal with reference %%%%%% %%%%%% Sync Rx signal with reference %%%%%%
[Scpe_sig,~] = Scpe_sig.tsynch("reference",Symbols,"fs_ref",fsym,"debug_plots",1); [Scpe_sig,~] = Scpe_sig.tsynch("reference",Symbols,"fs_ref",fsym,"debug_plots",0);
Scpe_sig = Filter('filtdegree',4,"f_cutoff",Symbols.fs.*0.5,"fs",Scpe_sig.fs,"filterType",filtertypes.gaussian,"active",true).process(Scpe_sig); Scpe_sig = Filter('filtdegree',4,"f_cutoff",Symbols.fs.*0.5,"fs",Scpe_sig.fs,"filterType",filtertypes.gaussian,"active",true).process(Scpe_sig);
Scpe_sig = Scpe_sig - mean(Scpe_sig.signal); Scpe_sig = Scpe_sig - mean(Scpe_sig.signal);
Scpe_sig.spectrum("displayname",'Filtered Digital Spectrum','fignum',100,'normalizeTo0dB',1);
%%% EQUALIZING %%% EQUALIZING
if 0
% -------------------- FFE -------------------- % -------------------- FFE --------------------
ffe_order = [50, 0, 0]; ffe_order = [50, 0, 0];
eq_ffe = EQ("Ne",ffe_order,"Nb",[0,0,0], ... eq_ffe = EQ("Ne",ffe_order,"Nb",[0,0,0], ...
@@ -186,7 +181,8 @@ output.ffe_results = ffe(eq_ffe,M,Scpe_sig,Symbols,Tx_bits, ...
"eth_style_symbol_mapping",0); "eth_style_symbol_mapping",0);
output.ffe_results.metrics.print output.ffe_results.metrics.print
end
if 0
% -------------------- DFE -------------------- % -------------------- DFE --------------------
eq_dfe = EQ("Ne",ffe_order,"Nb",[2,0,0], ... eq_dfe = EQ("Ne",ffe_order,"Nb",[2,0,0], ...
"training_length",len_tr,"training_loops",5,"dd_loops",5, ... "training_length",len_tr,"training_loops",5,"dd_loops",5, ...
@@ -198,33 +194,36 @@ output.dfe_results = ffe(eq_dfe,M,Scpe_sig,Symbols,Tx_bits, ...
"eth_style_symbol_mapping",0); "eth_style_symbol_mapping",0);
output.dfe_results.metrics.print("description",'DFE'); output.dfe_results.metrics.print("description",'DFE');
end
if 0
% -------------------- VNLE + MLSE --------------------
pf_ncoeffs = 1;
ffe_order3 = [50, 5, 5];
eq_v = EQ("Ne",ffe_order3,"Nb",dfe_order, ...
"training_length",len_tr,"training_loops",5,"dd_loops",5, ...
"K",2,"DCmu",mu_dc,"DDmu",[mu_ffe mu_dfe],"DFEmu",0.005, ...
"FFEmu",0,"plotfinal",0,"ideal_dfe",1);
pf_ = Postfilter("ncoeff",pf_ncoeffs,"useBurg",1);
mlse_ = MLSE("duobinary_output",0,'M',M,'trellis_states',PAMmapper(M,0).levels);
[output.vnle_results, output.mlse_results] = vnle_postfilter_mlse(eq_v, pf_, mlse_, M, Scpe_sig, Symbols, Tx_bits, ...
"precode_mode", duob_mode, 'showAnalysis', 0, "postFFE", [], "eth_style_symbol_mapping", 0);
output.mlse_results.metrics.print("description",'MLSE');
end
if 1
% -------------------- VNLE + MLSE -------------------- %% -------------------- DB target --------------------
pf_ncoeffs = 1; mlse_db_ = MLSE("DIR",[1,1],"duobinary_output",0,"M",M,'trellis_states',PAMmapper(M,0).levels);
ffe_order3 = [50, 5, 5]; ffe_order = [50, 5, 5];
eq_v = EQ("Ne",ffe_order3,"Nb",dfe_order, ... eq_ = EQ("Ne",ffe_order,"Nb",dfe_order,"training_length",len_tr,"training_loops",5,"dd_loops",5, ...
"training_length",len_tr,"training_loops",5,"dd_loops",5, ... "K",2,"DCmu",mu_dc,"DDmu",[mu_ffe mu_dfe],"DFEmu",0.005,"FFEmu",0,"plotfinal",0,"ideal_dfe",1,"DB_aim",0);
"K",2,"DCmu",mu_dc,"DDmu",[mu_ffe mu_dfe],"DFEmu",0.005, ... output.dbt_results = duobinary_target(eq_,mlse_db_, M, Scpe_sig, Symbols, Tx_bits, ...
"FFEmu",0,"plotfinal",0,"ideal_dfe",1); "precode_mode", duob_mode, 'showAnalysis', 1, "postFFE", [],"decoding_mode","memoryless");
pf_ = Postfilter("ncoeff",pf_ncoeffs,"useBurg",1);
output.dbt_results.metrics.print("description",'Duobinary');
mlse_ = MLSE("duobinary_output",0,'M',M,'trellis_states',PAMmapper(M,0).levels); end
[output.vnle_results, output.mlse_results] = vnle_postfilter_mlse(eq_v, pf_, mlse_, M, Scpe_sig, Symbols, Tx_bits, ...
"precode_mode", duob_mode, 'showAnalysis', 0, "postFFE", [], "eth_style_symbol_mapping", 0);
% -------------------- DB target --------------------
mlse_db_ = MLSE("DIR",[1,1],"duobinary_output",0,"M",M,'trellis_states',PAMmapper(M,0).levels);
ffe_order = [50, 5, 5];
eq_ = EQ("Ne",ffe_order,"Nb",dfe_order,"training_length",len_tr,"training_loops",5,"dd_loops",5, ...
"K",2,"DCmu",mu_dc,"DDmu",[mu_ffe mu_dfe],"DFEmu",0.005,"FFEmu",0,"plotfinal",0,"ideal_dfe",1);
output.dbt_results = duobinary_target(eq_,mlse_db_, M, Scpe_sig, Symbols, Tx_bits, ...
"precode_mode", duob_mode, 'showAnalysis', 0, "postFFE", []);
output.dbt_results.metrics.print("description",'Duobinary');
disp('- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ') disp('- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ')
fprintf('\n') fprintf('\n')

View File

@@ -4,7 +4,7 @@ freqresp = ChannelFreqResp("Nacq",1024,"Navg",64,"Ncp",70,"f_ref",256e9);
% %
Digi_sig = freqresp.buildOFDM(); Digi_sig = freqresp.buildOFDM();
Digi_sig.spectrum("fignum",1112,"displayname",['maxamp:',num2str(maxamp)]); Digi_sig.spectrum("fignum",1112);
Digi_sig = Filter('filtdegree',3,"f_cutoff",70e9,"fs",256e9,"filterType",filtertypes.butterworth,"active",true).process(Digi_sig); Digi_sig = Filter('filtdegree',3,"f_cutoff",70e9,"fs",256e9,"filterType",filtertypes.butterworth,"active",true).process(Digi_sig);

View File

@@ -1,7 +1,7 @@
M = 6; M = 4;
apply_precode = 1; apply_precode = 0;
bitpattern = []; bitpattern = [];
s = RandStream('twister','Seed',1); s = RandStream('twister','Seed',1);
@@ -29,12 +29,12 @@ else
end end
show2Dconstellation(symbols_tx,symbols_tx,"displayname",'VNLE Out','fignum',2241); show2Dconstellation(symbols_tx,symbols_tx,"displayname",'VNLE Out','fignum',2241);
if apply_precode if apply_precode
% Entschiedene Symbole codieren: d_DB(n) = d(n) + d(n-1) (im Fall von PAM4 7 level [0 1 2 3 4 5 6]) % Entschiedene Symbole codieren: d_DB(n) = d(n) + d(n-1) (im Fall von PAM4 7 level [0 1 2 3 4 5 6])
symbols_db = Duobinary().encode(symbols_tx); symbols_db = Duobinary().encode(symbols_tx);
% Entschiedene codierte Symbole decodieren: d_dec(n) = d_DB(n) mod4 % Entschiedene codierte Symbole decodieren: d_dec(n) = d_DB(n) mod4
symbols_rx = Duobinary().decode(symbols_db); symbols_rx = Duobinary().decode(symbols_db);
else else
@@ -51,6 +51,8 @@ disp(['BER: ',sprintf('%.1E',ber),' - - PAM-',num2str(M)]);
figure(200) figure(200)
clf clf
hold on hold on
start = 100;
burstwidth = 10;
idxs = start-10:start+burstwidth+10; idxs = start-10:start+burstwidth+10;
scatter(idxs,d.signal(idxs),'DisplayName',['Orig Signal'],'Marker','o'); scatter(idxs,d.signal(idxs),'DisplayName',['Orig Signal'],'Marker','o');
scatter(idxs,d_burst.signal(idxs),'DisplayName',['Error Signal'],'Marker','x'); scatter(idxs,d_burst.signal(idxs),'DisplayName',['Error Signal'],'Marker','x');

View File

@@ -0,0 +1,75 @@
% einstellungen
M = 4;
apply_precode_at_tx = 0;
emulate_precode = 1;
% daten erzeugen
bitpattern = [];
s = RandStream('twister','Seed',1);
for i = 1:log2(M)
N = 2^(17-1); %length of prbs
bitpattern(:,i) = randi(s,[0 1], N, 1);
end
if M == 6
bitpattern = reshape(bitpattern',[],1);
bitpattern = bitpattern(1:end-mod(length(bitpattern),5));
end
tx_bits = Informationsignal(bitpattern);
tx_symbols = PAMmapper(M,0).map(tx_bits);
if apply_precode_at_tx
tx_symbols = Duobinary().precode(tx_symbols);
if emulate_precode
% ansatz 1B) Omit precode (einfach precoded empfangen, nichts weiter machen und normal prozessieren - möglich weil konstellation sich nicht ändert)
rx_symbols = tx_symbols;
bits_rx = PAMmapper(M,0).demap(rx_symbols);
% beachten, dass man die tx_bits anpassen muss, da man ja mit precoded symbolen vergleicht
tx_bits = PAMmapper(M,0).demap(tx_symbols);
else
% ansatz 1A) Precode normal:
% Entschiedene Symbole codieren: d_DB(n) = d(n) + d(n-1) (im Fall von PAM4 7 level [0 1 2 3 4 5 6])
symbols_db = Duobinary().encode(tx_symbols);
% Entschiedene codierte Symbole decodieren: d_dec(n) = d_DB(n) mod4
rx_symbols = Duobinary().decode(symbols_db);
bits_rx = PAMmapper(M,0).demap(rx_symbols);
end
[~,~,ber,~] = calc_ber(tx_bits.signal,bits_rx.signal,"skip_front",0,"skip_end",0,"returnErrorLocation",1);
disp(['BER: ',sprintf('%.1E',ber)]);
assert(ber == 0)
else
if emulate_precode
% emulate precode:
% Entschiedene Symbole codieren: d_DB(n) = d(n) + d(n-1) (im Fall von PAM4 7 level [0 1 2 3 4 5 6])
symbols_db = Duobinary().encode(tx_symbols); % das wäre der FFE mit db target
% Entschiedene codierte Symbole decodieren: d_dec(n) = d_DB(n) mod4
rx_symbols = Duobinary().decode(symbols_db); % modulo
bits_rx = PAMmapper(M,0).demap(rx_symbols); % demappen
% ref symbole precoden, auch hier muss man wieder etwas fummeln wegen der emulation:
% encode + decode == remove precoding (mathematisch die gleiche operation)
tx_symbols_ref = Duobinary().encode(tx_symbols);
tx_symbols_ref = Duobinary().decode(tx_symbols_ref);
tx_bits = PAMmapper(M,0).demap(tx_symbols_ref);
else
% normal detection without any precode stuff
symbols_db = Duobinary().encode(tx_symbols);
rx_symbols = tx_symbols;
bits_rx = PAMmapper(M,0).demap(rx_symbols);
end
[~,~,ber,~] = calc_ber(tx_bits.signal,bits_rx.signal,"skip_front",1,"skip_end",1,"returnErrorLocation",1);
disp(['BER: ',sprintf('%.1E',ber)]);
assert(ber == 0)
end