Add new functions
This commit is contained in:
150
Functions/EQ_visuals/analyzeEQperformance.m
Normal file
150
Functions/EQ_visuals/analyzeEQperformance.m
Normal file
@@ -0,0 +1,150 @@
|
||||
function analyzeEQperformance(ref_bits,ref_symbols,rx_signal,eq_signal,eq_decisions,fsym,M,options)
|
||||
arguments
|
||||
ref_bits
|
||||
ref_symbols
|
||||
rx_signal
|
||||
eq_signal
|
||||
eq_decisions
|
||||
fsym
|
||||
M
|
||||
options.postfilterclass
|
||||
options.eqclass
|
||||
options.mlseclass
|
||||
options.db_precoded
|
||||
options.displayname
|
||||
end
|
||||
|
||||
% toolkit to visualize stuff related to DSP of IM/DD
|
||||
%%% Preps
|
||||
if isempty(eq_decisions)
|
||||
eq_decisions = PAMmapper(M,0).quantize(eq_signal);
|
||||
end
|
||||
|
||||
%%% Demap eqlzd signal to determine BER
|
||||
if options.db_precoded
|
||||
eq_hd = PAMmapper(M,0).quantize(eq_signal);
|
||||
eq_hd = Duobinary().encode(eq_hd);
|
||||
eq_hd = Duobinary().decode(eq_hd,"M",M);
|
||||
rx_bits = PAMmapper(M,0).demap(eq_hd);
|
||||
else
|
||||
rx_bits = PAMmapper(M,0).demap(eq_signal);
|
||||
end
|
||||
|
||||
[~,numerr,ber_sd,errpos] = calc_ber(rx_bits.signal,ref_bits.signal,"skip_front",100,"skip_end",150,"returnErrorLocation",1);
|
||||
% fprintf('SD BER: %.2e \n',ber_sd);
|
||||
|
||||
%%% Demap provided decisions to determine BER
|
||||
rx_bits = PAMmapper(M,0).demap(eq_decisions);
|
||||
[~,numerr,ber_mlse,errpos] = calc_ber(rx_bits.signal,ref_bits.signal,"skip_front",100,"skip_end",150,"returnErrorLocation",1);
|
||||
% fprintf('MLSE BER: %.2e \n',ber_mlse);
|
||||
|
||||
|
||||
|
||||
%%% Noise prior to DSP (is thius accurate with resampling?)
|
||||
rx_resampled = rx_signal.normalize("mode","rms").resample("fs_out",fsym);
|
||||
rx_noise = rx_resampled-ref_symbols;
|
||||
|
||||
%%% Noise after to soft-decision DSP
|
||||
eq_noise = eq_signal-ref_symbols;
|
||||
|
||||
|
||||
col = cbrewer2('paired',12);
|
||||
lines = numel(findall(figure(200), 'Type', 'Line'))+1;
|
||||
darkcoloridx = max(mod(2*lines,12),2);
|
||||
lightcoloridx = max(mod(2*lines-1,12),1);
|
||||
|
||||
%%% Separate Classes
|
||||
constellation = unique(ref_symbols.signal);
|
||||
received_sd = NaN(numel(constellation),length(ref_symbols));
|
||||
received_hd = NaN(numel(constellation),length(ref_symbols));
|
||||
lvlcol = cbrewer2('Set1',numel(constellation));
|
||||
for lvl = 1:numel(constellation)
|
||||
%Separate the equalized signal into the
|
||||
%respective levels based on the actually
|
||||
%transmitted level!
|
||||
received_sd(lvl,ref_symbols.signal==constellation(lvl)) = eq_signal.signal(ref_symbols.signal==constellation(lvl));
|
||||
received_hd(lvl,ref_symbols.signal==constellation(lvl)) = eq_decisions.signal(ref_symbols.signal==constellation(lvl));
|
||||
end
|
||||
|
||||
%%% bursts
|
||||
% Find differences between consecutive elements
|
||||
diff_indices = diff(errpos);
|
||||
|
||||
% Identify the start of new sequences (when the difference is not 1)
|
||||
sequence_starts = [1, find(diff_indices ~= 1) + 1]; % Include the first index
|
||||
sequence_ends = [sequence_starts(2:end) - 1, length(errpos)]; % Calculate end indices
|
||||
|
||||
% Initialize burst count and print bursts longer than 10
|
||||
burst_len = 1:10;
|
||||
burst_count = zeros(length(burst_len),1);
|
||||
for t = 1:numel(burst_len)
|
||||
for i = 1:length(sequence_starts)
|
||||
% Extract current sequence
|
||||
current_burst = errpos(sequence_starts(i):sequence_ends(i));
|
||||
% Check if the sequence length matches criterion
|
||||
if length(current_burst) == burst_len(t)
|
||||
burst_count(t) = burst_count(t) + 1;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
burst_symbols = burst_count .* burst_len';
|
||||
burst_rate = burst_symbols ;%./ length(rx_signal);
|
||||
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
%%% Rx Spectrum %200
|
||||
rx_signal.spectrum("displayname",sprintf('Rx %d GBd PAM%d',fsym.*1e-9,M),'fignum',200,'normalizeTo0dB',1,'color',col(darkcoloridx,:));
|
||||
xline([-fsym/2,fsym/2].*1e-9,'Color',col(mod(lines,12)+2,:),'HandleVisibility','off');
|
||||
ylim([-20,3]);
|
||||
%%% EQ Spectrum
|
||||
%
|
||||
|
||||
%%% EQ Time Series %210
|
||||
showEQTimeSignal(eq_signal,ref_symbols)
|
||||
|
||||
|
||||
%%% EQ Noise Spectrum + inverted Postfilter %220
|
||||
showEQNoisePSD(eq_noise,options.postfilterclass.burg_coeff,"fignum",220,"color",col(darkcoloridx,:));
|
||||
|
||||
%%% EQ SNR Spectrum %230
|
||||
fft_length = 2^13;
|
||||
[s_lin,w] = pwelch(eq_signal.signal,hanning(fft_length),fft_length/2,fft_length,eq_signal.fs,"centered","psd","mean");
|
||||
[n_lin,w] = pwelch(eq_noise.signal,hanning(fft_length),fft_length/2,fft_length,eq_noise.fs,"centered","psd","mean");
|
||||
w = w.*1e-9;
|
||||
snr_dbm = 10*log10(s_lin./n_lin);
|
||||
|
||||
figure(230)
|
||||
hold on
|
||||
plot(w,snr_dbm,'DisplayName','SNR after EQ','LineWidth',1,'Color',col(darkcoloridx,:));
|
||||
xlabel("Frequency in GHz");
|
||||
edgetick = 2^(nextpow2(eq_signal.fs*1e-9));
|
||||
xticks(-edgetick:16:edgetick);
|
||||
xlim([-128 128]);
|
||||
ylim([-20,35]);
|
||||
grid minor
|
||||
yticks(-200:10:100);
|
||||
grid on; grid minor;
|
||||
legend('Interpreter','none');
|
||||
title('Noise of soft decision signal (not MLSE)');
|
||||
|
||||
%%% FFE histogram %240
|
||||
showLevelHistogram(eq_signal,ref_symbols)
|
||||
|
||||
%%% Confusion Matrix
|
||||
showLevelConfusionMatrix(eq_decisions,ref_symbols,"fignum",250)
|
||||
|
||||
|
||||
%%% Burst Count
|
||||
figure(260)
|
||||
hold on
|
||||
plot(burst_len,burst_rate,'Marker','x','Color',col(darkcoloridx,:),"displayname",sprintf('Rx %d GBd PAM%d; %s',fsym.*1e-9,M,options.displayname));
|
||||
xlabel('length of error burst');
|
||||
ylabel('occurences')
|
||||
grid on
|
||||
set(gca, 'YScale', 'log');
|
||||
|
||||
|
||||
autoArrangeFigures
|
||||
|
||||
end
|
||||
Reference in New Issue
Block a user