Add partial response symbol mapping and IM/DD system example
- Implemented a new MATLAB script for partial response symbol mapping using Duobinary precoding. - Added functions for printing constellation bit mapping and partial response state tables. - Created a minimal example for an IM/DD system, including signal generation, modulation, and equalization processes. - Integrated various components such as pulse shaping, optical modulation, and receiver processing. - Included detailed configurations for parameters like bias, link length, and filter settings.
This commit is contained in:
@@ -6,12 +6,12 @@ classdef Partialresponse
|
|||||||
end
|
end
|
||||||
|
|
||||||
methods
|
methods
|
||||||
function obj = Partialresponse(options)
|
function obj = Partialresponse(varargin)
|
||||||
arguments
|
parser = inputParser;
|
||||||
options.order (1,1) double = 1
|
parser.addParameter("order", 1);
|
||||||
end
|
parser.parse(varargin{:});
|
||||||
|
|
||||||
obj.order = options.order;
|
obj.order = parser.Results.order;
|
||||||
end
|
end
|
||||||
|
|
||||||
function signal = precode(obj, signal, options)
|
function signal = precode(obj, signal, options)
|
||||||
|
|||||||
@@ -1,23 +1,21 @@
|
|||||||
for M = [2 4 8]
|
for M = [2 4 8]
|
||||||
bits = Signalgenerator("form", signalform.prms,"M", M,"order", 15).process();
|
bits = Signalgenerator("form", signalform.prms,"M", M,"order", 16).process();
|
||||||
|
|
||||||
mapper = PAMmapper(M,0);
|
mapper = PAMmapper(M,0);
|
||||||
symbols = mapper.map(bits);
|
symbols = mapper.map(bits);
|
||||||
|
|
||||||
symbols_pre = Duobinary().precode(symbols);
|
db = Duobinary();
|
||||||
|
pr1 = Partialresponse();
|
||||||
symbols_db = Duobinary().encode(symbols_pre);
|
|
||||||
|
|
||||||
symbols_rx = Duobinary().decode(symbols_db);
|
|
||||||
|
|
||||||
|
symbols_pre = db.precode(symbols);
|
||||||
|
symbols_db = db.encode(symbols_pre);
|
||||||
|
symbols_rx = db.decode(symbols_db);
|
||||||
bits_rx = PAMmapper(M,0).demap(symbols_rx);
|
bits_rx = PAMmapper(M,0).demap(symbols_rx);
|
||||||
[~,~,ber,~] = calc_ber(bits.signal,bits_rx.signal,"skip_front",0,"skip_end",0,"returnErrorLocation",1);
|
[~,~,ber,~] = calc_ber(bits.signal,bits_rx.signal,"skip_front",0,"skip_end",0,"returnErrorLocation",1);
|
||||||
disp(['Class BER: ',sprintf('%.1E',ber),' - PAM-',num2str(M)]);
|
disp(['Class BER: ',sprintf('%.1E',ber),' - PAM-',num2str(M)]);
|
||||||
|
|
||||||
symbols_pre_pr = Partialresponse("order",1).precode(symbols,"M",M);
|
symbols_pre_pr = pr1.precode(symbols,"M",M);
|
||||||
symbols_db_pr = Partialresponse("order",1).encode(symbols_pre_pr,"M",M);
|
symbols_db_pr = pr1.encode(symbols_pre_pr,"M",M);
|
||||||
symbols_rx_pr = Partialresponse("order",1).decode(symbols_db_pr,"M",M);
|
symbols_rx_pr = pr1.decode(symbols_db_pr,"M",M);
|
||||||
|
|
||||||
bits_rx_pr = mapper.demap(symbols_rx_pr);
|
bits_rx_pr = mapper.demap(symbols_rx_pr);
|
||||||
[~,~,ber_pr,~] = calc_ber(bits.signal,bits_rx_pr.signal,"skip_front",0,"skip_end",0,"returnErrorLocation",1);
|
[~,~,ber_pr,~] = calc_ber(bits.signal,bits_rx_pr.signal,"skip_front",0,"skip_end",0,"returnErrorLocation",1);
|
||||||
disp(['Partialresponse BER: ',sprintf('%.1E',ber_pr),' - PAM-',num2str(M)]);
|
disp(['Partialresponse BER: ',sprintf('%.1E',ber_pr),' - PAM-',num2str(M)]);
|
||||||
@@ -37,4 +35,43 @@ for M = [2 4 8]
|
|||||||
disp(['Decode match: ',num2str(dec_match), ...
|
disp(['Decode match: ',num2str(dec_match), ...
|
||||||
' | max abs diff: ',sprintf('%.3g',dec_maxdiff)]);
|
' | max abs diff: ',sprintf('%.3g',dec_maxdiff)]);
|
||||||
disp('---');
|
disp('---');
|
||||||
|
|
||||||
|
f = figure("Name",sprintf("PAM-%d Partial-Response Histograms",M));
|
||||||
|
t = tiledlayout(f,1,4,"TileSpacing","compact","Padding","compact");
|
||||||
|
title(t,sprintf("PAM-%d Symbol Histograms",M));
|
||||||
|
|
||||||
|
nexttile;
|
||||||
|
plotDiscreteHistogram(symbols.signal,sprintf("PAM-%d",M));
|
||||||
|
|
||||||
|
nexttile;
|
||||||
|
plotDiscreteHistogram(symbols_db_pr.signal,"Duobinary 1st Order");
|
||||||
|
|
||||||
|
nexttile;
|
||||||
|
plotDiscreteHistogram(getEncodedSymbols(symbols,M,2),"Duobinary 2nd Order");
|
||||||
|
|
||||||
|
nexttile;
|
||||||
|
plotDiscreteHistogram(getEncodedSymbols(symbols,M,3),"Duobinary 3rd Order");
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
function y = getEncodedSymbols(symbols, M, order)
|
||||||
|
pr = Partialresponse("order",order);
|
||||||
|
y = pr.encode(pr.precode(symbols,"M",M),"M",M).signal;
|
||||||
|
end
|
||||||
|
|
||||||
|
function plotDiscreteHistogram(x, plot_title)
|
||||||
|
levels = unique(x(:)).';
|
||||||
|
counts = zeros(size(levels));
|
||||||
|
|
||||||
|
for idx = 1:numel(levels)
|
||||||
|
counts(idx) = sum(abs(x - levels(idx)) < 1e-12);
|
||||||
|
end
|
||||||
|
|
||||||
|
bar(levels, counts, 0.9, "FaceColor", [0.2 0.45 0.75], "EdgeColor", "none");
|
||||||
|
grid on;
|
||||||
|
box on;
|
||||||
|
xlabel("Level");
|
||||||
|
ylabel("Count");
|
||||||
|
title(plot_title);
|
||||||
|
xticks(levels);
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -1,122 +0,0 @@
|
|||||||
useprbs = 1;
|
|
||||||
M = 2;
|
|
||||||
randkey = 1;
|
|
||||||
datarate = 448e9;
|
|
||||||
fsym = round(datarate / log2(M)) ;
|
|
||||||
|
|
||||||
Tx_bits = Signalgenerator( ...
|
|
||||||
"form", signalform.prms, ...
|
|
||||||
"M", M, ...
|
|
||||||
"order", 15).process();
|
|
||||||
|
|
||||||
|
|
||||||
Symbols_tx = PAMmapper(M,0,"eth_style",0).map(Tx_bits);
|
|
||||||
Symbols_tx.fs = fsym;
|
|
||||||
|
|
||||||
precode = db_mode.db_precoded;
|
|
||||||
|
|
||||||
%%% precode
|
|
||||||
switch precode
|
|
||||||
case db_mode.db_precoded
|
|
||||||
Symbols_tx = Duobinary().precode(Symbols_tx);
|
|
||||||
case db_mode.db_encoded
|
|
||||||
Symbols_tx = Duobinary().precode(Symbols_tx);
|
|
||||||
Symbols_tx = Duobinary().encode(Symbols_tx);
|
|
||||||
case db_mode.no_db
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
for n = 10
|
|
||||||
|
|
||||||
% Start from the transmitted symbol sequence for this impairment case.
|
|
||||||
Symbols_rx = Symbols_tx;
|
|
||||||
|
|
||||||
% Insert n deterministic symbol errors near the beginning of the sequence.
|
|
||||||
% Each replacement is chosen from another symbol position with a different
|
|
||||||
% amplitude, so this produces actual symbol decisions errors.
|
|
||||||
pos = 1;
|
|
||||||
if n~=0
|
|
||||||
for pos = 1:n
|
|
||||||
po = randi(100);
|
|
||||||
a = Symbols_rx.signal(100+pos) == Symbols_tx.signal(100+po);
|
|
||||||
while a == 1
|
|
||||||
po = po+1;
|
|
||||||
po = randi(100);
|
|
||||||
a = Symbols_rx.signal(100+pos) == Symbols_tx.signal(100+po);
|
|
||||||
end
|
|
||||||
Symbols_rx.signal(100+pos) = Symbols_tx.signal(100+po);
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
% Keep track of the positions where the artificial symbol errors were
|
|
||||||
% inserted before duobinary encoding/decoding is applied.
|
|
||||||
error_positions = ~(Symbols_rx.signal == Symbols_tx.signal);
|
|
||||||
error_positions = find(error_positions==1);
|
|
||||||
|
|
||||||
% Receiver-side duobinary processing depends on what was already done at
|
|
||||||
% the transmitter side:
|
|
||||||
% - db_precoded: the sequence is precoded only, so emulate the channel PR
|
|
||||||
% encoder first and then apply memoryless duobinary decoding.
|
|
||||||
% - db_encoded: the sequence already contains duobinary levels, so only
|
|
||||||
% the memoryless duobinary decoder is applied.
|
|
||||||
switch precode
|
|
||||||
|
|
||||||
case db_mode.db_precoded
|
|
||||||
Symbols_rx = Duobinary().encode(Symbols_rx);
|
|
||||||
Symbols_rx = Duobinary().decode(Symbols_rx);
|
|
||||||
case db_mode.db_encoded
|
|
||||||
Symbols_rx = Duobinary().decode(Symbols_rx);
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
% Convert the recovered PAM symbols back to bits with the framework mapper.
|
|
||||||
Rx_bits = PAMmapper(M,0).demap(Symbols_rx);
|
|
||||||
|
|
||||||
%%%%% Check BER of Bit Sequence %%%%%
|
|
||||||
% Skip a few edge samples because the first/last symbols can include
|
|
||||||
% state/transient effects from the duobinary recursion.
|
|
||||||
[~,error_num(n+1),ber,error_pos] = calc_ber(Tx_bits.signal,Rx_bits.signal,"skip_front",10,"skip_end",10,"returnErrorLocation",1);
|
|
||||||
|
|
||||||
% disp(['BER: ',sprintf('%.1E',ber),sprintf(' - Num. Err: %.1d',error_num(n+1)-2),' - - PAM-',num2str(M)]);
|
|
||||||
fprintf('n: %d - Num. Err: %.1d \n',n,error_num(n+1));
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
% Plot bit-level and symbol-level comparisons for a quick visual sanity check.
|
|
||||||
figure(3);
|
|
||||||
clf
|
|
||||||
%sgtitle(['BER: ',num2str(ber),' // Error is at position: ',num2str(error_pos),''])
|
|
||||||
|
|
||||||
% Compare the first few transmitted and received bits.
|
|
||||||
subplot(2,2,1)
|
|
||||||
hold on
|
|
||||||
title('First Bits')
|
|
||||||
stairs(Tx_bits.signal(100:150,1),'LineStyle','-','LineWidth',2,'DisplayName','Tx Bits');
|
|
||||||
stairs(Rx_bits.signal(100:150,1),'LineWidth',2,'DisplayName','Rx Bits','LineStyle',':')
|
|
||||||
legend
|
|
||||||
|
|
||||||
% Compare the last few transmitted and received bits.
|
|
||||||
subplot(2,2,2)
|
|
||||||
title('Last Bits')
|
|
||||||
hold on
|
|
||||||
stairs(Tx_bits.signal(end-50:end,1),'LineStyle','-','LineWidth',2,'DisplayName','Tx Bits');
|
|
||||||
stairs(Rx_bits.signal(end-50:end,1),'LineWidth',2,'DisplayName','Rx Bits','LineStyle',':')
|
|
||||||
legend
|
|
||||||
|
|
||||||
% Compare the first few symbol decisions after the duobinary processing chain.
|
|
||||||
subplot(2,2,3)
|
|
||||||
hold on
|
|
||||||
title('First Symbols Compare')
|
|
||||||
stairs(Symbols_tx.signal(1:100,1),'LineWidth',2,'DisplayName','Tx Symbols','LineStyle','-')
|
|
||||||
stairs(Symbols_rx.signal(1:100,1),'LineStyle',':','LineWidth',2,'DisplayName','Rx Symbols');
|
|
||||||
legend
|
|
||||||
|
|
||||||
% Compare the last few symbol decisions after the duobinary processing chain.
|
|
||||||
subplot(2,2,4)
|
|
||||||
hold on
|
|
||||||
title('Last Symbols Compare')
|
|
||||||
stairs(Symbols_tx.signal(end-50:end,1),'LineWidth',2,'DisplayName','Tx Symbols','LineStyle','-')
|
|
||||||
stairs(Symbols_rx.signal(end-50:end,1),'LineStyle',':','LineWidth',2,'DisplayName','Rx Symbols');
|
|
||||||
legend
|
|
||||||
@@ -0,0 +1,147 @@
|
|||||||
|
|
||||||
|
M = 4;
|
||||||
|
useUnitRmsScaling = false;
|
||||||
|
bits = Signalgenerator("form", signalform.prms,"M", M,"order", 16).process();
|
||||||
|
mapper = PAMmapper(M,0);
|
||||||
|
symbols = mapper.map(bits);
|
||||||
|
|
||||||
|
|
||||||
|
[constellation, bitmap] = mapper.getConstellationBitMapping();
|
||||||
|
printConstellationBitMapping(M, constellation, bitmap);
|
||||||
|
printPartialResponseStateTable(M, bitmap, "Duobinary", 1, useUnitRmsScaling);
|
||||||
|
|
||||||
|
db = Duobinary();
|
||||||
|
pr1 = Partialresponse();
|
||||||
|
|
||||||
|
symbols_pre = db.precode(symbols);
|
||||||
|
symbols_db = db.encode(symbols_pre);
|
||||||
|
symbols_rx = db.decode(symbols_db);
|
||||||
|
bits_rx = PAMmapper(M,0).demap(symbols_rx);
|
||||||
|
[~,~,ber,~] = calc_ber(bits.signal,bits_rx.signal,"skip_front",0,"skip_end",0,"returnErrorLocation",1);
|
||||||
|
disp(['Class BER: ',sprintf('%.1E',ber),' - PAM-',num2str(M)]);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
function printConstellationBitMapping(M, constellation, bitmap)
|
||||||
|
fprintf("\n=== PAM-%d Bit Mapping ===\n", M);
|
||||||
|
|
||||||
|
bitLabels = string(cellstr(char(bitmap + '0')));
|
||||||
|
|
||||||
|
if size(constellation, 2) == 1
|
||||||
|
mappingTable = table(constellation(:), bitLabels, ...
|
||||||
|
'VariableNames', {'Symbol', 'Bits'});
|
||||||
|
else
|
||||||
|
mappingTable = table(constellation(:,1), constellation(:,2), bitLabels, ...
|
||||||
|
'VariableNames', {'Symbol_1', 'Symbol_2', 'Bits'});
|
||||||
|
end
|
||||||
|
|
||||||
|
disp(mappingTable);
|
||||||
|
fprintf("Number of constellation points: %d\n\n", size(constellation, 1));
|
||||||
|
end
|
||||||
|
|
||||||
|
function printPartialResponseStateTable(M, bitmap, label, order, useUnitRmsScaling)
|
||||||
|
if useUnitRmsScaling
|
||||||
|
scalingLabel = "unit-RMS scaling";
|
||||||
|
encodedScaling = getEncodedScaling(M, order);
|
||||||
|
else
|
||||||
|
scalingLabel = "raw encoder levels";
|
||||||
|
encodedScaling = 1;
|
||||||
|
end
|
||||||
|
|
||||||
|
fprintf("=== %s Effective State Table (order = %d, %s) ===\n", label, order, scalingLabel);
|
||||||
|
|
||||||
|
mapper = PAMmapper(M, 0);
|
||||||
|
h = arrayfun(@(k) nchoosek(order, k), 0:order);
|
||||||
|
center = ((M - 1) * sum(h)) / 2;
|
||||||
|
|
||||||
|
if useUnitRmsScaling
|
||||||
|
pamScaling = mapper.scaling;
|
||||||
|
else
|
||||||
|
pamScaling = 1;
|
||||||
|
end
|
||||||
|
|
||||||
|
numStates = M^order;
|
||||||
|
numInputs = M;
|
||||||
|
|
||||||
|
prevStateLabels = strings(numStates * numInputs, 1);
|
||||||
|
bitLabels = strings(numStates * numInputs, 1);
|
||||||
|
aAmp = zeros(numStates * numInputs, 1);
|
||||||
|
uIdx = zeros(numStates * numInputs, 1);
|
||||||
|
uAmp = zeros(numStates * numInputs, 1);
|
||||||
|
yAmp = zeros(numStates * numInputs, 1);
|
||||||
|
nextStateLabels = strings(numStates * numInputs, 1);
|
||||||
|
|
||||||
|
row = 1;
|
||||||
|
for stateIdx = 0:(numStates - 1)
|
||||||
|
state = indexToState(stateIdx, M, order);
|
||||||
|
|
||||||
|
for a = 0:(numInputs - 1)
|
||||||
|
u = mod(a - sum(h(2:end) .* state), M);
|
||||||
|
y = (sum(h .* [u, state]) - center) / encodedScaling;
|
||||||
|
|
||||||
|
prevStateLabels(row) = formatState(state);
|
||||||
|
bitLabels(row) = bitsFromIndex(bitmap, a + 1);
|
||||||
|
aAmp(row) = indexToPamAmplitude(a, pamScaling, M);
|
||||||
|
uIdx(row) = u;
|
||||||
|
uAmp(row) = indexToPamAmplitude(u, pamScaling, M);
|
||||||
|
yAmp(row) = y;
|
||||||
|
nextStateLabels(row) = formatState([u, state(1:end-1)]);
|
||||||
|
row = row + 1;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
stateTable = table(prevStateLabels, bitLabels, aAmp, uIdx, uAmp, yAmp, nextStateLabels, ...
|
||||||
|
'VariableNames', {'PrevState', 'Bits', 'InputSymbol', 'PrecodedIndex', 'PrecodedSymbol', 'EncodedLevel', 'NextState'});
|
||||||
|
|
||||||
|
disp(stateTable);
|
||||||
|
fprintf("States: %d, transitions: %d\n\n", numStates, height(stateTable));
|
||||||
|
end
|
||||||
|
|
||||||
|
function state = indexToState(stateIdx, M, order)
|
||||||
|
state = zeros(1, order);
|
||||||
|
tmp = stateIdx;
|
||||||
|
|
||||||
|
for k = 1:order
|
||||||
|
state(k) = mod(tmp, M);
|
||||||
|
tmp = floor(tmp / M);
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function label = formatState(state)
|
||||||
|
if isempty(state)
|
||||||
|
label = "[]";
|
||||||
|
else
|
||||||
|
label = "[" + join(string(state), " ") + "]";
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function bitLabel = bitsFromIndex(bitmap, idx)
|
||||||
|
bitLabel = string(char(bitmap(idx, :) + '0'));
|
||||||
|
end
|
||||||
|
|
||||||
|
function amplitude = indexToPamAmplitude(a, scaling, M)
|
||||||
|
amplitude = (2 * a - (M - 1)) / scaling;
|
||||||
|
end
|
||||||
|
|
||||||
|
function scaling = getEncodedScaling(M, order)
|
||||||
|
h = arrayfun(@(k) nchoosek(order, k), 0:order);
|
||||||
|
numCombinations = M^(order + 1);
|
||||||
|
y = zeros(numCombinations, 1);
|
||||||
|
|
||||||
|
for n = 0:(numCombinations - 1)
|
||||||
|
state = zeros(1, order + 1);
|
||||||
|
tmp = n;
|
||||||
|
|
||||||
|
for k = 1:numel(state)
|
||||||
|
state(k) = mod(tmp, M);
|
||||||
|
tmp = floor(tmp / M);
|
||||||
|
end
|
||||||
|
|
||||||
|
y(n + 1) = sum(h .* state);
|
||||||
|
end
|
||||||
|
|
||||||
|
center = ((M - 1) * sum(h)) / 2;
|
||||||
|
scaling = sqrt(mean((y - center).^2));
|
||||||
|
end
|
||||||
@@ -1,55 +0,0 @@
|
|||||||
|
|
||||||
M = 8;
|
|
||||||
apply_precode_at_tx = 1;
|
|
||||||
|
|
||||||
bits = Signalgenerator( ...
|
|
||||||
"form", signalform.prms, ...
|
|
||||||
"M", M, ...
|
|
||||||
"order", 15).process();
|
|
||||||
|
|
||||||
symbols = PAMmapper(M,0).map(bits);
|
|
||||||
|
|
||||||
if apply_precode_at_tx
|
|
||||||
symbols_tx = Duobinary().precode(symbols);
|
|
||||||
else
|
|
||||||
symbols_tx = symbols;
|
|
||||||
end
|
|
||||||
|
|
||||||
disp(['Tx Sequenz: -- RMS:',sprintf('%.1f',rms(symbols_tx.signal)),' - - Levels -',num2str(numel(unique(symbols_tx.signal)))]);
|
|
||||||
unique(symbols_tx.signal)
|
|
||||||
disp('- - - - - - - - - -');
|
|
||||||
|
|
||||||
show2Dconstellation(symbols_tx,symbols_tx,"displayname",'VNLE Out','fignum',2241);
|
|
||||||
|
|
||||||
if apply_precode_at_tx
|
|
||||||
% 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);
|
|
||||||
|
|
||||||
disp(['DB encoded -- RMS:',sprintf('%.1f',rms(symbols_db.signal)),' - - Levels -',num2str(numel(unique(symbols_db.signal)))]);
|
|
||||||
unique(symbols_db.signal)
|
|
||||||
disp('- - - - - - - - - -');
|
|
||||||
|
|
||||||
% Entschiedene codierte Symbole decodieren: d_dec(n) = d_DB(n) mod4
|
|
||||||
symbols_rx = Duobinary().decode(symbols_db);
|
|
||||||
else
|
|
||||||
symbols_db = Duobinary().encode(symbols_tx);
|
|
||||||
symbols_rx = Duobinary().decode(symbols_db);
|
|
||||||
end
|
|
||||||
|
|
||||||
% Vergleichen von b(n) und d_dec(n)
|
|
||||||
bits_rx = PAMmapper(M,0).demap(symbols_rx);
|
|
||||||
disp(['Wieder normal -- RMS:',sprintf('%.1f',rms(symbols_rx.signal)),' - - Levels -',num2str(numel(unique(symbols_rx.signal)))]);
|
|
||||||
unique(symbols_rx.signal)
|
|
||||||
disp('- - - - - - - - - -');
|
|
||||||
|
|
||||||
|
|
||||||
[~,~,ber,~] = calc_ber(bits.signal,bits_rx.signal,"skip_front",10,"skip_end",10,"returnErrorLocation",1);
|
|
||||||
|
|
||||||
disp(['BER: ',sprintf('%.1E',ber),' - - PAM-',num2str(M)]);
|
|
||||||
|
|
||||||
figure()
|
|
||||||
subplot(1,2,1)
|
|
||||||
histogram(symbols_tx.signal,100,'Normalization','count')
|
|
||||||
|
|
||||||
subplot(1,2,2)
|
|
||||||
histogram(symbols_db.signal,100,'Normalization','count')
|
|
||||||
182
projects/Precoding_analysis/precode_imdd_system.m
Normal file
182
projects/Precoding_analysis/precode_imdd_system.m
Normal file
@@ -0,0 +1,182 @@
|
|||||||
|
% minimal example IM/DD
|
||||||
|
|
||||||
|
M = 4;
|
||||||
|
fsym = 112e9;
|
||||||
|
|
||||||
|
apply_pulsef = 1;
|
||||||
|
fdac = 256e9;
|
||||||
|
fadc = 256e9;
|
||||||
|
random_key = 1;
|
||||||
|
|
||||||
|
rcalpha = 0.05;
|
||||||
|
kover = 16;
|
||||||
|
|
||||||
|
duob_mode = db_mode.no_db;
|
||||||
|
|
||||||
|
vbias_rel = 0.5;
|
||||||
|
u_pi = 3;
|
||||||
|
vbias = -vbias_rel*u_pi;
|
||||||
|
|
||||||
|
laser_wavelength = 1293;
|
||||||
|
laser_linewidth = 0;
|
||||||
|
tx_bw_nyquist = 0.8;
|
||||||
|
|
||||||
|
% Channel
|
||||||
|
link_length = 1;
|
||||||
|
|
||||||
|
% RX
|
||||||
|
rop = -9;
|
||||||
|
rx_bw_nyquist = 0.8;
|
||||||
|
|
||||||
|
vnle_order1 = 50;
|
||||||
|
vnle_order2 = 7;
|
||||||
|
vnle_order3 = 7;
|
||||||
|
|
||||||
|
vnle_order=[vnle_order1,vnle_order2,vnle_order3];
|
||||||
|
dfe_order = [0 0 0];
|
||||||
|
|
||||||
|
pf_ncoeffs = 1;
|
||||||
|
|
||||||
|
alpha = 0;
|
||||||
|
|
||||||
|
len_tr = 4096*2;
|
||||||
|
|
||||||
|
mu_ffe1 = 0.0001;
|
||||||
|
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;
|
||||||
|
|
||||||
|
|
||||||
|
Pform = Pulseformer("fsym",fsym,"fdac",4*fsym,"pulse","rrc","pulselength",16,"alpha",rcalpha);
|
||||||
|
|
||||||
|
[Digi_sig,Symbols,Tx_bits] = PAMsource(...
|
||||||
|
"fsym",fsym,"M",M,"order",18,"useprbs",0,...
|
||||||
|
"fs_out",fdac,...
|
||||||
|
"applyclipping",0,"clipfactor",1.5,...
|
||||||
|
"applypulseform",apply_pulsef,"pulseformer",Pform,...
|
||||||
|
"randkey",random_key,...
|
||||||
|
'duobinary_mode',duob_mode,...
|
||||||
|
"mrds_code",0,"mrds_blocklength",512).process();
|
||||||
|
|
||||||
|
%%%%% AWG
|
||||||
|
% 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.spectrum("displayname",'Digi Spectrum','fignum',1,'normalizeTo0dB',1);
|
||||||
|
xlim([0,130]);
|
||||||
|
ylim([-30,5]);
|
||||||
|
% El_sig = El_sig.setPower(0,"dBm");
|
||||||
|
|
||||||
|
%%%%% Electrical Driver Amplifier %%%%%%
|
||||||
|
% El_sig = Amplifier("amp_mode","ideal_no_noise","gain_mode","gain","amplification_db",3).process(El_sig);
|
||||||
|
El_sig = El_sig.normalize("mode","oneone");
|
||||||
|
scaling = 0.6*(u_pi/2-abs(vbias-u_pi/2));
|
||||||
|
El_sig = El_sig .* scaling;
|
||||||
|
|
||||||
|
%%%%% 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.spectrum("displayname",'Opt Spectrum','fignum',10,'normalizeTo0dB',1);
|
||||||
|
|
||||||
|
% Opt_sig.eye(fsym,M,"displayname",'eye adter modulator','fignum',2026);
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
%%%%%% ROP %%%%%%
|
||||||
|
Rx_sig = Amplifier("amp_mode","ideal_no_noise","gain_mode","output_power","amplification_db",rop).process(Opt_sig);
|
||||||
|
|
||||||
|
%%%%%% PD Square Law %%%%%%
|
||||||
|
Rx_sig = Photodiode("fsimu",fdac*kover,"dark_current",2e-08,"responsivity",1,"temperature",20,"nep",1.8e-11).process(Rx_sig);
|
||||||
|
|
||||||
|
%%%%%% Low-pass RX (PD, El. Connectors and Scope %%%%%%
|
||||||
|
rx_bwl = 80e9;
|
||||||
|
Rx_sig = Filter('filtdegree',4,"f_cutoff",rx_bwl,"fs",fdac*kover,"filterType",filtertypes.butterworth,"active",true).process(Rx_sig);
|
||||||
|
|
||||||
|
% %%%%%% Low-pass Scope %%%%%%
|
||||||
|
Lp_scpe = Filter('filtdegree',4,"f_cutoff",110e9,"fs",fadc,"filterType",filtertypes.butterworth,"active",true);
|
||||||
|
|
||||||
|
%%%%%% Scope %%%%%%
|
||||||
|
Scpe_sig = Scope("fsimu",fdac*kover,"fadc",fadc,...
|
||||||
|
"delay",0,"fixed_delay",0,"filtertype",filtertypes.butterworth,...
|
||||||
|
"samplingdelay",0,"rand_samplingdelay",0,"freq_offset",0,"samp_jitter",0,...
|
||||||
|
"adcresolution",8,"quantbuffer",0.1,'block_dc',1,'lpf_active',1,'H_lpf',Lp_scpe).process(Rx_sig);
|
||||||
|
%%
|
||||||
|
|
||||||
|
% 1) matched filter
|
||||||
|
% pulse is symmetric, hence we can use pulsef firectly as matched filter.
|
||||||
|
% It feels off (bit I think correct) that the fsym is now the output freq.!!
|
||||||
|
% -> output 2 sps to omit timing recovery!?
|
||||||
|
Pform = Pulseformer("fsym",fsym,"fdac",2*fsym,"pulse","rrc","pulselength",16,"alpha",rcalpha,"matched",1);
|
||||||
|
Scpe_sig = Pform.process(Scpe_sig);
|
||||||
|
Scpe_sig.spectrum("displayname",'Signal after matched filter','fignum',1,'normalizeTo0dB',1);
|
||||||
|
%
|
||||||
|
|
||||||
|
% %%
|
||||||
|
% %%%%%% Sample to 2x fsym %%%%%%
|
||||||
|
% Scpe_sig = Scpe_sig.resample("fs_out",2*fsym);
|
||||||
|
% Scpe_sig.signal = Scpe_sig.signal(1:2*length(Symbols));
|
||||||
|
|
||||||
|
%%
|
||||||
|
%%%%%% Sync Rx signal with reference %%%%%%
|
||||||
|
[Scpe_sig,~] = Scpe_sig.tsynch("reference",Symbols,"fs_ref",fsym,"debug_plots",1);
|
||||||
|
Scpe_sig.spectrum("displayname",'Opt Spectrum','fignum',11,'normalizeTo0dB',1);
|
||||||
|
|
||||||
|
% 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.signal = Scpe_sig.signal(1:2*length(Symbols));
|
||||||
|
|
||||||
|
%%
|
||||||
|
|
||||||
|
% -------------------- FFE --------------------
|
||||||
|
ffe_order = [50, 0, 0];
|
||||||
|
eq_ = EQ("Ne",ffe_order,"Nb",[2,0,0], ...
|
||||||
|
"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",0);
|
||||||
|
|
||||||
|
% eq_ = FFE("epochs_tr",4,"epochs_dd",5,"len_tr",4096,"mu_dd",0.01,"mu_tr",0.01,"order",50,"sps",2,"decide",0, "adaption",adaption_method.nlms,"dd_mode",1);
|
||||||
|
eq_ = FFE_DFE("epochs_tr",5,"epochs_dd",5,"len_tr",512,"ffe_mu_dd",1e-4,"dfe_mu_dd",5e-4,"ffe_mu_tr",0,"dfe_mu_tr",0,"ffe_order",99,"dfe_order",99,"sps",2,"decide",0);
|
||||||
|
|
||||||
|
|
||||||
|
output.ffe_results = ffe(eq_,M,Scpe_sig,Symbols,Tx_bits, ...
|
||||||
|
"precode_mode",duob_mode,'showAnalysis',1,"postFFE",[], ...
|
||||||
|
"eth_style_symbol_mapping",0);
|
||||||
|
|
||||||
|
output.ffe_results.metrics.print("description",'DFE');
|
||||||
|
|
||||||
|
%%
|
||||||
|
|
||||||
|
% -------------------- 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', 1, "postFFE", [], "eth_style_symbol_mapping", 0);
|
||||||
|
|
||||||
|
output.mlse_results.metrics.print("description",'MLSE');
|
||||||
|
|
||||||
|
%%
|
||||||
|
|
||||||
|
% -------------------- 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');
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Reference in New Issue
Block a user