diff --git a/Classes/00_signals/Frame 1.png b/Classes/00_signals/Frame 1.png deleted file mode 100644 index b1797d7..0000000 Binary files a/Classes/00_signals/Frame 1.png and /dev/null differ diff --git a/Classes/00_signals/Signal.m b/Classes/00_signals/Signal.m index 500eb76..1ae61d2 100644 --- a/Classes/00_signals/Signal.m +++ b/Classes/00_signals/Signal.m @@ -24,11 +24,11 @@ classdef Signal obj.signal = signal; obj.signal = obj.signal; obj.fs = options.fs; - + [~,obj.gitSHA] = system('git rev-parse HEAD'); [~,obj.gitStatus] = system('git status --porcelain'); % [~,obj.gitPatch] = system('git diff'); - + %%% Stuff for Logbook %%% SignalType = []; TimeStamp = []; @@ -133,6 +133,7 @@ classdef Signal end + %% function plot(obj, options) % signal to plot: obj.signal % fsamp : obj.fs (e.g. 92e9 => 92 GHz) @@ -144,6 +145,7 @@ classdef Signal options.displayname = []; options.timeframe = 0; options.clear = 0; + options.color = []; end figure(options.fignum); % If figure does not exist, create new figure @@ -169,8 +171,11 @@ classdef Signal end hold on; - plot(t, sig(1:length(t)), 'DisplayName', dn, 'LineWidth', 0.1, 'Marker', '.', 'LineStyle','none', 'MarkerSize', 0.1); - + if isempty(options.color) + plot(t, sig(1:length(t)), 'DisplayName', dn, 'LineWidth', 0.1, 'Marker', '.', 'LineStyle','none', 'MarkerSize', 0.1); + else + plot(t, sig(1:length(t)), 'DisplayName', dn, 'LineWidth', 0.1, 'Marker', '.', 'LineStyle','none', 'MarkerSize', 0.1,'Color',options.color); + end % 2 c) % - xlabel if not already here: time in readable format (1 ms and not 1e-3 s) % - ylabel amplitude @@ -254,7 +259,12 @@ classdef Signal CallingModifier = evalin('caller','obj'); end - CallingModifierStruct = obj.objToStructFilteredRecursive(CallingModifier); + if isa(CallingModifier,"Signal") + CallingModifierStruct = obj.objToStructFilteredRecursive(CallingModifier); + ModifierCopy = {CallingModifierStruct}; + end + + ModifierCopy = {CallingModifier}; SignalType = [string(class(obj))]; TimeStamp = [(datetime('now','TimeZone','local','Format','HH:mm:ss'))]; @@ -263,7 +273,7 @@ classdef Signal Nase = [0]; SignalCopy = obj.signal; ModifierName = class(CallingModifier); - ModifierCopy = {CallingModifierStruct}; + cell = {SignalType , TimeStamp , Length , SignalPower(1) , Nase, SignalCopy, ModifierName, ModifierCopy, Description}; @@ -313,17 +323,17 @@ classdef Signal if options.fs_in == options.fs_out desc = ['No need to resample signal from ', num2str(options.fs_in*1e-9), ' GHz to ', num2str(options.fs_out*1e-9), ' GHz' ]; - + obj = obj.logbookentry(desc,obj); else obj.signal = resample(obj.signal,options.fs_out,options.fs_in,options.n,options.beta); - + desc = ['resample signal from ', num2str(options.fs_in*1e-9), ' GHz to ', num2str(options.fs_out*1e-9), ' GHz' ]; - + obj = obj.logbookentry(desc,obj); - + obj.fs = options.fs_out; end @@ -340,59 +350,193 @@ classdef Signal options.color = []; options.normalizeToNyquist = 0; options.normalizeTo0dB = 0; + options.max_num_lines = []; % Leave empty or omit to disable line rotation + options.fft_length = []; end - % spectrum_plot(obj.signal,options.fsamp,options.figurename,options.displayname); - - N = 2^(nextpow2(length(obj.signal))-10); - - if options.normalizeToNyquist==0 - [p_lin,w] = pwelch(obj.signal,hanning(N),N/2,N,obj.fs,"centered","power","mean"); - w=w.*1e-9; - else - [p_lin,w] = pwelch(obj.signal,hanning(N),N/2,N,"centered","power","mean"); - p_lin = smooth(p_lin,0.05,'rloess'); + if isempty(options.fft_length) + options.fft_length = 2^(nextpow2(length(obj.signal))-7); end - + if options.normalizeToNyquist == 0 + [p_lin,w] = pwelch(obj.signal,hanning(options.fft_length),options.fft_length/2,options.fft_length,obj.fs,"centered","psd","mean"); + w = w.*1e-9; + else + [p_lin,w] = pwelch(obj.signal,hanning(options.fft_length),options.fft_length/2,options.fft_length,"centered","psd","mean"); + end + if options.normalizeTo0dB p_lin = p_lin./ max(p_lin); - p_dbm = 10*log10(p_lin); %dB to dBm in case of "power" + p_dbm = 10*log10(p_lin); % normalized to 0 dB ylab = "normalized to 0 dB"; else - p_dbm = 10*log10(p_lin)+30; %dB to dBm in case of "power" - ylab = "Power (dBm)"; + p_dbm = 10*log10(p_lin); + ylab = "Power (dB/Hz)"; end - figure(options.fignum); % If figure does not exist, create new figure + figure(options.fignum); ax = gca; hold on if isempty(options.color) - plot(w,p_dbm,'DisplayName',options.displayname,'LineWidth',1); + hLine = plot(w,p_dbm,'DisplayName',options.displayname,'LineWidth',1); else - plot(w,p_dbm,'DisplayName',options.displayname,'LineWidth',1,'Color',options.color); + hLine = plot(w,p_dbm,'DisplayName',options.displayname,'LineWidth',1,'Color',options.color); end - if options.normalizeToNyquist==0 + % If user wants to limit the number of lines, check and remove old lines + if ~isempty(options.max_num_lines) && options.max_num_lines > 0 + allLines = findall(ax, 'Type', 'Line'); + if length(allLines) > options.max_num_lines + % Sort lines by creation order. Usually, the oldest lines appear first in allLines. + % If needed, you can sort by UserData or other criteria. + numToRemove = length(allLines) - options.max_num_lines; + delete(allLines(1:numToRemove)); + end + end + + if options.normalizeToNyquist == 0 xlabel("Frequency in GHz"); - %xlim([-obj.fs/2 obj.fs/2].*1e-9) edgetick = 2^(nextpow2(obj.fs*1e-9)); - xticks([-edgetick:16:edgetick]); - xlim([100*round( min(w)/100,1)-10,100*round( max(w)/100,1)+10]) + xticks(-edgetick:16:edgetick); + xlim([100*round(min(w)/100,1)-10, 100*round(max(w)/100,1)+10]) + xlim([-128 128]);%256GSa/s else xlabel("Normalized Frequency"); xlim([-pi, pi]); end - - ylabel("Power/frequency (dB/Hz)"); + ylabel(ylab); - - ylim([min(floor( min(p_dbm))-3 , ax.YLim(1)), max(ceil( max(p_dbm) )+(3), ax.YLim(2))]); - yticks([-200:10:10]); - grid on - grid minor - legend('Interpreter','none'); + + try + ylim([max(min(floor(min(p_dbm))-3, ax.YLim(1)),-40), min(max(ceil(max(p_dbm))+3, ax.YLim(2)),10)]); + catch + ylim([min(floor(min(p_dbm))-3, ax.YLim(1)), max(ceil(max(p_dbm))+3, ax.YLim(2))]); + end + yticks(-200:10:10); + grid on; grid minor; + legend + % legend('Interpreter','none'); + + end + + + function move_it_spectrum(obj,options) + arguments + obj + options.fignum + options.displayname = ""; + options.color = []; + options.normalizeToNyquist = 0; + options.normalizeTo0dB = 0; + end + + data_in = obj.signal; + + if size(data_in,1) > size(data_in,2) + data_in = data_in'; + end + + for pol = 1:size(data_in,1) + + %compute FFT of input + Data_in = fft( data_in(pol,:) ); + + %psd = Data_in.*conj(Data_in); + psd = Data_in; + + %Use only magnitude of FFT (which was complex) + psd = abs(psd); + + %Shift the spectrum to yield + psd = fftshift(psd); + + %divide by N + psd = psd/length(data_in(pol,:)); + + psd_plot = 20*log10(psd); + + % psd_plot = psd_plot - max(psd_plot); + + + %smoothing + % psd_smoothed = smooth(psd,1000); + % + % psd_smoothed = 10*log10(psd_smoothed); + + % psd_smoothed = psd_smoothed - max(psd_smoothed); + + carrier_power_time_dbm = 20*log10( mean(abs(data_in)) .^2 )+30; % dB -> +30 -> dBm + carrier_power_freq_dbm = max(psd_plot); + + + % psd_plot = psd_plot - max(psd_plot); + + %% cspr + c = mean(data_in).^2; + s = mean(data_in.^2); + cspr = 10*log10(c / s); + + testParseval = 1; + + if testParseval == 1 + + E_FreqDomain =1/length(psd) * sum((psd.*length(psd)).^2); + + %test parseval + E_TimeDomain = sum( (data_in(pol,:).^2) ); + + if isequal(round(E_FreqDomain,1),round(E_TimeDomain,1)) + disp('Parseval is right!'); + else + % disp('Something is wrong here?!'); + end + end + + figure(options.fignum); % If figure does not exist, create new figure + + if 1 + %Frequency Axis + freq_vec = linspace(-obj.fs/2,obj.fs/2,length(psd)); + freq_vec = reshape(freq_vec,size(psd_plot)); + + + if nargin == 4 + p = plot(freq_vec*1e-9,psd_plot,'Linewidth',0.5,'DisplayName',options.displayname); + % plot(freq_vec*1e-9,psd_smoothed','Linewidth',1,'Color',[0 0 0],'DisplayName',[char(varargin{2}),' smoothed']); + + else + p = plot(freq_vec*1e-9,psd_plot,'Linewidth',0.5); + % plot(freq_vec*1e-9,psd_smoothed','Linewidth',1,'Color',[1 1 1],'LineStyle',':'); + + end + + %xlim([freq_vec(1)/1e9-2 freq_vec(end)/1e9+2]) + xlabel('frequency [GHz]') + else + %Wavelength Axis + freq_vec = physconst('LightSpeed')*linspace(-obj.fs/2,obj.fs/2,length(psd))./((physconst('LightSpeed')/1310e-9)^2)*1e9; + freq_vec = freq_vec+1310; + if nargin == 4 + plot(freq_vec',psd_plot,'Linewidth',0.5,'DisplayName',options.displayname) + else + plot(freq_vec,psd_plot','Linewidth',0.5); + end + + %xlim([freq_vec(1)/1e9-2 freq_vec(end)/1e9+2]) + xlabel('wavelength [nm]') + end + hold on + + + end + + % xlim([-150 150]) + % ylim([-100,0]); + ylabel('magnitude [dBm]') + legend + grid minor; + end @@ -500,6 +644,7 @@ classdef Signal if options.mode == delay_mode.samples obj.signal=delayseq(obj.signal,delay); + % obj.signal=circshift(obj.signal,delay); elseif options.mode == delay_mode.time @@ -534,50 +679,63 @@ classdef Signal %estimate start pos of signal maxpeaknum = floor(length(a)/length(b)); - [pks,pkpos] = findpeaks(abs(co./max(co)),'MinPeakDistance',length(b)/2,'MinPeakHeight',0.2,'NPeaks',maxpeaknum); + [pks,pkpos] = findpeaks(abs(co./max(co)),'MinPeakDistance',length(b)/2,'MinPeakHeight',0.2,'NPeaks',maxpeaknum,'SortStr','descend'); shifts = lags(pkpos); - - %Cut occurences of ref signal from signal (only positive shifts) + + shifts = shifts(shifts>=0); + S = {}; - for c = shifts(shifts>0) - sig = obj.delay(-c,'mode','samples'); - sig.signal = sig.signal(1:length(b)); - S{end+1,1} = sig; - end - - % isFlipped=0; - if all(sign(co(pkpos))) - isFlipped = 1; + + if numel(shifts) > 0 + + %Cut occurences of ref signal from signal (only positive shifts) + + for c = shifts(shifts>=0) + sig = obj.delay(-c,'mode','samples'); + sig.signal = sig.signal(1:length(b)); + S{end+1,1} = sig; + end + + % + + if all(sign(co(pkpos))) + isFlipped = 1; + end + + %return/keep the sinal with the highest correlation (only within positive shifts) + [~,idx]=max(pks(shifts>=0)); + obj.signal = S{idx}.signal; + %put signal with highest corr. to first index in S array + swap = S{1}; + S{1} = S{idx}; + S{idx} = swap; + + for c = 1:numel(shifts(shifts>0)) + S{c}.logbook = []; + end + + else + + %do nothing when shifts are negative or there are none... + end - %return/keep the sinal with the highest correlation (only within positive shifts) - [~,idx]=max(pks(shifts>0)); - obj.signal = S{idx}.signal; - %put signal with highest corr. to first index in S array - swap = S{1}; - S{1} = S{idx}; - S{idx} = swap; - - for c = 1:numel(shifts(shifts>0)) - S{c}.logbook = []; - end - %plot all synced signals and the ref signal debug = 0; - if debug + if debug figure;hold on; for i = 1:size(S,1) plot(S{i}.normalize('mode','oneone').signal(1000:1100),'LineWidth',0.1,'Color',[0.2157 0.4941 0.7216]); plot(b(1000:1100),'LineWidth',1); end end - + end - + %% function obj = filter(obj,a,b) lbdesc = ['Filtering signal with H = a: ',num2str(a),' / b: ',num2str(b)]; @@ -586,6 +744,7 @@ classdef Signal obj.signal = filter(a,b,obj.signal); end + %% function er = extinctionratio(obj,fsym,M) histpoints = 1024; %% verticale resolution histpoints = floor(histpoints/2)*2+1; %% to have the eye digram centered around one point make the vertical resolution uneven @@ -665,7 +824,7 @@ classdef Signal end - + %% function eye(obj,fsym,M,options) arguments @@ -796,85 +955,85 @@ classdef Signal try - hist_interest = plot_data(:,posxall); - hist_interest_smoth = smooth(hist_interest,20); - a = scatter(hist_interest_smoth+posxall,1:length(hist_interest_smoth),4,'.','MarkerEdgeColor','red'); + hist_interest = plot_data(:,posxall); + hist_interest_smoth = smooth(hist_interest,20); + a = scatter(hist_interest_smoth+posxall,1:length(hist_interest_smoth),4,'.','MarkerEdgeColor','red'); - [pk,loc] = findpeaks(hist_interest_smoth,"MinPeakDistance",10,"NPeaks",M,"MinPeakHeight",30,"MinPeakProminence",10); - - scatter(posxall,loc,'red','Marker','x','LineWidth',2); - - yline(loc,'Color','red','LineWidth',1,'LineStyle',':'); + [pk,loc] = findpeaks(hist_interest_smoth,"MinPeakDistance",10,"NPeaks",M,"MinPeakHeight",30,"MinPeakProminence",10); - for i = 1:numel(loc) - ppeak(i) = maxA - (difference/histpoints*loc(i)); - end + scatter(posxall,loc,'red','Marker','x','LineWidth',2); - oma = false; - if isa(obj,'Opticalsignal') - er=10*log10(ppeak(1)/ppeak(end)); - elseif isa(obj,'Electricalsignal') - if mean([ppeak(1),ppeak(end)]) < 1e-2 - oma = true; - er=max(ppeak)-min(ppeak); + yline(loc,'Color','red','LineWidth',1,'LineStyle',':'); + + for i = 1:numel(loc) + ppeak(i) = maxA - (difference/histpoints*loc(i)); + end + + oma = false; + if isa(obj,'Opticalsignal') + er=10*log10(ppeak(1)/ppeak(end)); + elseif isa(obj,'Electricalsignal') + if mean([ppeak(1),ppeak(end)]) < 1e-2 + oma = true; + er=max(ppeak)-min(ppeak); + else + er=10*log10(ppeak(1)/ppeak(end)); + end else er=10*log10(ppeak(1)/ppeak(end)); end - else - er=10*log10(ppeak(1)/ppeak(end)); - end - % Adjust position for the third box (slightly to the right) - boxPosition = [0.59 0.86 0.2 0.05]; % Adjusted position + % Adjust position for the third box (slightly to the right) + boxPosition = [0.59 0.86 0.2 0.05]; % Adjusted position - % Create third annotation box for Vmax - if ~oma - thirdboxstring = ['ER (db):',num2str(er),' dB']; - else - thirdboxstring = ['OMA outer:',num2str(er),' V']; - end + % Create third annotation box for Vmax + if ~oma + thirdboxstring = ['ER (db):',num2str(er),' dB']; + else + thirdboxstring = ['OMA outer:',num2str(er),' V']; + end - plot_infos = 0; - if plot_infos + plot_infos = 0; + if plot_infos - % Define properties - boxPosition = [0.15 0.86 0.2 0.05]; % Position for the first box [x y width height] - boxColor = [0.9 0.9 0.9]; % Light grey background color - boxEdgeColor = 'k'; % Black edge color - boxLineStyle = '--'; % Dashed line style - boxFontWeight = 'bold'; % Bold font + % Define properties + boxPosition = [0.15 0.86 0.2 0.05]; % Position for the first box [x y width height] + boxColor = [0.9 0.9 0.9]; % Light grey background color + boxEdgeColor = 'k'; % Black edge color + boxLineStyle = '--'; % Dashed line style + boxFontWeight = 'bold'; % Bold font - % Create first annotation box for Power - annotation('textbox', boxPosition, ... - 'String', ['Power: ',num2str(pwr_dbm),' dBm'], ... - 'BackgroundColor', boxColor, ... - 'EdgeColor', boxEdgeColor, ... - 'LineStyle', boxLineStyle, ... - 'FontWeight', boxFontWeight, ... - 'HorizontalAlignment', 'center'); + % Create first annotation box for Power + annotation('textbox', boxPosition, ... + 'String', ['Power: ',num2str(pwr_dbm),' dBm'], ... + 'BackgroundColor', boxColor, ... + 'EdgeColor', boxEdgeColor, ... + 'LineStyle', boxLineStyle, ... + 'FontWeight', boxFontWeight, ... + 'HorizontalAlignment', 'center'); - % Adjust position for the second box (slightly to the right) - boxPosition = [0.37 0.86 0.2 0.05]; % Adjusted position + % Adjust position for the second box (slightly to the right) + boxPosition = [0.37 0.86 0.2 0.05]; % Adjusted position - % Create second annotation box for PAPR - annotation('textbox', boxPosition, ... - 'String', ['PAPR(lin):',num2str(papr_),''], ... - 'BackgroundColor', boxColor, ... - 'EdgeColor', boxEdgeColor, ... - 'LineStyle', boxLineStyle, ... - 'FontWeight', boxFontWeight, ... - 'HorizontalAlignment', 'center'); + % Create second annotation box for PAPR + annotation('textbox', boxPosition, ... + 'String', ['PAPR(lin):',num2str(papr_),''], ... + 'BackgroundColor', boxColor, ... + 'EdgeColor', boxEdgeColor, ... + 'LineStyle', boxLineStyle, ... + 'FontWeight', boxFontWeight, ... + 'HorizontalAlignment', 'center'); - - annotation('textbox', boxPosition, ... - 'String',thirdboxstring , ... - 'BackgroundColor', boxColor, ... - 'EdgeColor', boxEdgeColor, ... - 'LineStyle', boxLineStyle, ... - 'FontWeight', boxFontWeight, ... - 'HorizontalAlignment', 'center'); - end + + annotation('textbox', boxPosition, ... + 'String',thirdboxstring , ... + 'BackgroundColor', boxColor, ... + 'EdgeColor', boxEdgeColor, ... + 'LineStyle', boxLineStyle, ... + 'FontWeight', boxFontWeight, ... + 'HorizontalAlignment', 'center'); + end end diff --git a/Classes/01_transmit/AWG.m b/Classes/01_transmit/AWG.m index 4a60a1d..6a6e894 100644 --- a/Classes/01_transmit/AWG.m +++ b/Classes/01_transmit/AWG.m @@ -8,6 +8,7 @@ classdef AWG < handle upsampling_method repetitions %repeat the signal to generate a longer sequence? fdac %needed + precomp_sinc_rolloff = 1; normalize2dac %want to normalize at first? either 0 or 1 bit_resolution %bit res. of quantizer (e.g. 5 bit) dac_min @@ -33,7 +34,8 @@ classdef AWG < handle arguments options.kover = 16; - options.upsampling_method upsampling_mode + options.upsampling_method upsampling_mode = upsampling_mode.samplehold; + options.precomp_sinc_rolloff = 1; options.repetitions = 1; options.normalize2dac = 1; options.fdac = 92e9; @@ -43,7 +45,7 @@ classdef AWG < handle options.skew_active = 0; options.awg_skew = 0; options.lpf_active = 0; - options.lpf_type = 0; + options.lpf_type = filtertypes.butterworth; options.f_cutoff = 32e9; options.H_lpf Filter @@ -95,7 +97,7 @@ classdef AWG < handle signalclass_in = obj.H_lpf.process(signalclass_in); else %4.B) just use a standard filter - lpf = Filter('filtdegree',5,"f_cutoff",obj.f_cutoff,"fsamp",obj.kover*obj.fdac,"filterType",obj.lpf_type); + lpf = Filter('filtdegree',5,"f_cutoff",obj.f_cutoff,"fs",obj.kover*obj.fdac,"filterType",obj.lpf_type); signalclass_in = lpf.process(signalclass_in); end end @@ -133,7 +135,7 @@ classdef AWG < handle obj.signal_length = length(data_in); %%%%%%%%% PRECOMP SINC ROLLOFF %%%%%%%%% - if 1 + if obj.precomp_sinc_rolloff % X: design FIR filter for sinc precomp % https://www.dsprelated.com/showarticle/1191.php ntaps = 13; diff --git a/Classes/01_transmit/ChannelFreqResp.m b/Classes/01_transmit/ChannelFreqResp.m index d003650..9a1be19 100644 --- a/Classes/01_transmit/ChannelFreqResp.m +++ b/Classes/01_transmit/ChannelFreqResp.m @@ -202,19 +202,19 @@ classdef ChannelFreqResp < handle function plot(obj) figure(55); - %clf; + clf; Havg = obj.H; %1) - subplot(2,1,1);hold on;box on;title('Magnitude Freq. Response'); + subplot(2,1,1);hold all;box on;title('Magnitude Freq. Response'); plot(obj.faxis/1e9, 20*log10(abs(obj.H_all)),'linewidth',0.1,'LineStyle','-','Color','#808080') ; xlim([0.2 .5*max(obj.faxis)*1e-9]); plot(obj.faxis/1e9, 20*log10(abs(Havg)),'LineWidth',2); grid on; %2) - subplot(2,1,2); hold on; box on; title('Phase Freq. Response'); + subplot(2,1,2); hold all; box on; title('Phase Freq. Response'); plot(obj.faxis/1e9, angle(obj.H_all),'linewidth',0.1,'LineStyle','-','Color','#808080') ; plot(obj.faxis/1e9, unwrap(angle(Havg)),'LineWidth',2) ; xlim([0.2 .5*max(obj.faxis)*1e-9]); @@ -228,7 +228,7 @@ classdef ChannelFreqResp < handle Havg = Havg./mean(Havg(2:10)); %3) - subplot(2,1,1); hold on; box on; title('Inverse Magnitude Freq. Response'); + subplot(2,1,1); hold all; box on; title('Inverse Magnitude Freq. Response'); plot(obj.faxis/1e9, 20*log10(abs(1./Havg)),"LineWidth",2,"Color",[0.3467 0.5360 0.6907]) ; xlim([0.2 .5*max(obj.faxis)*1e-9]); grid on; ylim([-1 15]); @@ -236,17 +236,19 @@ classdef ChannelFreqResp < handle yline(3,'LineWidth',2,'LineStyle','--'); %4) - subplot(2,1,2); hold on; box on; title('Inverse Phase Freq. Response'); + subplot(2,1,2); hold all; box on; title('Inverse Phase Freq. Response'); plot(obj.faxis/1e9, unwrap(angle(1./Havg)),"LineWidth",2,"Color",[0.3467 0.5360 0.6907]) ; xlim([0.2 .5*max(obj.faxis)*1e-9]); grid on; %%% plot for publication - figure(30);hold on;box on;title('Magnitude Freq. Response'); - % xlim([0 max(obj.faxis)*1e-9]); - % ylim([-20, 10]); - fax = obj.faxis - obj.f_ref/2; - Havg = Havg ./ max(abs(Havg)); - plot(fax/1e9, 20*log10(abs(fftshift(Havg)))+7,'LineWidth',2); + figure(1234);hold all;box on;title('Magnitude Freq. Response'); + %xlim([0.2 .5*max(obj.faxis)*1e-9]); + %ylim([-40, 2]); + Havg_smooth = smooth(Havg,50); + symaxis = (obj.faxis-(obj.f_ref/2))/1e9; + Havg = fftshift(Havg); + %Havg = smooth(Havg); + plot(symaxis, 20*log10(abs(Havg)),'LineWidth',0.5); grid on; @@ -362,7 +364,7 @@ classdef ChannelFreqResp < handle end - % fprintf('Frequency response information successfully loaded from %s\n', fullFileName); + fprintf('Frequency response information successfully loaded from %s\n', fullFileName); end end diff --git a/Classes/01_transmit/PAMmapper.m b/Classes/01_transmit/PAMmapper.m index c233a13..00ed0ca 100644 --- a/Classes/01_transmit/PAMmapper.m +++ b/Classes/01_transmit/PAMmapper.m @@ -23,7 +23,6 @@ classdef PAMmapper obj.scaling = rms(obj.get_levels()); - end function out = map(obj,signal_in) @@ -41,11 +40,25 @@ classdef PAMmapper end - function signalclass_out = demap(obj,signalclass_in) - signalclass_in.signal = obj.demap_(signalclass_in.signal); - lbdesc = ['Demap PAM ',num2str(obj.M),' symbols to bit stream']; - signalclass_in = signalclass_in.logbookentry(lbdesc,obj); - signalclass_out = signalclass_in; + function signal_out = demap(obj,signal_in) + issignalclass = 0; + + if isa(signal_in,'Signal') + signalclass = signal_in; + signal_in = signal_in.signal; + issignalclass = 1; + end + + signal_out = obj.demap_(signal_in); + + if issignalclass + lbdesc = ['Demap PAM ',num2str(obj.M),' symbols to bit stream']; + signal_in = signalclass; + signal_in = signal_in.logbookentry(lbdesc,obj); + signal_in.signal = signal_out; + signal_out = signal_in; + end + end function pam_sig = map_(obj,bitpattern) @@ -156,6 +169,8 @@ classdef PAMmapper case 6 %PAM 6 thres = [-3 5;-1 5;-3 -5;-1 -5;-5 3;-5 1;-5 -3;-5 -1;-1 3;-1 1;-1 -3;-1 -1;-3 3;-3 1;-3 -3;-3 -1;3 5;1 5;3 -5;1 -5;5 3;5 1;5 -3;5 -1;1 3;1 1;1 -3;1 -1;3 3;3 1;3 -3;3 -1]; + % thres = [-4 -2 0 2 4]; + % thres = thres ./ sqrt(10); case 8 % 8-ASK @@ -194,7 +209,6 @@ classdef PAMmapper end end - function [data_out] = demap_(obj,data_in) data_in= data_in'; if obj.M ~= 6 @@ -309,14 +323,35 @@ classdef PAMmapper end function [Signal_out] = quantize(obj,Signal_in) + constellation = obj.get_levels(); constellation = constellation ./ rms(constellation); - Signal_out = Signal_in; - dist = abs(Signal_in.signal - constellation); - [~,symbol_idx] = min(dist,[],2); % decision for closest constellation point - Signal_out.signal = constellation(symbol_idx); - Signal_out.signal = reshape(Signal_out.signal,size(Signal_in.signal)); + issignalclass = 0; + if isa(Signal_in,'Signal') + issignalclass = 1; + Sig_class = Signal_in; + Signal_in = Signal_in.signal; + end + + [~,high_dim_sig] = max(size(Signal_in)); + [~,high_dim_const] = max(size(constellation)); + + if high_dim_sig == high_dim_const + Signal_in = Signal_in'; + end + + dist = abs(Signal_in - constellation); + [~,symbol_idx] = min(dist,[],2); % decision for closest constellation point + Signal_out = constellation(symbol_idx); + Signal_out = reshape(Signal_out,size(Signal_in)); + + if issignalclass + Sig_class.signal = Signal_out; + Signal_out = Sig_class; + end + + end diff --git a/Classes/01_transmit/PAMsource.m b/Classes/01_transmit/PAMsource.m index 4e96911..4a410a0 100644 --- a/Classes/01_transmit/PAMsource.m +++ b/Classes/01_transmit/PAMsource.m @@ -151,6 +151,12 @@ classdef PAMsource sym_max = max(symbols.signal); end + % symbols.move_it_spectrum("fignum",222,"displayname","Symbols only"); + + + % symbols.spectrum("fignum",222,"displayname","Symbols only","normalizeTo0dB",1); + + %%%%% Pulse-forming %%%%%% if obj.applypulseform digi_sig = obj.pulseformer.process(symbols); diff --git a/Classes/01_transmit/Pulseformer.m b/Classes/01_transmit/Pulseformer.m index a306ef8..c8e8537 100644 --- a/Classes/01_transmit/Pulseformer.m +++ b/Classes/01_transmit/Pulseformer.m @@ -4,6 +4,8 @@ classdef Pulseformer properties(Access=public) fdac + end + properties(Access=private) fsym pulse pulselength diff --git a/Classes/04_DSP/Coding/Duobinary.m b/Classes/04_DSP/Coding/Duobinary.m index 5801163..e93c594 100644 --- a/Classes/04_DSP/Coding/Duobinary.m +++ b/Classes/04_DSP/Coding/Duobinary.m @@ -1,10 +1,9 @@ classdef Duobinary %Duobinary Coding - % should work - + % should work + properties(Access=public) - end methods (Access=public) @@ -12,6 +11,7 @@ classdef Duobinary function obj = Duobinary() %NAME Construct an instance of this class + end function signal = precode(~,signal) @@ -52,7 +52,7 @@ classdef Duobinary % end for k = 2:numel(data) - bk(k) =mod(data(k)-bk(k-1),M); + bk(k) = mod(data(k)-bk(k-1),M); end %make bipolar @@ -78,7 +78,13 @@ classdef Duobinary end - function signal = encode(~,signal) + function signal = encode(~,signal,options) + + arguments + ~ + signal + options.M = []; + end if isa(signal,'Signal') data = signal.signal; @@ -88,17 +94,19 @@ classdef Duobinary data = data./rms(data); - u = unique(data); - M = numel(u); + if isempty(options.M) + u = unique(data); + options.M = numel(u); + end %make unipolar - if M == 4 + if options.M == 4 data = data .* sqrt(5); - elseif M == 6 + elseif options.M == 6 data = data .* sqrt(10); - elseif M == 8 + elseif options.M == 8 data = data .* sqrt(21); - elseif M == 16 + elseif options.M == 16 data = data .* sqrt(85); warning('Check if PAM16 implementation, mapping and scaling is correct!') end @@ -108,7 +116,7 @@ classdef Duobinary data = data - b; data = data ./ 2; - % assert(isequal((0:M-1)',unique(data)),'Check Duobinary Precoding'); %seems the signal is not unipolar + % assert(isequal((0:options.M-1)',unique(data)),'Check Duobinary Precoding'); %seems the signal is not unipolar % duobinary coding (1+D) % coeff = [1,1]; @@ -132,12 +140,14 @@ classdef Duobinary mean_power = sum((unique_points .^ 2) .* probabilities); scaling_factor = sqrt(mean_power); - if M == 4 + if options.M == 4 data = data ./ sqrt(2.5); % 7-level constellation weighted with probability after DB code i.e. mean([-3 3 -2 -2 2 2 -1 -1 -1 1 1 1 0 0 0 0].^2) = 2.5 --> sqrt(2.5) == rms(constellation) - elseif M == 6 + elseif options.M == 6 data = data ./ sqrt(5.8); - elseif M == 8 + elseif options.M == 8 data = data ./ sqrt(10.5); % 15-level constellation weighted with probability after DB code i.e. + else + error("Error in: Duobinary encode > scale unipolar to bipolar > The data is not PAM4, PAM6 or PAM 8? ") end if isa(signal,'Signal') @@ -158,24 +168,30 @@ classdef Duobinary end - function signalclass = decode(~,signalclass) + function signalclass = decode(~,signalclass,options) + + arguments + ~ + signalclass + options.M = []; + end data = signalclass.signal; u = unique(data); I = numel(u); %number of duobinary coded const. points - M = (I+1)/2; %PAM-M order + if isempty(options.M) + M = (I+1)/2; %PAM-M order + else + M = options.M; %PAM-M order + end %make unipolar - if I == 7 + if I == 7 || I == 6 data = data .* sqrt(2.5); elseif I == 11 - %todo data = data .* sqrt(5.8); - warning('Check db decode implementation, mapping and scaling is correct!') elseif I == 15 data = data .* sqrt(10.5); - elseif I == 16 - warning('Check db decode implementation, mapping and scaling is correct!') end data = round(data); @@ -196,6 +212,8 @@ classdef Duobinary data = data ./ sqrt(10); elseif M == 8 data = data ./ sqrt(21); + else + errormsg("Error in: Duobinary decode > scale unipolar to bipolar > The data is not PAM4, PAM6 or PAM 8? ") end signalclass.signal = data; diff --git a/Classes/04_DSP/Equalizer/EQ.m b/Classes/04_DSP/Equalizer/EQ.m index 9f528ab..a03d66b 100644 --- a/Classes/04_DSP/Equalizer/EQ.m +++ b/Classes/04_DSP/Equalizer/EQ.m @@ -1,4 +1,4 @@ -classdef EQ %< handle +classdef EQ < handle %EQ Summary of this class goes here % Detailed explanation goes here @@ -289,9 +289,9 @@ classdef EQ %< handle e_dc = e_dc - obj.DCmu*error; - obj.error_log.e_ffe(cnt,trainloops) = e_ffe; - obj.error_log.e_dfe(cnt,trainloops) = e_dfe; - obj.error_log.e_(cnt,trainloops) = error; + % obj.error_log.e_ffe(cnt,trainloops) = e_ffe; + % obj.error_log.e_dfe(cnt,trainloops) = e_dfe; + % obj.error_log.e_(cnt,trainloops) = error; cnt = cnt+1; if obj.Nb(1) > 0 @@ -460,7 +460,7 @@ classdef EQ %< handle if 1%mu_mat ~= 0 e_dc = e_dc - obj.DCmu*error; - error_log(cnt,dd_loop) = e_dc; + % error_log(cnt,dd_loop) = e_dc; cnt = cnt+1; end diff --git a/Classes/04_DSP/Equalizer/Postfilter.m b/Classes/04_DSP/Equalizer/Postfilter.m new file mode 100644 index 0000000..1fed009 --- /dev/null +++ b/Classes/04_DSP/Equalizer/Postfilter.m @@ -0,0 +1,98 @@ +classdef Postfilter < handle + %NAME Summary of this class goes here + % Detailed explanation goes here + + properties(Access=public) + ncoeff = 2; + coefficients = []; + useBurg = NaN + end + + methods (Access=public) + function obj = Postfilter(options) + %NAME Construct an instance of this class + % Detailed explanation goes here + + arguments + options.useBurg = NaN + options.coefficients = [] + options.ncoeff double = 2 + end + + % + fn = fieldnames(options); + for n = 1:numel(fn) + try + obj.(fn{n}) = options.(fn{n}); + end + end + + % do more stuff + + end + + function signalclass_out = process(obj,signalclass_in,noiseclass_in,options) + + arguments + obj + signalclass_in + noiseclass_in + options.useBurg = obj.useBurg; + options.coefficients = obj.coefficients; + end + + if ~isnan(options.useBurg) && options.useBurg + + disp('using burg alg') + obj.coefficients = arburg(noiseclass_in.signal,obj.ncoeff); + + elseif ~isempty(options.coefficients) + + disp('using given taps') + obj.coefficients = options.coefficients; + obj.useBurg = 0; + + else + + end + + signalclass_in = signalclass_in.filter(obj.coefficients,1); + + % append to logbook + lbdesc = ['Postfilter']; + signalclass_in = signalclass_in.logbookentry(lbdesc); + + % write to output + signalclass_out = signalclass_in; + + end + + function showFilter(obj,noiseclass_in,options) + + arguments + obj + noiseclass_in + options.fignum = 121 + options.color = [] + end + + % noiseclass_in.spectrum('displayname','Noise PSD shifted to 0dBm','fignum',options.fignum,'normalizeTo0dB',1); + + figure(options.fignum) + [h,w] = freqz(1,obj.coefficients,length(noiseclass_in),"whole",noiseclass_in.fs); + h = h/max(abs(h)); + hold on + w_ = (w - noiseclass_in.fs/2); + + if isempty(options.color) + plot(w_.*1e-9,20*log10(fftshift(abs(h))),'DisplayName',['Burg Coeffs: ', num2str(round(obj.coefficients,2)), ' '],'LineWidth',2); + else + plot(w_.*1e-9,20*log10(fftshift(abs(h))),'DisplayName',['Burg Coeffs: ', num2str(round(obj.coefficients,2)), ' '],'Color',options.color,'LineWidth',2); + end + + ylim([-30,2]); + end + + end + +end diff --git a/Classes/04_DSP/Equalizer/VNLE.m b/Classes/04_DSP/Equalizer/VNLE.m index 397d58e..d95bb98 100644 --- a/Classes/04_DSP/Equalizer/VNLE.m +++ b/Classes/04_DSP/Equalizer/VNLE.m @@ -57,7 +57,7 @@ classdef VNLE < handle end - function [X] = process(obj, X, D) + function [X,N] = process(obj, X, D) % actual processing of the signal (steps 1. - 3.) % 1 normalize RMS @@ -91,6 +91,9 @@ classdef VNLE < handle lbdesc = [num2str(obj.order),' tap FFE']; X = X.logbookentry(lbdesc); % append to logbook + N = X; + N = X - D; + end @@ -156,7 +159,6 @@ classdef VNLE < handle end if ~all(mu==0,'all') %mu has not only zeros - % obj.e = obj.e - (mu * err * x_in) ; % Weight update rule of LMS obj.e = obj.e - ( (mu * x_in) * err ) ; % Weight update rule of LMS else normalizationfactor = (x_in.' * x_in); diff --git a/Classes/04_DSP/Sequence Detection/MLSE.m b/Classes/04_DSP/Sequence Detection/MLSE.m index aad4134..59b9c33 100644 --- a/Classes/04_DSP/Sequence Detection/MLSE.m +++ b/Classes/04_DSP/Sequence Detection/MLSE.m @@ -1,4 +1,4 @@ -classdef MLSE +classdef MLSE < handle %MLSE calculates the most probable sequence for an input signal with given/ known channel impulse response of any length properties(Access=public) @@ -34,17 +34,22 @@ classdef MLSE end - function signalclass = process(obj,signalclass) + function [signalclass_hd,signalclass_sd] = process(obj,signalclass,ref_symbolclass) data_in = signalclass.signal; + data_ref = ref_symbolclass.signal; - data_out = obj.process_(data_in); + [data_out_hd,data_out_sd] = obj.process_(data_in,data_ref); - signalclass.signal = data_out; + signalclass_hd = signalclass; + signalclass_hd.signal = data_out_hd; + + signalclass_sd = signalclass; + signalclass_sd.signal = data_out_sd; end - function data_out = process_(obj,data_in) + function [VITERBI_ESTIMATION_SYMBOLS,soft_decisions] = process_(obj,data_in,data_ref) % remove unnecessary zeros at start of impulse response to keep @@ -58,6 +63,17 @@ classdef MLSE obj.DIR = [0 obj.DIR]; end + + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + %%%%%% PREPARATIONS %%%%%%%% + + %%%% Separate the equalized signal into the respective levels based on the actually transmitted level + constellation = unique(data_ref); + decisionLevels = (constellation(1:end-1) + constellation(2:end)) / 2; + tx_bits = PAMmapper(numel(constellation),0).demap(data_ref); + + + % impulse respnse i.e. [0.5, 1.0000] obj.DIR = flip(obj.DIR); % RMS normalization of input data @@ -77,6 +93,7 @@ classdef MLSE % Calculate all possible input symbols for the desired impulse % response. Row number is the index of the previous state, % column number is the index of the next state + % noise free received == branch metrics noise_free_received = zeros(length(states),length(states)); count_row = 1; count_col = 1; @@ -101,127 +118,302 @@ classdef MLSE end end + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + %%%%% FORWARD PASS %%%%% - - % - % %% Optimized - % % Preallocate and initialize variables - % data_out = NaN(size(data_in)); % output vector - % sum_path_metrics_res = zeros(length(states), length(data_in)); - % path_idx = zeros(length(states), length(data_in)); - % - % % Precompute repmat size - % num_states = length(states); - % num_signals = numel(noise_free_received); - % - % % First trellis path (initialize) - % sum_path_metrics = zeros(num_states, num_states); - % path_metrics = (abs(data_in(1) - noise_free_received)).^2; % Use broadcasting instead of repmat - % sum_path_metrics = sum_path_metrics + path_metrics; % Compute initial path metrics - % - % [sum_path_metrics_res(:,1), path_idx(:,1)] = min(sum_path_metrics, [], 2); % Best path for first step - % - % % Preallocate path_metrics and sum_path_metrics to avoid reallocating in each loop - % path_metrics = zeros(num_states, num_signals); - % - % % Loop over remaining trellis paths - % for n = 2:length(data_in) - % % Avoid reallocation of sum_path_metrics, reuse the same matrix and update - % previous_sum_path_metrics = sum_path_metrics_res(:,n-1).'; % Transpose once for broadcasting - % sum_path_metrics = repmat(previous_sum_path_metrics, num_states, 1); % Avoid dynamic resizing - % - % % Calculate path metrics using broadcasting - % path_metrics = (abs(data_in(n) - noise_free_received)).^2; % Avoid repmat - % - % % Update sum path metrics - % sum_path_metrics = sum_path_metrics + path_metrics; - % - % % Find the best path for each state and store results - % [sum_path_metrics_res(:,n), path_idx(:,n)] = min(sum_path_metrics, [], 2); - % end - % - % %% Traceback - % ideal_path = NaN(1, length(data_in)+1); % Preallocate ideal path - % [~, ideal_path(length(data_in)+1)] = min(sum_path_metrics_res(:,length(data_in))); % Start from final state - % - % % Trace back through trellis - % for h = length(data_in):-1:1 - % ideal_path(h) = path_idx(ideal_path(h+1),h); % Follow the best path back - % end - % - % % Extract the output indices - % idx_out = ideal_path(2:end); + % Initialize the output vector + pm = zeros(length(states),length(states)); + bm_fw = zeros(length(states),length(states),length(data_in)); + + % Forward Recursion (FSM Computation) + for n = 1:length(data_in) + bm = abs(data_in(n) - noise_free_received).^2; + pm = pm + bm; + [pm_survivor_fw(:,n),pm_survivor_fw_idx(:,n)] = min(pm,[],2); % choose lowest path metric as new state + pm = repmat(pm_survivor_fw(:,n).',length(states),1); % update pm (chosen state to 2nd dimension -> FROM state) + bm_fw(:,:,n) = bm; - % OLD - % initilaize the output vector - data_out = NaN(size(data_in)); - - sum_path_metrics = zeros(length(states),length(states)); - - % first trellis path - % euclidian distance as path metric - path_metrics = (abs(repmat(data_in(1),size(noise_free_received)) - noise_free_received)).^2; - sum_path_metrics = sum_path_metrics + path_metrics; % calculation of all possible sum path metrics - [sum_path_metrics_res(:,1),path_idx(:,1)] = min(sum_path_metrics,[],2); % find the best path to each state, store sum path metric and predecessor for each state - - % remaining trellis paths - for n = 2:length(data_in) - sum_path_metrics = repmat(sum_path_metrics_res(:,n-1).',length(states),1); - % path_metrics = (repmat(data_in(n),size(noise_free_received)) - noise_free_received).^2;%.*prob_mat; - path_metrics = (abs(repmat(data_in(n),size(noise_free_received)) - noise_free_received)).^2; - sum_path_metrics = sum_path_metrics + path_metrics; - [sum_path_metrics_res(:,n),path_idx(:,n)] = min(sum_path_metrics,[],2); end - %% trace back - ideal_path = NaN(1,length(data_in)+1); - % find ideal trellis path by going through the trellis - % backwards - [~,ideal_path(length(data_in)+1)] = min(sum_path_metrics_res(:,length(data_in))); + % we can now get the best path as min + best_fw_path = NaN(1,length(data_in)+1); + + % find ideal trellis path by going through the trellis backwards + [~,best_fw_path(length(data_in)+1)] = min(pm_survivor_fw(:,length(data_in))); + + + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + %%%%% BACKWARD PASS %%%%% + + % Initialize the output vector + pm = zeros(length(states),length(states)); + pm_survivor_bw = zeros(length(states),length(data_in)+1); + pm_survivor_bw_idx = zeros(length(states),length(data_in)+1); + bm_bw = zeros(length(states),length(states),length(data_in)+1); % starting with the state that has the lowest sum path % metric, follow the stored information about the % predecessor for h = length(data_in):-1:1 - ideal_path(h) = path_idx(ideal_path(h+1),h); + + best_fw_path(h) = pm_survivor_fw_idx(best_fw_path(h+1),h); + + bm = abs(data_in(h) - noise_free_received).^2; + pm = pm + bm.'; + [pm_survivor_bw(:,h),pm_survivor_bw_idx(:,h)] = min(pm,[],2); % choose lowest path metric as new state + pm = repmat(pm_survivor_bw(:,h).',length(states),1); % update pm (chosen state to 2nd dimension -> FROM state) + + bm_bw(:,:,h) = bm; + end - idx_out = ideal_path(2:length(data_in)+1); + VITERBI_ESTIMATION_IDX(1:length(data_in)) = first_sym(best_fw_path(2:end)); + VITERBI_ESTIMATION_SYMBOLS(1:length(data_in)) = constellation(best_fw_path(2:end)); + + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + %%%%% FORWARD PASS %%%%% + + %calc the log probabilities (llp's) + + for k = 2:length(data_in) + + fsm = repmat(pm_survivor_fw(:,k-1)',[length(states),1]); %pm_survivor_fw size: length(states)xlength(sequence) + bm = bm_fw(:,:,k); %bm_fw size: length(states)xlength(states)xlength(sequence) + bsm = repmat(pm_survivor_bw(:,k)',[length(states),1]); %pm_survivor_bw size: length(states)xlength(sequence)+1 + + llp(:,k) = min(fsm+bm+bsm,[],2); + + end + + % directly decide based on lowest LLP index + [~,llp_based_state_seq]=min(llp); + LLP_EST(1:length(data_in)) = constellation(llp_based_state_seq); + rx_bits = PAMmapper(numel(constellation),0).demap(LLP_EST'); + [~,~,ber_llp,~] = calc_ber(rx_bits,tx_bits,"skip_front",100,"skip_end",150,"returnErrorLocation",1); + fprintf('LLP BER : %.2e \n',ber_llp); + % [~,~,ber_llp,~] = calc_ber(circshift(rx_bits,1),tx_bits,"skip_front",100,"skip_end",150,"returnErrorLocation",1); + % fprintf('LLP BER +1: %.2e \n',ber_llp); + % [~,~,ber_llp,~] = calc_ber(circshift(rx_bits,-1),tx_bits,"skip_front",100,"skip_end",150,"returnErrorLocation",1); + % fprintf('LLP BER -1: %.2e \n',ber_llp); + + %%%% DECIDE based on Viterbi traceback + rx_bits = PAMmapper(numel(constellation),0).demap(VITERBI_ESTIMATION_SYMBOLS'); + [~,~,ber_viterbi,~] = calc_ber(rx_bits,tx_bits,"skip_front",100,"skip_end",150,"returnErrorLocation",1); + fprintf('Viterbi BER: %.2e \n',ber_viterbi); + % [~,~,ber_viterbi,~] = calc_ber(circshift(rx_bits,1),tx_bits,"skip_front",100,"skip_end",150,"returnErrorLocation",1); + % fprintf('Viterbi BER: %.2e \n',ber_viterbi); + + % directly decide based on the FW path metrics + [~,fw_direct_state_seq]=min(pm_survivor_fw); + FW_EST(1:length(data_in)) = constellation(fw_direct_state_seq); + rx_bits = PAMmapper(numel(constellation),0).demap(FW_EST'); + [~,~,ber_fw,~] = calc_ber(rx_bits,tx_bits,"skip_front",100,"skip_end",150,"returnErrorLocation",1); + fprintf('FW BER: %.2e \n',ber_fw); + + % directly decide based on the BW path metrics + [~,bw_direct_state_seq]=min(pm_survivor_bw); + BW_EST(1:length(data_in)) = constellation(bw_direct_state_seq(2:end)); + rx_bits = PAMmapper(numel(constellation),0).demap(BW_EST'); + [~,~,ber_bw,~] = calc_ber(rx_bits,tx_bits,"skip_front",100,"skip_end",150,"returnErrorLocation",1); + fprintf('BW BER: %.2e \n',ber_bw); + % [~,~,ber_viterbi,~] = calc_ber(circshift(rx_bits,1),tx_bits,"skip_front",100,"skip_end",150,"returnErrorLocation",1); + % fprintf('BW BER: %.2e \n',ber_viterbi); + % [~,~,ber_viterbi,~] = calc_ber(circshift(rx_bits,-1),tx_bits,"skip_front",100,"skip_end",150,"returnErrorLocation",1); + % fprintf('BW BER: %.2e \n',ber_viterbi); + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + tx_symbolpos = zeros(numel(constellation),length(data_ref)); + est_symbolpos = zeros(numel(constellation),length(data_ref)); + for lvl = 1:numel(constellation) + tx_symbolpos(lvl,data_ref==constellation(lvl)) = 1; + est_symbolpos(lvl,VITERBI_ESTIMATION_IDX==first_sym(lvl)) = 1; + est_symbolpos_llm(lvl,llp_based_state_seq==lvl) = 1; + end + est_symbolpos= logical(est_symbolpos); + tx_symbolpos = logical(tx_symbolpos); + est_symbolpos_llm = logical(est_symbolpos_llm); + figure(299);clf;hold on; + llp_filt = NaN(length(states),length(data_in)); + llp_ = llp - min(llp,[],1); + for c = 2%:numel(constellation) + for c2 = 1:3%numel(constellation) - if obj.duobinary_output - %use duobinary encoder, output is already scaled inside this - %one - data_out = Duobinary().encode(first_sym(idx_out)); + idx = est_symbolpos_llm(c,:); + llp_filt(c2,idx) = (llp(c2,idx)); + + plotidx = 2:200000; + scatter(plotidx,llp_filt(c2,plotidx),1,'o','LineWidth',1,'DisplayName',sprintf('LLP of Symbol %d | %d was transmitted',c2,c)); - else - % - data_out(1:length(data_in)) = first_sym(idx_out); - % scale to rms = 1 using the standard sqrt() expressions - if obj.M == 4 - data_out = data_out./sqrt(5); - elseif obj.M == 6 - data_out = data_out./sqrt(10); - elseif obj.M == 8 - data_out = data_out./sqrt(21); end + end + + % Assume llp is a 4 x N matrix (4 PAM-4 symbols, N time steps) + [numSymbols, numTimeSteps] = size(llp); + P_symbols = zeros(numSymbols, numTimeSteps); % To hold the soft output probabilities + + for k = 1:numTimeSteps + + % Compute the exponentials. (Use -llp_shifted if llp's are costs.) + exponents = -llp_(:, k); + + % Normalize to form a probability vector. + P_symbols(:, k) = exponents / sum(exponents); + end + + % Optionally, if you prefer a single soft output value per symbol (an expectation), + % define your PAM-4 constellation levels, e.g.: + soft_output = sum(P_symbols .* constellation, 1); % 1 x N vector of soft outputs + + + %%%% BITWISE LLR's ??? %%%%% + figure(100); + clf + hold on + title('LLR between inner and outer bits') + bitmapping = PAMmapper(numel(constellation),0).demap(constellation); + for bp = 1:size(bitmapping,2) + pos_bitone = find(bitmapping(:,bp)==1); + pos_bitzero = find(bitmapping(:,bp)~=1); + + llr_bits(bp,:) = min(llp(pos_bitone,:),[],1) - min(llp(pos_bitzero,:),[],1); + + subplot(size(bitmapping,2),1,bp) + scatter(1:length(data_ref),llr_bits(bp,:),1,'.'); + end + %%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + % From: Log-Likelihood Probabilities LLP --> To: Log-Likelihood Ratios LLR + for s = 1:length(states)-1 + llr(s,:) = llp_(s,:) - llp_(s+1,:); % subtract llp's of successive const. points to get llr's + end + + % Build Sets of LLR's that contain only those values at + % timepoint k, where the symbols: + % a) were actually transmitted: set "S" + % b) were decoded by viterbi: set "SC" + S = NaN(length(states)-1,length(data_in)); + SC = NaN(length(states)-1,length(data_in)); + + llp_inf = llp_; + llp_inf(llp_==0) = Inf; + [~,scnd_idx] = min(llp_inf,[],1) ; + for s = 1:length(states)-1 + + %%% SET "S" + % find all time indices k, where const point s was actually transmitted + indice = tx_symbolpos(s,:)==1; + S(s,indice) = llr(s,indice); + %calc mean of all llr's where symbol s was transmitted + K(s,1) = mean(S(s,indice),'omitnan'); + + % find all time indices k, where const. point s+1 was actually transmitted + indice_plusone = tx_symbolpos(s+1,:)==1; + S(s,indice_plusone) = llr(s,indice_plusone); + K(s,2) = mean(S(s,indice_plusone),'omitnan'); + + + %%% SET "SC" + % find all time indices k, where symbol s was decoded + % idx: find positions in time where a symbol s was decoded + idx = est_symbolpos_llm(s,:); + % idx 2: find positions where the strongest competitor is + % s+1, i.e. the second best llp is at s+1 + idx2 = scnd_idx == s+1; + SC(s,idx&idx2) = llr(s,idx&idx2); + KC(s,1) = mean(SC(s,idx&idx2),'omitnan'); + + % find all time indices k, where symbol s+1 was decoded + % idx: find positions in time where a symbol s+1 was decoded + idx = est_symbolpos_llm(s+1,:); + idx2 = scnd_idx == s; + % idx 2: find positions where the strongest competitor is + % s, i.e. the second best llp is at s + SC(s,idx&idx2) = llr(s,idx&idx2); + KC(s,2) = mean(SC(s,idx&idx2),'omitnan'); + + % scale the sets, using the average (?) of the + llrcn(s,:) = SC(s,:) * ( constellation(s+1)-constellation(s) ) ./ ( K(s,2)-K(s,1)) + decisionLevels(s); + + end + + figure(111) + title("Bla") + clf + for s = 1:length(states)-1 + figure(1111) + hold on + title(sprintf('llrcn = llp %d - llp %d',s, s+1,s, s+1)); + scatter(1:length(llrcn),llrcn(s,:),1,'.'); + + + % STUFENARTIGE LLR'S UND LLP'S %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + figure(111) + + subplot(1,length(states),s) + hold on + title(sprintf('llr = llp %d - llp %d \n SC=llr(tx sym = %d or %d)',s, s+1,s, s+1)); + scatter(1:length(llr),llr(s,:),1,'.'); + scatter(1:length(SC),SC(s,:),1,'.'); + yline([K(s,1),K(s,2)]); + low = min(min(llr)); + hi = max(max(llr)); + ylim([low,hi]); + + subplot(1,length(states),length(states)) + hold on + scatter(1:length(llr),llr(s,:),1,'.'); + ylim([low,hi]); + + + % HISTOGRAMME %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + figure(112) + subplot(length(states),1,s) + hold on + title(sprintf('histogram of llr; between const point %d - %d',s, s+1)); + histogram(llrcn(s,:),10000,'EdgeAlpha',0) + % histogram(SC(s,:),10000,'EdgeAlpha',0) + xlim([-20, 20]); + subplot(length(states),1,length(states)) + hold on + histogram(llrcn(s,:),10000,'EdgeAlpha',0) + % histogram(SC(s,:),10000,'EdgeAlpha',0) + % xlim([-20, 20]); end + softdecisions = mean(llrcn,1,'omitnan'); + + distance = abs(VITERBI_ESTIMATION_SYMBOLS-llrcn); + [win_cost,win_idx] = min(distance,[],1); + + for i = 1:length(data_in) + soft_decisions(i) = llrcn(win_idx(i),i); + end + + soft_decisions = max(llrcn,[],1); + + showLevelHistogram(soft_decisions,data_ref) + + figure() + % scatter(1:length(data_in),VITERBI_ESTIMATION_SYMBOLS,1,'.'); + scatter(1:length(data_in),soft_decisions,1,'.'); + + + MLM_ESTIMATION(1:length(data_in)) = PAMmapper(numel(constellation),0).quantize(soft_decisions)'; + rx_bits = PAMmapper(numel(constellation),0).demap(MLM_ESTIMATION'); + [~,~,ber_mlm,~] = calc_ber(rx_bits,tx_bits,"skip_front",100,"skip_end",150,"returnErrorLocation",1); + fprintf('MLM BER: %.2e \n',ber_mlm); end end methods (Access=private) - % Cant be seen from outside! So put all your functions here that can/ - % shall not be called from outside - end end diff --git a/Classes/04_DSP/Sequence Detection/MLSE_viterbi.m b/Classes/04_DSP/Sequence Detection/MLSE_viterbi.m new file mode 100644 index 0000000..9a67728 --- /dev/null +++ b/Classes/04_DSP/Sequence Detection/MLSE_viterbi.m @@ -0,0 +1,177 @@ +classdef MLSE_viterbi < handle + %MLSE calculates the most probable sequence for an input signal with given/ known channel impulse response of any length + + properties(Access=public) + M %PAM-M + DIR + trellis_states + duobinary_output + end + + methods (Access=public) + + function obj = MLSE_viterbi(options) + %NAME Construct an instance of this class + % Detailed explanation goes here + + arguments + options.M double = 4; + options.DIR double = [1]; + options.trellis_states double = [-3 -1 1 3]; + options.duobinary_output logical = false; + + end + + % + fn = fieldnames(options); + for n = 1:numel(fn) + try + obj.(fn{n}) = options.(fn{n}); + end + end + + % do more stuff + + end + + function signalclass = process(obj,signalclass) + + data_in = signalclass.signal; + + data_out = obj.process_(data_in); + + signalclass.signal = data_out; + + end + + function data_out = process_(obj,data_in) + + + % remove unnecessary zeros at start of impulse response to keep + % number of trellis states minimal + DIR_nonzero = find(obj.DIR ~= 0); + if DIR_nonzero(1) > 1 + obj.DIR(1:DIR_nonzero(1)-1) = []; + end + + if isscalar(obj.DIR) + obj.DIR = [0 obj.DIR]; + end + + + %%%%%%%%%%%%%%%%%%%%%%%%%%%% WORKING + % impulse respnse i.e. [0.5, 1.0000] + obj.DIR = flip(obj.DIR); + + % RMS normalization of input data + data_in = data_in ./ rms(data_in); + + % seems to be the only way to use combvec for a flexible amount + % of vectors. 'combs' contains all trellis states + pre_comb_mat = repmat(obj.trellis_states,length(obj.DIR)-1,1); + pre_comb_cell = mat2cell(pre_comb_mat,ones(1,size(pre_comb_mat,1)),size(pre_comb_mat,2)); + combs = fliplr(combvec(pre_comb_cell{:}).'); + + % Save first and last symbol of each state + first_sym = combs(:,1); + last_sym = combs(:,end); + states = sum(combs,2); + + % Calculate all possible input symbols for the desired impulse + % response. Row number is the index of the previous state, + % column number is the index of the next state + % noise free received == branch metrics + noise_free_received = zeros(length(states),length(states)); + count_row = 1; + count_col = 1; + for l1 = 1:length(states) + for l2 = 1:length(states) + if sum(combs(l2,2:end) == combs(l1,1:end-1)) == size(combs,2)-1 + noise_free_received(count_row,count_col) = sum(combs(l2,:).*obj.DIR(end:-1:2)) + last_sym(l1)*obj.DIR(1); + else + noise_free_received(count_row,count_col) = inf; + end + count_row = count_row + 1; + end + count_col = count_col + 1; + count_row = 1; + end + + % match amplitude levels of input signal to those of the calculated ideal symbols + % i.e. match the rms values of data_in to noise_free_received + if isreal(data_in) + if obj.M == round(obj.M) + data_in = data_in * rms(noise_free_received(noise_free_received ~= inf),'all','omitnan'); + end + end + + % OLD + % initilaize the output vector + data_out = NaN(size(data_in)); + + sum_path_metrics = zeros(length(states),length(states)); + + % first trellis path + % euclidian distance as path metric + path_metrics = (abs(repmat(data_in(1),size(noise_free_received)) - noise_free_received)).^2; + sum_path_metrics = sum_path_metrics + path_metrics; % calculation of all possible sum path metrics + [sum_path_metrics_res(:,1),path_idx(:,1)] = min(sum_path_metrics,[],2); % find the best path to each state, store sum path metric and predecessor for each state + + % remaining trellis paths + for n = 2:length(data_in) + sum_path_metrics = repmat(sum_path_metrics_res(:,n-1).',length(states),1); + % path_metrics = (repmat(data_in(n),size(noise_free_received)) - noise_free_received).^2;%.*prob_mat; + path_metrics = (abs(repmat(data_in(n),size(noise_free_received)) - noise_free_received)).^2; + sum_path_metrics = sum_path_metrics + path_metrics; + [sum_path_metrics_res(:,n),path_idx(:,n)] = min(sum_path_metrics,[],2); + end + + %% trace back + ideal_path = NaN(1,length(data_in)+1); + % find ideal trellis path by going through the trellis + % backwards + [~,ideal_path(length(data_in)+1)] = min(sum_path_metrics_res(:,length(data_in))); + + % starting with the state that has the lowest sum path + % metric, follow the stored information about the + % predecessor + for h = length(data_in):-1:1 + ideal_path(h) = path_idx(ideal_path(h+1),h); + end + + idx_out = ideal_path(2:length(data_in)+1); + %%%%%%%%%%%%%%%%%%%%%%%%%%%% WORKING + + + + + if obj.duobinary_output + %use duobinary encoder, output is already scaled inside this + %one + data_out = Duobinary().encode(first_sym(idx_out)); + + else + % + data_out(1:length(data_in)) = first_sym(idx_out); + % scale to rms = 1 using the standard sqrt() expressions + if obj.M == 4 + data_out = data_out./sqrt(5); + elseif obj.M == 6 + data_out = data_out./sqrt(10); + elseif obj.M == 8 + data_out = data_out./sqrt(21); + end + + end + + + end + end + + methods (Access=private) + % Cant be seen from outside! So put all your functions here that can/ + % shall not be called from outside + + + end +end diff --git a/Classes/04_DSP/TransmissionPerformance.m b/Classes/04_DSP/TransmissionPerformance.m new file mode 100644 index 0000000..49ca0c7 --- /dev/null +++ b/Classes/04_DSP/TransmissionPerformance.m @@ -0,0 +1,214 @@ +classdef TransmissionPerformance + % TransmissionPerformance + % + % This class calculates the best possible net data rate (in bits/s) + % from a given gross rate (bits/s) and a measured channel quality + % parameter (either bit error ratio (BER) or NGMI). The class uses + % lookup tables for three different FEC modes: + % + % 1. SD+HD concatenated (uses overall code rate and an NGMI threshold) + % 2. SD+HD concatenated with punctured LDPC (uses overall code rate and an NGMI threshold) + % 3. HD-only (uses a code rate and a BER threshold) + % + % The basic algorithm is as follows: + % 1. Given a measured quality (NGMI or BER) for each measurement, find in + % the table the first (i.e. “best”) entry that is satisfied by the + % measured value. For NGMI the condition is measured NGMI >= threshold, + % while for BER the condition is measured BER <= threshold. + % 2. Use the corresponding overall code rate to compute: + % + % net rate = gross rate * code rate. + % + % USAGE EXAMPLE (array inputs): + % + % tp = TransmissionPerformance; + % % Suppose we have 3 measurements: + % % Gross rates: 10, 15, and 20 Gbps + % % Measured NGMI: 0.92, 0.88, and 0.85 + % % Measured BER: 1e-4, 7e-3, and 2e-2 + % netrates = tp.calculatenetrate([10e9 15e9 20e9], ... + % 'NGMI', [0.92 0.88 0.85], ... + % 'BER', [1e-4 7e-3 2e-2]); + % + % The returned structure netrates will contain the net rates (and the + % used code rates and thresholds) for each mode in vector form. + + properties (Constant) + %% Lookup Table for SD+HD concatenated (using NGMI) + % Overall code rate and NGMI threshold for each row. + OVERALLCODERATES_SDHD = [0.7519, 0.7602, 0.7684, 0.7766, 0.7850, ... + 0.7932, 0.8014, 0.8098, 0.8180, 0.8262, ... + 0.8345, 0.8428, 0.8510, 0.8593, 0.8676, ... + 0.8733, 0.8790, 0.8848, 0.8905, 0.8962, ... + 0.9019, 0.9077, 0.9134, 0.9191, 0.9248, ... + 0.9306, 0.9363, 0.9420, 0.9477, 0.9535]; + NGMITHRESHOLDS_SDHD = [0.8116, 0.8167, 0.8241, 0.8317, 0.8401, ... + 0.8459, 0.8512, 0.8574, 0.8685, 0.8746, ... + 0.8829, 0.8892, 0.8958, 0.9022, 0.9090,... + 0.9150, 0.9210, 0.9270, 0.9330, 0.9390, ... + 0.9450, 0.9510, 0.9570, 0.9630, 0.9690, ... + 0.9750, 0.9810, 0.9870, 0.9930, 0.9990]; + + ISPUNCT_LDPI = [zeros(1,15),ones(1,15)]; + + %% Lookup Table for HD-only mode (using BER) + % For HD-only, the table gives the code rate and the maximum acceptable BER. + CODE_RATES_HD = [0.7500, 0.8000, 0.8123, 0.8333, 0.8571, ... + 0.8750, 0.8889, 0.9000, 0.9091, 0.9167, 0.9412]; + BERTHRESHOLDS_HD = [2.12e-2, 1.76e-2, 1.62e-2, 1.44e-2, 1.25e-2, ... + 1.03e-2, 9.29e-3, 8.33e-3, 7.54e-3, 7.04e-3, 4.70e-3]; + + %% LUT for KP4-FEC and Inner Code https://grouper.ieee.org/groups/802/3/dj/public/23_03/patra_3dj_01b_2303.pdf + CODE_RATE_KP4_AND_INNER = [0.885799]; + BERTHRESHOLDS_KP4_AND_INNER = 4.85e-3; + + + + end + + methods + function netrates = calculateNetRate(obj, grossRate, varargin) + % calculatenetrate Calculate the net data rate(s) from measured data. + % + % netrates = tp.calculatenetrate(grossRate, 'BER', berValue, 'NGMI', ngmiValue) + % + % INPUTS: + % grossRate - (scalar or vector) gross data rate(s) [bits/s] + % + % Optional name/value pairs: + % 'BER' - (scalar or vector) measured bit error ratio(s) + % 'NGMI' - (scalar or vector) measured NGMI value(s) + % + % At least one of 'BER' or 'NGMI' must be provided. + % + % OUTPUT: + % netrates - a structure with the following fields (if available): + % .SDHD - for SD+HD concatenated (using NGMI) + % .SDHD_LDPC - for SD+HD with punctured LDPC (using NGMI) + % .HD - for HD-only (using BER) + % + % Each sub-structure contains fields: + % .CodeRate - the chosen overall code rate from the table (vector) + % .Threshold - the threshold value used from the table (vector) + % . - net rate computed as grossRate * CodeRate (vector) + + % Parse inputs. + p = inputParser; + addRequired(p, 'grossRate', @(x) isnumeric(x)); + addParameter(p, 'BER', [], @(x) isnumeric(x)); + addParameter(p, 'NGMI', [], @(x) isnumeric(x)); + parse(p, grossRate, varargin{:}); + + ber = p.Results.BER; + ngmi = p.Results.NGMI; + + if isempty(ber) && isempty(ngmi) + error('At least one of ''BER'' or ''NGMI'' must be provided.'); + end + + % Determine the number of measurements. + numMeasurements = max([numel(grossRate), numel(ngmi), numel(ber)]); + + % Broadcast scalars if needed. + if isscalar(grossRate) && numMeasurements > 1 + grossRate = repmat(grossRate, 1, numMeasurements); + elseif numel(grossRate) ~= numMeasurements + error('grossRate must be scalar or have %d elements.', numMeasurements); + end + + if ~isempty(ngmi) + if isscalar(ngmi) && numMeasurements > 1 + ngmi = repmat(ngmi, 1, numMeasurements); + elseif numel(ngmi) ~= numMeasurements + error('NGMI must be scalar or have %d elements.', numMeasurements); + end + end + + if ~isempty(ber) + if isscalar(ber) && numMeasurements > 1 + ber = repmat(ber, 1, numMeasurements); + elseif numel(ber) ~= numMeasurements + error('BER must be scalar or have %d elements.', numMeasurements); + end + end + + % Initialize the output structure. + netrates = struct; + if ~isempty(ngmi) + netrates.SDHD.GrossRate = NaN(1, numMeasurements); + netrates.SDHD.NetRate = NaN(1, numMeasurements); + netrates.SDHD.punctLDPI = NaN(1, numMeasurements); + netrates.SDHD.CodeRate = NaN(1, numMeasurements); + netrates.SDHD.Threshold = NaN(1, numMeasurements); + end + if ~isempty(ber) + netrates.HD.GrossRate = NaN(1, numMeasurements); + netrates.HD.NetRate = NaN(1, numMeasurements); + netrates.HD.CodeRate = NaN(1, numMeasurements); + netrates.HD.Threshold = NaN(1, numMeasurements); + + netrates.KP4_hamming.GrossRate = NaN(1, numMeasurements); + netrates.KP4_hamming.NetRate = NaN(1, numMeasurements); + netrates.KP4_hamming.CodeRate = NaN(1, numMeasurements); + netrates.KP4_hamming.Threshold = NaN(1, numMeasurements); + end + + % Process each measurement individually. + for i = 1:numMeasurements + + % --- NGMI-based modes --- + if ~isempty(ngmi) + % SD+HD concatenated mode. + idx = find(obj.NGMITHRESHOLDS_SDHD <= ngmi(i), 1, 'last'); + if ~isempty(idx) + codeRate = obj.OVERALLCODERATES_SDHD(idx); + netrates.SDHD.NetRate(i) = grossRate(i) * codeRate; + netrates.SDHD.GrossRate(i) = grossRate(i) ; + netrates.SDHD.CodeRate(i) = codeRate; + netrates.SDHD.Threshold(i) = obj.NGMITHRESHOLDS_SDHD(idx); + netrates.SDHD.punctLDPI(i) = obj.ISPUNCT_LDPI(idx); + end + + end + + % --- BER-based mode (HD-only) --- + if ~isempty(ber) + % Loop through the BER thresholds from the best (highest code rate) + % to the worst until the measured BER is acceptable. + idxBER = []; + for j = length(obj.BERTHRESHOLDS_HD):-1:1 + if ber(i) <= obj.BERTHRESHOLDS_HD(j) + idxBER = j; + break; + end + end + if ~isempty(idxBER) + codeRate = obj.CODE_RATES_HD(idxBER); + netrates.HD.NetRate(i) = grossRate(i) * codeRate; + netrates.HD.GrossRate(i) = grossRate(i) ; + netrates.HD.CodeRate(i) = codeRate; + netrates.HD.Threshold(i) = obj.BERTHRESHOLDS_HD(idxBER); + end + idxBER = []; + for j = length(obj.BERTHRESHOLDS_KP4_AND_INNER):-1:1 + if ber(i) <= obj.BERTHRESHOLDS_KP4_AND_INNER(j) + idxBER = j; + break; + end + end + if ~isempty(idxBER) + codeRate = obj.CODE_RATE_KP4_AND_INNER(idxBER); + netrates.KP4_hamming.NetRate(i) = grossRate(i) * codeRate; + netrates.KP4_hamming.GrossRate(i) = grossRate(i) ; + netrates.KP4_hamming.CodeRate(i) = codeRate; + netrates.KP4_hamming.Threshold(i) = obj.BERTHRESHOLDS_KP4_AND_INNER(idxBER); + end + + + end + + + end + end + end +end diff --git a/Classes/DataBaseHandler/DBHandler.m b/Classes/DataBaseHandler/DBHandler.m new file mode 100644 index 0000000..1495209 --- /dev/null +++ b/Classes/DataBaseHandler/DBHandler.m @@ -0,0 +1,660 @@ +classdef DBHandler < handle + % DBHANDLER Class to handle database queries + % This class provides methods to interact with an SQLite database, including + % inserting data, retrieving table names, and appending new rows. + + properties + conn % Database connection object + pathToDB % Path to the SQLite database + tableNames % Cell array containing names of all tables in the database + tables = struct(); % Structure containing MATLAB tables for each database table + distinctValues + end + + methods + function obj = DBHandler(options) + % DBHANDLER Constructor for the DBHandler class + % Initializes the database connection and retrieves table and field names. + % + % Usage: + % obj = DBHandler('pathToDB', 'path/to/database.db'); + + arguments + options.pathToDB = ""; % Default value for pathToDB if not provided + end + + % Assign values to class properties based on input arguments + fn = fieldnames(options); + for n = 1:numel(fn) + try + obj.(fn{n}) = options.(fn{n}); + end + end + + % Establish a connection to the SQLite database + try + obj.conn = sqlite(obj.pathToDB); + catch e + error('Failed to connect to the database: %s', e.message); + end + + if obj.dbIsHealthy + + obj.refresh(); + + else + error('DB seems to be corrupt') + end + + end + + + function obj = refresh(obj) + % Get table names and the first rows of each table to understand the structure + obj.getTableNames(); + obj.getTables(); + obj.getDistinctValues(); + end + + function obj = getTableNames(obj) + % Get all table names from the database + try + result = fetch(obj.conn, 'SELECT name FROM sqlite_master WHERE type="table"'); + obj.tableNames = result.name; + catch e + error('Failed to retrieve table names: %s', e.message); + end + end + + function obj = getTables(obj) + % Get a preview (first row) of each table to understand its structure + for i = 1:numel(obj.tableNames) + try + tableName = obj.tableNames{i}; + + results = fetch(obj.conn, sprintf('SELECT * FROM %s WHERE 1 = 2', tableName)); + % Matlab cant handle if there is a NULL in a returned + % datarow... therefore do not return a row using the + % above condition which is never true + % results = sqlread(obj.conn, tableName, MaxRows=1); + + for l = 1:numel(results.Properties.VariableNames) + varName = results.Properties.VariableNames{l}; + obj.tables.(tableName).(varName) = []; % Store the preview as a reference + end + + catch e + warning('Failed to read the table %s: %s', tableName, e.message); + end + end + end + + function obj = getDistinctValues(obj) + % getDistinctValues Retrieves distinct values for each relevant field in all tables + % excluding fields ending with "_id". Stores distinct values in the 'distinctValues' + % property. + + % Initialize a structure to store distinct values for each table + obj.distinctValues = struct(); + + % Iterate over each table in obj.tables + tableNames_ = fieldnames(obj.tables); + + for i = 1:numel(tableNames_) + tableName = tableNames_{i}; + + % Initialize a sub-struct to store distinct values for each field in the table + obj.distinctValues.(tableName) = struct(); + + % Get all fields of the current table + fieldNames = fieldnames(obj.tables.(tableName)); + + % Iterate over each field + for j = 1:numel(fieldNames) + fieldName = fieldNames{j}; + + % % Skip fields ending with '_id' as they don't contain useful distinct values + % if endsWith(fieldName, '_id') + % continue; + % end + + % Construct SQL to get distinct values for the current field + query = sprintf('SELECT DISTINCT %s FROM %s', fieldName, tableName); + + % Execute query and fetch distinct values + try + result = fetch(obj.conn, query); + + % Store the distinct values in the structure + if ~isempty(result) + distinctValues = table2array(result); + else + distinctValues = []; + end + + obj.distinctValues.(tableName).(fieldName) = distinctValues; + + catch e + % warning('Failed to retrieve distinct values for %s.%s: %s', tableName, fieldName, e.message); + obj.distinctValues.(tableName).(fieldName) = []; + end + end + end + + end + + function healthyDB = dbIsHealthy(obj) + healthyDB = false; + + num_runs = obj.fetch('SELECT COUNT(*) AS total_runs FROM Runs'); + + num_configs = obj.fetch('SELECT COUNT(*) AS total_configurations FROM Configurations'); + + num_meas = obj.fetch('SELECT COUNT(*) AS total_measurements FROM Measurements'); + + assert((num_runs{1,1}==num_configs{1,1})&&(num_configs{1,1}==num_meas{1,1}),'Different num of entries per table'); + + %Check for any duplicate paths + duplictae_raw = obj.fetch("SELECT COALESCE(Runs.rx_raw_path,'NaN') AS rx_raw_path, COUNT(*) AS occurrences FROM Runs GROUP BY rx_raw_path HAVING COUNT(*) > 1"); + duplictae_sync = obj.fetch("SELECT COALESCE(Runs.rx_sync_path,'NaN') AS rx_sync_path, COUNT(*) AS occurrences FROM Runs GROUP BY rx_sync_path HAVING COUNT(*) > 1"); + + if size(duplictae_raw,2) > 1 + for i = 1:size(duplictae_raw,1) + fprintf('Raw Rx Paths: Found %d duplictaes of %s \n',duplictae_raw.occurrences(i),duplictae_raw.rx_raw_path(i)); + end + end + healthyDB = true; + end + + + + function lastID = appendToTable(obj, tableName, newRow) + % appendToTable Appends a new row to the specified table + % + % Usage: + % appendToTable(tableName, newRow) + % + % Inputs: + % tableName: The name of the table to append data to. + % newRow: A MATLAB table or struct containing the new row to be appended. + + % Check if the table exists in the fetched tables + if ~isfield(obj.tables, tableName) + error('Table %s does not exist in the database or has not been fetched.', tableName); + end + + % Convert newRow to a table if it is a struct + if isstruct(newRow) + fields = fieldnames(newRow); + emptyFields = structfun(@isempty,newRow); + if sum(emptyFields)>0 + newRow.(fields{emptyFields==1}) = NaN; + disp(['In Table: ',tableName,': ',fields{emptyFields==1},' was empty, is now NaN ',newRow.(fields{emptyFields==1})]) + + end + newRow = struct2table(newRow); + end + + % Ensure the new row matches the structure of the existing table + existingTableStructure = obj.tables.(tableName); + + % Perform data type checks and conversions + for colName = newRow.Properties.VariableNames + % Extract the value and its intended column type + value = newRow.(colName{1}); + existingValue = existingTableStructure.(colName{1}); + + % If the value is a class object, convert it to JSON format + if isobject(value) && ~isdatetime(value) && ~isa(value,"string") + newRow.(colName{1}) = string(jsonencode(value)); + + % If the value is a character array, convert it to a string + elseif ischar(value) + newRow.(colName{1}) = string(value); + + end + + end + + % Append the new row to the database table + try + sqlwrite(obj.conn, tableName, newRow); + % disp(['Successfully appended new row to the table ', tableName]); + catch e + error('Failed to append to the table %s: %s', tableName, e.message); + end + + % Retrieve the measurement_id of the newly inserted row for linking other tables + result = fetch(obj.conn, 'SELECT last_insert_rowid()'); + lastID = result{1, 1}; % Access the value directly from the table + end + + function exists = checkIfRunExists(obj, table2check, column2check, value2check) + % checkIfRunExists Checks if a specific value exists in a specified column of a table + % + % Usage: + % exists = checkIfRunExists(table2check, column2check, value2check) + % + % Inputs: + % table2check: The name of the table to check for duplicates. + % column2check: The name of the column to check within the specified table. + % value2check: The value to check for in the specified column. + % + % Outputs: + % exists: Boolean indicating whether the value already exists in the table. + + % Ensure the specified table and column exist in the database + if ~isfield(obj.tables, table2check) + error('Table %s does not exist in the database.', table2check); + end + + % Ensure the specified column exists in the table structure + if ~isfield(obj.tables.(table2check), column2check) + error('Column %s does not exist in the table %s.', column2check, table2check); + end + + % Construct the query to check for the value in the specified column + query = sprintf('SELECT COUNT(*) FROM %s WHERE %s = "%s"', table2check, column2check, value2check); + + % Execute the query and pass the value2check to avoid SQL injection issues + try + result = fetch(obj.conn, query); + count = result{1, 1}; % Extract the count from the result + catch e + error('Failed to execute the duplicate check query: %s', e.message); + end + + % If count is greater than 0, then the value exists in the table + exists = count > 0; + + if exists + disp(['The value "', value2check, '" already exists in the column "', column2check, '" of the table "', table2check, '".']); + else + % disp(['The value "', value2check, '" does not exist in the column "', column2check, '" of the table "', table2check, '".']); + end + end + + function addBEREntry(obj, berValue, occurrence, runID, ffe, dfe, mlse, pf, eqType, ffe_order, dfe_order, len_tr, mu_ffe, mu_dfe, mu_dc, comment) + % addBEREntry Adds a BER entry linked to an existing or new Equalizer entry. + % Usage: + % addBEREntry(runID, eq, ffe, dfe, mlse, pf, eqType, ffe_order, dfe_order, len_tr, mu_ffe, mu_dfe, mu_dc, berValue, comment) + + if isempty(pf) + postfilter_taps = []; + else + postfilter_taps = pf.burg_coeff; + end + + % Create equalizer data struct for searching and adding if necessary + equalizerData = struct( ... + 'ffe', jsonencode(ffe), ... + 'dfe', jsonencode(dfe), ... + 'mlse', jsonencode(mlse), ... + 'pf', jsonencode(pf), ... + 'eq_type', string(eqType), ... + 'ffe_order', jsonencode(ffe_order), ... + 'dfe_order', jsonencode(dfe_order), ... + 'postfilter_taps',jsonencode(postfilter_taps),... + 'len_tr', len_tr, ... + 'mu_ffe', jsonencode(mu_ffe), ... + 'mu_dfe', mu_dfe, ... + 'mu_dc', mu_dc, ... + 'comment', comment ... + ); + + % Check if exact Equalizer and BER entries already exist in the DB ... + selectedFields = {'Runs.run_id','BERs.ber_id','Equalizer.eq_id','BERs.ber',['BERs.occurrence' ... + '']}; + filterParams = obj.tables; + filterParams.Equalizer = equalizerData; + [dataTable,sql_query] = obj.queryDB(filterParams, selectedFields); + + % get or insert Equalizer + if ~isempty(dataTable) + % Equalizer entry already exists, use the existing eq_id + cur_eq_id = dataTable.eq_id; + else + % Insert the new Equalizer entry + cur_eq_id = obj.appendToTable('Equalizer', equalizerData); + end + + % skip if already here or insert BER entry + if ~isempty(dataTable) + + % A BER entry with the same eq_id, run_id, and occurrence already exists + existingBERValue = dataTable.ber; + + % Compare the existing BER value with the new BER value + if existingBERValue == berValue + fprintf('The BER entry %.2e || -- eq_id: %d -- run_id: %d -- occurrence: %d already exists. \n',berValue, cur_eq_id, runID, occurrence); + else + fprintf('Already found BER for EQ: %.2e ~= %.2e || -- eq_id: %d -- run_id: %d -- occurrence: %d already exists.\n', berValue, existingBERValue, cur_eq_id, runID, occurrence); + end + + else + + % No such BER entry exists, insert the new BER entry + berData = struct( ... + 'run_id', runID, ... + 'eq_id', cur_eq_id, ... + 'ber', berValue, ... + 'occurrence', occurrence ... + ); + + obj.appendToTable('BERs', berData); + + end + + end + + + + function executeSQL(obj, query) + % This method executes an SQL statement using MATLAB's execute function. + execute(obj.conn, query); + end + + + function answer = fetch(obj,query) + answer = fetch(obj.conn,query); + end + + function [result,query] = queryDB(obj, filterParams, selectedFields) + % getPathsWithFlexibleFilter Retrieves values from Runs table with flexible filtering + % and lets the user select which fields to include in the SELECT statement. + % + % Usage: + % [rxRawPaths, filteredValues] = getPathsWithFlexibleFilter(filterParams) + % + % Inputs: + % filterParams: A structure containing the parameters with their values. + % If left empty, two popup windows will prompt the user for input. + % + % Outputs: + % result: table with sql return + % query: this was send to SQL DB + + arguments + obj + filterParams = []; + selectedFields = []; + end + + % Step 1: Prompt the user to input filter parameters if not provided + if isempty(filterParams) + filterParams = obj.promptFilterParameters(); + end + + % Step 2: Prompt the user to select fields to include in the SELECT statement + if isempty(selectedFields) + selectedFields = obj.promptSelectFields(); + else + if iscell(selectedFields) + + elseif isstruct(selectedFields) + + end + end + + % Step 3: Construct the SQL query based on the inputs + query = obj.constructSQLQuery(filterParams, selectedFields); + + % Step 4: Execute the query and handle results + result = obj.fetch(query); + end + + function query = constructSQLQuery(obj, filterParams, selectedFields) + % constructSQLQuery Constructs the SQL query based on filter parameters and selected fields. + + % Construct the SELECT clause dynamically based on user selection + selectClause = 'SELECT DISTINCT '; + for i = 1:numel(selectedFields) + fieldParts = strsplit(selectedFields{i}, '.'); + tableName = fieldParts{1}; + fieldName = fieldParts{2}; + + if isnumeric(obj.tables.(tableName).(fieldName)) + selectClause = [selectClause, 'COALESCE(', selectedFields{i}, ', ''NaN'') AS ', fieldName]; + else + selectClause = [selectClause, 'COALESCE(', selectedFields{i}, ', '''') AS ', fieldName]; + end + + if i < numel(selectedFields) + selectClause = [selectClause, ', ']; + else + selectClause = [selectClause, ' ']; + end + end + + % Construct the FROM and WHERE clause + baseQuery = [selectClause, 'FROM Runs ' ... + 'LEFT JOIN Configurations ON Runs.run_id = Configurations.run_id ' ... + 'LEFT JOIN Measurements ON Runs.run_id = Measurements.run_id ' ... + 'WHERE ']; + % 'LEFT JOIN BERs ON Runs.run_id = BERs.run_id ' ... + % 'LEFT JOIN Equalizer ON BERs.eq_id = Equalizer.eq_id ' ... + + + % Loop through each table in filterParams + filterClauses = []; + tableNames_ = fieldnames(filterParams); + + for t = 1:numel(tableNames_) + tableName = tableNames_{t}; + tableParams = filterParams.(tableName); + + % Loop through each parameter in the table + fieldNames = fieldnames(tableParams); + for i = 1:numel(fieldNames) + fieldName = fieldNames{i}; + value = tableParams.(fieldName); + + % Construct the full column name in the format "tableName.fieldName" + fullName = sprintf('%s.%s', tableName, fieldName); + + % Handle different types of values for SQL query construction + if isempty(value) + % Skip this parameter if it is empty (include all values) + continue; + elseif isnumeric(value) && isnan(value) + % If value is NaN, use IS NULL in SQL + filterClause = sprintf('%s IS NULL', fullName); + elseif isnumeric(value) && ~isEnumeration(value) + filterClause = sprintf('%s = %f', fullName, value); + elseif islogical(value) || (isnumeric(value) && ismember(value, [0, 1])) && ~isEnumeration(value) + filterClause = sprintf('%s = %d', fullName, value); + elseif ischar(value) || isstring(value) + filterClause = sprintf('%s = ''%s''', fullName, char(value)); %nicht nach string suchen sondern nach chararray -> 'bla' statt "bla" + elseif isEnumeration(value) + filterClause = sprintf('%s = ''%s''', fullName, value); + else + error('Unsupported data type for field "%s".', fullName); + end + + % Add the constructed filter clause to the list + filterClauses = [filterClauses, filterClause, ' AND ']; + end + end + + % Remove trailing ' AND ' from the filter clauses if any filters were added + if ~isempty(filterClauses) + filterClauses = filterClauses(1:end-5); + end + + % Construct the final SQL query + if isempty(filterClauses) + query = [selectClause, 'FROM Runs ' ... + 'LEFT JOIN Configurations ON Runs.run_id = Configurations.run_id ' ... + 'LEFT JOIN Measurements ON Runs.run_id = Measurements.run_id ' ... + 'LEFT JOIN BERs ON Runs.run_id = BERs.run_id']; + else + query = [baseQuery, filterClauses]; + end + + end + + + + function selectedFields = promptSelectFields(obj) + % promptSelectFields Prompts the user to select fields from multiple tables to include in the SELECT statement using settingsdlg. + + % Get all possible fields from all tables (excluding sqlite_sequence) + tableNames = fieldnames(obj.tables); + tableNames = setdiff(tableNames, {'sqlite_sequence'}); % Remove sqlite_sequence + + % Prepare the inputs for settingsdlg + promptSettings = {}; + allFieldsFullName = {}; + convertedFieldNames = {}; + + for i = 1:numel(tableNames) + tableFields = fieldnames(obj.tables.(tableNames{i})); + for j = 1:numel(tableFields) + fieldName = tableFields{j}; + fullName = sprintf('%s.%s', tableNames{i}, fieldName); + convertedName = strrep(fullName, '.', '_'); % Replace '.' with '_' + + allFieldsFullName{end + 1} = fullName; % Add full name to the list + convertedFieldNames{end + 1} = convertedName; % Store the converted name + + % Add the field name and checkbox setting to the prompt + promptSettings{end + 1} = {sprintf('Include %s', fullName), convertedName}; + promptSettings{end + 1} = false; % Default: not selected + end + end + + % Create the settings dialog + [settings, button] = settingsdlg(... + 'title', 'Select Fields for the SQL Query', ... + 'description', 'Check the boxes for the fields you want to include in the SELECT statement.', ... + promptSettings{:} ... + ); + + % If the user cancels, default to selecting all fields + if strcmp(button, 'cancel') + selectedFields = allFieldsFullName; + return; + end + + % Parse user input into selectedFields + selectedFields = {}; + for i = 1:numel(allFieldsFullName) + convertedName = convertedFieldNames{i}; + if isfield(settings, convertedName) && settings.(convertedName) % Add to selectedFields if the checkbox was selected + selectedFields{end + 1} = allFieldsFullName{i}; %#ok + end + end + + % If no fields are selected, default to selecting all fields + if isempty(selectedFields) + selectedFields = allFieldsFullName; + end + end + + function filterParams = promptFilterParameters(obj) + % promptFilterParameters Prompts the user to enter filter parameters using the settingsdlg framework. + + % Get all possible parameters from all tables (excluding sqlite_sequence) + tableNames_ = fieldnames(obj.tables); + tableNames_ = setdiff(tableNames_, {'sqlite_sequence'}); % Remove sqlite_sequence + + % Prepare the inputs for settingsdlg with sections and separators + promptSettings = {}; + allFieldsFullName = {}; + convertedFieldNames = {}; + + for i = 1:numel(tableNames_) + % Add a separator for each table section + promptSettings{end + 1} = 'separator'; + promptSettings{end + 1} = tableNames_{i}; + + % Get all fields from the current table + tableFields = fieldnames(obj.tables.(tableNames_{i})); + + % Prepare each field to be added to the dialog + for j = 1:numel(tableFields) + fieldName = tableFields{j}; + fullName = sprintf('%s.%s', tableNames_{i}, fieldName); + convertedName = strrep(fullName, '.', '_'); % Replace '.' with '_' + + % Skip fields that do not have distinct values stored + if ~isfield(obj.distinctValues.(tableNames_{i}), fieldName) + continue; + end + + % Get the distinct values for the field + distinctValues_ = obj.distinctValues.(tableNames_{i}).(fieldName); + + % Prepare distinct values for dropdown + if isempty(distinctValues_) + % If there are no distinct values, use only an "All" entry + distinctValues_ = {'All'}; + else + % Ensure distinctValues is a cell array of strings + if isnumeric(distinctValues_) + distinctValues_ = arrayfun(@(x) num2str(x), distinctValues_, 'UniformOutput', false); + elseif isstring(distinctValues_) + distinctValues_ = cellstr(distinctValues_); + elseif iscell(distinctValues_) && ~iscellstr(distinctValues_) + distinctValues_ = cellfun(@num2str, distinctValues_, 'UniformOutput', false); + end + + % Add an "All" option at the beginning of the distinct values list + distinctValues_ = [{'All'}; distinctValues_]; + end + + allFieldsFullName{end + 1} = fullName; % Add full name to the list + convertedFieldNames{end + 1} = convertedName; % Store the converted name + + % Add the field name and value setting to the prompt + promptSettings{end + 1} = {sprintf('%s', fullName), convertedName}; + promptSettings{end + 1} = distinctValues_; % Add distinct values as dropdown options + end + end + + % Create the settings dialog + [settings, button] = settingsdlg(... + 'title', 'Input Parameters for Filtering', ... + 'description', 'Enter the values for each field to filter. Select "All" to include all values.', ... + promptSettings{:} ... + ); + + % If the user cancels, return an empty struct + if strcmp(button, 'cancel') + filterParams = struct(); + return; + end + + % Parse user input into filterParams structure + filterParams = struct(); + + for i = 1:numel(allFieldsFullName) + value = settings.(convertedFieldNames{i}); + + % Split full name to get table and field names + fieldParts = strsplit(allFieldsFullName{i}, '.'); + tableName = fieldParts{1}; + fieldName = fieldParts{2}; + + % If the table does not exist in the filterParams struct, create it + if ~isfield(filterParams, tableName) + filterParams.(tableName) = struct(); + end + + % Assign values to the respective fields under each table + if strcmp(value, 'All') + filterParams.(tableName).(fieldName) = []; % Set to empty to include all values + elseif isnumeric(value) && isnan(value) + filterParams.(tableName).(fieldName) = NaN; % Use NaN to handle as NULL + else + filterParams.(tableName).(fieldName) = value; % Use the entered value + end + end + end + + + + + + end +end diff --git a/Classes/DataBaseHandler/copyStylingFrom.m b/Classes/DataBaseHandler/copyStylingFrom.m new file mode 100644 index 0000000..aaf110f --- /dev/null +++ b/Classes/DataBaseHandler/copyStylingFrom.m @@ -0,0 +1,76 @@ +function copyStylingFrom(figNumSource, figNumTgt) + % Get handles to the source and target figures + sourceFig = figure(figNumSource); + targetFig = figure(figNumTgt); + + % Get axes of source and target figures + sourceAxes = findall(sourceFig, 'type', 'axes'); + targetAxes = findall(targetFig, 'type', 'axes'); + + % Ensure the number of axes match + if length(sourceAxes) ~= length(targetAxes) + error('Number of axes in source and target figures must be the same.'); + end + + % Loop through each pair of axes and copy styling properties + for i = 1:length(sourceAxes) + copyAxesProperties(sourceAxes(i), targetAxes(i)); + end + + % Apply general figure properties if desired + targetFig.Color = sourceFig.Color; % Background color +end + +function copyAxesProperties(sourceAx, targetAx) + % List of properties to copy from source to target axes + propsToCopy = {'XColor', 'YColor', 'ZColor', 'FontSize', 'FontName', ... + 'GridColor', 'GridLineStyle', 'MinorGridColor', 'Box', ... + 'XGrid', 'YGrid', 'ZGrid', 'XMinorGrid', 'YMinorGrid', 'ZMinorGrid', ... + 'LineWidth', 'TitleFontSizeMultiplier', 'LabelFontSizeMultiplier'}; + + % Copy properties from source to target + for i = 1:length(propsToCopy) + try + targetAx.(propsToCopy{i}) = sourceAx.(propsToCopy{i}); + catch + % Skip property if it doesn't exist or can't be copied + end + end + + % Copy axis labels and titles + targetAx.Title.String = sourceAx.Title.String; + targetAx.XLabel.String = sourceAx.XLabel.String; + targetAx.YLabel.String = sourceAx.YLabel.String; + targetAx.ZLabel.String = sourceAx.ZLabel.String; + + % Copy children elements like lines, patches, etc. + sourceChildren = allchild(sourceAx); + targetChildren = allchild(targetAx); + + % Ensure the number of children elements match + if length(sourceChildren) ~= length(targetChildren) + warning('Number of elements in source and target axes differ. Styling may not be applied completely.'); + end + + % Copy properties of children (like lines, patches, etc.), except colors and legends + for i = 1:min(length(sourceChildren), length(targetChildren)) + copyObjectProperties(sourceChildren(i), targetChildren(i)); + end +end + +function copyObjectProperties(sourceObj, targetObj) + % List of common properties to copy for plot elements (lines, patches, etc.) + propsToCopy = {'LineStyle', 'LineWidth', 'Marker', 'MarkerSize', ... + 'MarkerEdgeColor', 'MarkerFaceColor', 'DisplayName'}; + + % Copy properties from source to target, excluding colors + for i = 1:length(propsToCopy) + try + if ~contains(propsToCopy{i}, 'Color') % Skip color properties + targetObj.(propsToCopy{i}) = sourceObj.(propsToCopy{i}); + end + catch + % Skip property if it doesn't exist or can't be copied + end + end +end diff --git a/Classes/Warehouse_class/classes/DataStorage.m b/Classes/Warehouse_class/classes/DataStorage.m index 06b77b9..434bb97 100644 --- a/Classes/Warehouse_class/classes/DataStorage.m +++ b/Classes/Warehouse_class/classes/DataStorage.m @@ -114,6 +114,12 @@ classdef DataStorage < handle end + function addValueToStorageByLinIdx(obj, valueToStore ,storageVarName, lin_idx) + + obj.sto.(storageVarName){lin_idx} = valueToStore; + + end + % Access Value(s) function value = getStoValue(obj,storageVarName, varargin) @@ -125,74 +131,79 @@ classdef DataStorage < handle lin_idx = obj.getIndicesByPhys(varargin); errcnt = 0; for i=1:numel(lin_idx) - - tmp = obj.sto.(storageVarName){lin_idx(i)}; - if ~isempty(tmp) - if isa(tmp,'Signal') || isa(tmp,'struct') || isa(tmp,'Exfo_laser') || isa(tmp,'DC_supply') + tmp = obj.sto.(storageVarName){lin_idx(i)}; + if ~isempty(tmp) + + if isa(tmp,'double') + value(i) = tmp ; + elseif isa(tmp,'Signal') || isa(tmp,'struct') || isa(tmp,'Exfo_laser') || isa(tmp,'DC_supply') + if i == 1 + value = {}; + end + value{i} = tmp ; + + elseif isa(tmp,'cell') + if isa(tmp{1},'Signal') + if i == 1 + value = {}; + end + value{i} = tmp{1} ; + else + value{i} = tmp{1} ; + end + + else + + try if i == 1 value = {}; end value{i} = tmp ; + catch + % value(i,:) = tmp(1:size(value,2)) ; - elseif isa(tmp,'cell') - if isa(tmp{1},'Signal') - if i == 1 - value = {}; - end - value{i} = tmp{1} ; - else - value{i} = tmp{1} ; - end + if size(value,2) < size(tmp,2) - else - - try + diff = size(tmp,2) - size(value,2); + value(:,end+1:end+diff) = NaN(size(value,1),diff); value(i,:) = tmp ; - catch - % value(i,:) = tmp(1:size(value,2)) ; - - if size(value,2) < size(tmp,2) - diff = size(tmp,2) - size(value,2); - value(:,end+1:end+diff) = NaN(size(value,1),diff); - value(i,:) = tmp ; + elseif size(value,2) > size(tmp,2) - elseif size(value,2) > size(tmp,2) - - diff = size(value,2) - size(tmp,2); - tmp(:,end+1:end+diff) = NaN(1,diff); - value(i,:) = tmp ; - - end + diff = size(value,2) - size(tmp,2); + tmp(:,end+1:end+diff) = NaN(1,diff); + value(i,:) = tmp ; end - - end - else - errcnt = errcnt+1; - if errcnt < 3 + end + + end + else + errcnt = errcnt+1; + + if errcnt < 3 %get back the n-dimensional subiondices... [sub{1:length(size(obj.sto.(storageVarName)))}] = ind2sub(size(obj.sto.(storageVarName)),lin_idx(i)); - %get back the physical representaion + %get back the physical representaion word = []; for phys_idx = 1:numel(obj.fn) parametername = obj.fn(phys_idx); word = [word,char(parametername),': ', num2str(obj.parameter.(parametername).getPhysForIndex(sub{phys_idx})),' ;']; end - % warning(['Requested Data is not in Warehouse ', word]); - elseif errcnt == 3 - % warning(['... ', word]); - end - - end - if errcnt > 2 - % warning([num2str(errcnt),' requested datapoint(s) not in warehouse.']); + % warning(['Requested Data is not in Warehouse ', word]); + elseif errcnt == 3 + % warning(['... ', word]); end - + end + if errcnt > 2 + % warning([num2str(errcnt),' requested datapoint(s) not in warehouse.']); + end + + end else error('Wrong Request using ExampleWarehouse.getStoValue(*parameter set*). Give me all the Parameters! Please!') @@ -256,7 +267,7 @@ classdef DataStorage < handle end - + % Mapping for single Index function idx = getIndexByPhys(obj,fieldname,phys) %map single phys to index @@ -264,7 +275,70 @@ classdef DataStorage < handle end - + + function [phys_indices,param_name] = getPhysIndicesByLinIndex(obj, lin_idx) + % Converts a linear index into the corresponding physical parameter values + % Inputs: + % - lin_idx: The linear index within the storage array + % Output: + % - phys_indices: A cell array containing the physical parameter values for each dimension + + % Initialize output cell array + phys_indices = cell(1, numel(obj.fn)); + + % Convert linear index to subscript indices + [subscripts{1:numel(obj.dim)}] = ind2sub(obj.dim, lin_idx); + + % Map subscripts to physical values for each parameter + for i = 1:numel(obj.fn) + param_name{i} = obj.fn(i); + phys_indices{i} = obj.parameter.(param_name{i}).getPhysForIndex(subscripts{i}); + end + end + + function [physStruct, stored_value] = getPhysAndValueByLinIndex(obj, storageVarName, lin_idx) + % Retrieves a structure with physical parameter values as fieldnames, + % their corresponding parameter names as values, and the stored value + % for a given linear index. + % Inputs: + % - storageVarName: Name of the storage variable in obj.sto + % - lin_idx: The linear index within the storage array + % Outputs: + % - physStruct: A structure with physical parameter values as fieldnames + % and parameter names as values + % - stored_value: The value stored at the given linear index in the + % specified storage variable + + % Initialize an empty structure + physStruct = struct(); + + % Convert linear index to subscript indices + [subscripts{1:numel(obj.dim)}] = ind2sub(obj.dim, lin_idx); + + % Map subscripts to physical values and parameter names for each dimension + for i = 1:numel(obj.fn) + param_name = obj.fn(i); + phys_value = obj.parameter.(param_name).getPhysForIndex(subscripts{i}); + + % Add to the structure with phys_value as the fieldname and param_name as the value + physStruct.(param_name) = phys_value; + end + + % Retrieve the stored value at the given linear index + stored_value = obj.sto.(storageVarName){lin_idx}; + end + + function num_elements = getLastLinIndice(obj) + % Returns all possible linear indices for the data structure + % Output: + % - lin_indices: A column vector containing all linear indices for the storage array + + % Calculate the total number of elements in the storage array + num_elements = prod(obj.dim); + end + + + end end diff --git a/Classes/Warehouse_class/classes/DataStorage2.m b/Classes/Warehouse_class/classes/DataStorage2.m deleted file mode 100644 index 018f51c..0000000 --- a/Classes/Warehouse_class/classes/DataStorage2.m +++ /dev/null @@ -1,114 +0,0 @@ -classdef DataStorage2 < handle - % DATASTORAGE: Stores data with physical parameter mappings - - properties - inputParams = struct; - parameter = struct; - fn = []; - dim = []; - sto = struct; - end - - methods - function obj = DataStorage2(inputParams) - % Constructor to initialize the DataStorage object - if nargin > 0 - obj.inputParams = inputParams; - obj.fn = string(fieldnames(inputParams)); - obj = obj.buildParameter(); - obj.dim = obj.getDimension(); - obj.sto = struct; - else - error('Input parameters are required.'); - end - - end - - function showInfo(obj) - % Displays information about the storage and its dimensions - disp("Data Structure with fields:"); - fprintf('%-12s | %-8s | %-12s\n', 'Name', 'Dimension', 'Physical Values'); - disp('-------------------------------------------------------'); - for i = 1:numel(obj.fn) - fprintf('%-12s | %-8d | %-12s\n', ... - char(obj.fn(i)), obj.dim(i), ... - strjoin(string(obj.parameter.(obj.fn(i)).values), ', ')); - end - disp('-------------------------------------------------------'); - end - - function dim = getDimension(obj) - % Get the dimensions based on the length of parameters - dim = zeros(1, numel(obj.fn)); - for p = 1:numel(obj.fn) - dim(p) = obj.parameter.(obj.fn(p)).length; - end - end - - function obj = buildParameter(obj) - % Build the Parameter objects for each input parameter - for p = 1:numel(obj.fn) - name = obj.fn(p); - values = obj.inputParams.(name); - obj.parameter.(name) = Parameter2(name, values); - end - end - - function addStorage(obj, varName) - % Create an empty storage for a specific variable name - obj.sto.(string(varName)) = cell(obj.dim); - end - - function addValueToStorage(obj, valueToStore, storageVarName, varargin) - % Add a value to the storage at the specified indices - if nargin - 3 == numel(obj.fn) - lin_idx = obj.getIndicesByPhys(varargin); - obj.sto.(storageVarName){lin_idx} = valueToStore; - else - error('Please provide all indices for the storage.'); - end - end - - function value = getStoValue(obj, storageVarName, varargin) - % Retrieve a value from storage based on physical parameters - if nargin - 2 == numel(obj.fn) - lin_idx = obj.getIndicesByPhys(varargin); - value = cell(1, numel(lin_idx)); - for i = 1:numel(lin_idx) - value{i} = obj.sto.(storageVarName){lin_idx(i)}; - end - value = value(~cellfun('isempty', value)); % Remove empty entries - else - error('Please provide all physical parameters.'); - end - end - - function lin_idx = getIndicesByPhys(obj, varargin) - % Unpack nested cell array if needed - if numel(varargin) == 1 && iscell(varargin{1}) - varargin = varargin{1}; % Unpack if single cell array is passed - end - - indices = cell(1, numel(obj.fn)); - - % Loop through each parameter (e.g., L, D) - for p = 1:numel(obj.fn) - % Unwrap if it's a cell - if iscell(varargin{p}) - physVal = varargin{p}{1}; % Extract scalar from cell - else - physVal = varargin{p}; % It's already a scalar - end - - paramName = obj.fn(p); % Get the parameter name (e.g., 'L' or 'D') - - % Call getIndexByPhys on the corresponding Parameter2 object - indices{p} = obj.parameter.(paramName).getIndexByPhys(physVal); - end - - % Convert subscript indices to a linear index - lin_idx = sub2ind(obj.dim, indices{:}); - end - - end -end diff --git a/Classes/Warehouse_class/classes/Parameter2.m b/Classes/Warehouse_class/classes/Parameter2.m deleted file mode 100644 index 84852ff..0000000 --- a/Classes/Warehouse_class/classes/Parameter2.m +++ /dev/null @@ -1,51 +0,0 @@ -classdef Parameter2 < handle - % PARAMETER2: Represents a physical parameter with mappings between values and indices - - properties - name - values - length - physToIndexMap % Rename this from 'getPhysForIndex' - indexToPhysMap % Rename this from 'getIndexForPhys' - end - - methods - function obj = Parameter2(name, values) - % Constructor to initialize the Parameter2 object - obj.name = name; - obj.values = values; - obj.length = numel(values); - - % Initialize the mappings - obj.physToIndexMap = containers.Map('KeyType', 'double', 'ValueType', 'any'); - obj.indexToPhysMap = containers.Map('KeyType', 'double', 'ValueType', 'any'); - obj = obj.buildMappings(); - end - - function obj = buildMappings(obj) - % Build mappings between physical values and indices - for idx = 1:obj.length - obj.indexToPhysMap(idx) = obj.values(idx); - obj.physToIndexMap(obj.values(idx)) = idx; - end - end - - function physVal = getPhysForIndex(obj, idx) - % Return the physical value corresponding to the index - if isKey(obj.indexToPhysMap, idx) - physVal = obj.indexToPhysMap(idx); - else - error('Index out of range for parameter %s', obj.name); - end - end - - function idx = getIndexByPhys(obj, physVal) - % Return the index corresponding to the physical value - if isKey(obj.physToIndexMap, physVal) - idx = obj.physToIndexMap(physVal); - else - error('Physical value %g not found in parameter %s', physVal, obj.name); - end - end - end -end diff --git a/Classes/Warehouse_class/classes/minimalExample_gen2.m b/Classes/Warehouse_class/classes/minimalExample_gen2.m deleted file mode 100644 index c348197..0000000 --- a/Classes/Warehouse_class/classes/minimalExample_gen2.m +++ /dev/null @@ -1,45 +0,0 @@ -% Define input parameters for the DataStorage2 -inputParams.L = [1, 2, 10, 80]; % Length in kilometers -inputParams.D = [16, 17, 18]; % Diameter in millimeters - -% Create a DataStorage2 instance with the input parameters -dataStorage = DataStorage2(inputParams); % Using DataStorage2 class - -% Display the current information about the data storage structure -dataStorage.showInfo(); - -% Add a storage variable named 'testStorage' -dataStorage.addStorage('testStorage'); - -% Add a value (e.g., 100) to the storage at specific physical parameter values -% For example, we store the value 100 at L = 10 km and D = 17 mm -dataStorage.addValueToStorage(100, 'testStorage', 10, 16); -dataStorage.addValueToStorage(100, 'testStorage', 10, 17); -dataStorage.addValueToStorage(100, 'testStorage', 10, 18); - -% Retrieve the value from the storage at the same physical parameter values -storedValue = dataStorage.getStoValue('testStorage', 10, 16:18); -disp('Retrieved value from storage:'); -disp(storedValue); - -% Retrieve another value at a non-existent location (L = 2 km, D = 8 mm) -% This will show how the function handles empty storage entries -nonExistentValue = dataStorage.getStoValue('testStorage', 2, 8); -disp('Retrieved value from empty location:'); -disp(nonExistentValue); - -% Use the internal mappings to check how physical values map to indices -% Get the linear index for physical values L = 10 km and D = 17 mm -lin_idx = dataStorage.getIndicesByPhys(10, 17); -disp('Linear index for L=10 km and D=17 mm:'); -disp(lin_idx); - -% Check the reverse mapping: physical value for index 2 of parameter L -physValForIndex = dataStorage.parameter.L.getPhysForIndex(2); -disp('Physical value for index 2 of parameter L:'); -disp(physValForIndex); - -% Check the mapping: index for physical value D = 21 mm -indexForPhys = dataStorage.parameter.D.getIndexByPhys(21); -disp('Index for physical value D=21 mm:'); -disp(indexForPhys); diff --git a/Classes/matlab.mat b/Classes/matlab.mat deleted file mode 100644 index e33da65..0000000 Binary files a/Classes/matlab.mat and /dev/null differ diff --git a/Datatypes/db_mode.m b/Datatypes/db_mode.m new file mode 100644 index 0000000..93421b9 --- /dev/null +++ b/Datatypes/db_mode.m @@ -0,0 +1,11 @@ +classdef db_mode < int32 + + enumeration + no_db (0) + db_precoded (1) %sequence is precoded + db_encoded (2) %sequence is precoded and encoded + db_emulate (3) %for eq'ing: emulate precode on sequence that was not precoded at tx + db_discard (4) %for eq'ing: discard precode on sequence that was precoded at tx + end + +end \ No newline at end of file diff --git a/Datatypes/equalizer_structure.m b/Datatypes/equalizer_structure.m new file mode 100644 index 0000000..263260b --- /dev/null +++ b/Datatypes/equalizer_structure.m @@ -0,0 +1,11 @@ +classdef equalizer_structure < int32 + + enumeration + ffe (0) + vnle (1) + vnle_pf_mlse (2) + db_precoded (3) + db_encoded (4) + end + +end \ No newline at end of file diff --git a/Datatypes/isEnumeration.m b/Datatypes/isEnumeration.m new file mode 100644 index 0000000..048b851 --- /dev/null +++ b/Datatypes/isEnumeration.m @@ -0,0 +1,11 @@ +function result = isEnumeration(value) + % isEnumeration Checks if a given value is an instance of an enumeration class + % Usage: + % result = isEnumeration(value); + + % Get meta information about the class of the value + metaInfo = metaclass(value); + + % Check if the meta information indicates an enumeration class + result = metaInfo.Enumeration; +end \ No newline at end of file diff --git a/Functions/EQ_structures/duobinary_signaling.m b/Functions/EQ_structures/duobinary_signaling.m new file mode 100644 index 0000000..73f131c --- /dev/null +++ b/Functions/EQ_structures/duobinary_signaling.m @@ -0,0 +1,18 @@ +function [eq_package] = duobinary_signaling(eq_, mlse_,M ,rx_signal, tx_symbols, tx_bits) + %Duobinary Signaling + + [eq_signal, eq_noise] = eq_.process(rx_signal,tx_symbols); + + eq_signal = mlse_.process(eq_signal); + + eq_signal = Duobinary().encode(eq_signal); + eq_signal = Duobinary().decode(eq_signal); + + % M = numel(unique(eq_signal.signal)); + rx_bits = PAMmapper(M,0).demap(eq_signal); + + [~,numErrors,ber,~] = calc_ber(rx_bits.signal,tx_bits.signal,"skip_front",100,"skip_end",150,"returnErrorLocation",1); + + eq_package.ber = ber; + +end \ No newline at end of file diff --git a/Functions/EQ_structures/duobinary_target.m b/Functions/EQ_structures/duobinary_target.m new file mode 100644 index 0000000..c2d760e --- /dev/null +++ b/Functions/EQ_structures/duobinary_target.m @@ -0,0 +1,77 @@ +function [eq_package] = duobinary_target(eq_, mlse_,M, rx_signal, tx_symbols, tx_bits, options) + +arguments + eq_ + mlse_ + M + rx_signal + tx_symbols + tx_bits + options.precode_mode db_mode + options.showAnalysis = 0; +end + + %Duobinary Targeting + + [eq_signal, eq_noise] = eq_.process(rx_signal,Duobinary().encode(tx_symbols)); + + % dir = [1,1]; + mlse_sig_sd = mlse_.process(eq_signal); + + mlse_sig_hd = PAMmapper(M,0).quantize(mlse_sig_sd); + + % 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) + + % takes: + % -> eq_signal_hd: hard decision signal after eq + % -> tx_symbols: that where used as reference for eq + + switch options.precode_mode + case db_mode.db_emulate + + mlse_sig_hd = Duobinary().encode(mlse_sig_hd,"M",M); + mlse_sig_hd = Duobinary().decode(mlse_sig_hd,"M",M); + + tx_symbols_precoded = Duobinary().encode(tx_symbols); + tx_symbols_precoded = Duobinary().decode(tx_symbols_precoded); + + tx_bits = PAMmapper(M,0).demap(tx_symbols_precoded); + + case db_mode.db_discard + + % normal dsp for precoded sequence == discard/omit/ignore precode + tx_bits = PAMmapper(M,0).demap(tx_symbols); + + case db_mode.db_encoded + + % normal DB encoded data (only for 10KM) + + case db_mode.db_precoded + + mlse_sig_hd = Duobinary().encode(mlse_sig_hd,"M",M); + mlse_sig_hd = Duobinary().decode(mlse_sig_hd,"M",M); + + end + + % M = numel(unique(tx_symbols.signal)); + rx_bits = PAMmapper(M,0).demap(mlse_sig_hd); + + [~,numErrors,ber,~] = calc_ber(rx_bits.signal,tx_bits.signal,"skip_front",100,"skip_end",150,"returnErrorLocation",1); + + + eq_package.ber = ber; + + if options.showAnalysis + eq_noise = eq_noise - mean(eq_noise.signal); + +rx_signal.spectrum("normalizeTo0dB",1,"fignum",250); + + showEQNoisePSD(eq_noise,"fignum",250,"displayname",'Duobinary Target Noise'); + + Duobinary().encode(tx_symbols).spectrum("normalizeTo0dB",1,"fignum",250); + end + + +end \ No newline at end of file diff --git a/Functions/EQ_structures/vnle.m b/Functions/EQ_structures/vnle.m new file mode 100644 index 0000000..ba705d7 --- /dev/null +++ b/Functions/EQ_structures/vnle.m @@ -0,0 +1,86 @@ +function [eq_package] = vnle(eq_,M,rx_signal,tx_symbols,tx_bits,options) + %VNLE Apply an equalization algorithm to the received signal and calculate BER + % This function takes an equalizer object, a received signal, and the + % transmitted symbols to apply equalization, map the received signal back to bits, + % and compute the bit error rate (BER). + % + % Inputs: + % EQ - Equalizer object that provides the equalization method + % rx_signal - Received signal that needs to be equalized + % tx_symbols - Transmitted symbols used as a reference for BER calculation + % + % Outputs: + % eq_signal - Equalized version of the received signal + % ber - Bit error rate after equalization + % numErrors - Number of bit errors detected + + arguments + eq_ + M + rx_signal + tx_symbols + tx_bits + options.precode_mode db_mode + options.showAnalysis = 0 + end + + %FFE or VNLE + [eq_signal_sd,eq_noise] = eq_.process(rx_signal,tx_symbols); + + eq_signal_hd = PAMmapper(M,0).quantize(eq_signal_sd); + + % 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) + + % takes: + % -> eq_signal_hd: hard decision signal after eq + % -> tx_symbols: that where used as reference for eq + + switch options.precode_mode + case db_mode.db_emulate + % re + eq_signal_hd = Duobinary().encode(eq_signal_hd,"M",M); + eq_signal_hd = Duobinary().decode(eq_signal_hd,"M",M); + + tx_symbols_precoded = Duobinary().encode(tx_symbols); + tx_symbols_precoded = Duobinary().decode(tx_symbols_precoded); + + tx_bits = PAMmapper(M,0).demap(tx_symbols_precoded); + + case db_mode.db_discard + + % normal dsp for precoded sequence == discard/omit/ignore precode + tx_bits = PAMmapper(M,0).demap(tx_symbols); + + case db_mode.db_encoded + + % normal DB encoded data (only for 10KM) + + case db_mode.db_precoded + + eq_signal_hd = Duobinary().encode(eq_signal_hd,"M",M); + eq_signal_hd = Duobinary().decode(eq_signal_hd,"M",M); + + end + + rx_bits = PAMmapper(M,0).demap(eq_signal_hd); + + [~,numErrors,ber,~] = calc_ber(rx_bits.signal,tx_bits.signal,"skip_front",100,"skip_end",150,"returnErrorLocation",1); + [evm_total,evm_lvl] = calc_evm(eq_signal_sd,tx_symbols); + [inf_rate] = calc_air(eq_signal_sd,tx_symbols,"skip_front",10000,"skip_end",10000); + + eq_package.ber_vnle = ber; + eq_package.evm_total = evm_total; + eq_package.evm_lvl = evm_lvl; + eq_package.inf_rate_vnle = inf_rate; + + if options.showAnalysis + + fprintf(['VNLE EVM lvl: ',repmat('%.3f ',1,numel(evm_lvl)),' \n'],evm_lvl); + + fprintf('VNLE BER: %.2e \n',ber); + + end + +end \ No newline at end of file diff --git a/Functions/EQ_structures/vnle_postfilter_mlse.m b/Functions/EQ_structures/vnle_postfilter_mlse.m new file mode 100644 index 0000000..ac2493c --- /dev/null +++ b/Functions/EQ_structures/vnle_postfilter_mlse.m @@ -0,0 +1,125 @@ +function [eq_package] = vnle_postfilter_mlse(eq_,pf_,mlse_,M,rx_signal,tx_symbols,tx_bits,options) + +arguments + eq_ + pf_ + mlse_ + M + rx_signal + tx_symbols + tx_bits + options.precode_mode db_mode + options.showAnalysis = 0; +end + + %FFE or VNLE + [eq_signal_sd,eq_noise] = eq_.process(rx_signal,tx_symbols); + + eq_signal_hd = PAMmapper(M,0).quantize(eq_signal_sd); + + mlse_sig_sd = pf_.process(eq_signal_sd,eq_noise); + + mlse_.DIR = pf_.coefficients; + % [mlse_sig_hd,mlse_sig_sd] = mlse_.process(mlse_sig_sd,tx_symbols); + mlse_sig_sd = mlse_.process(mlse_sig_sd); + + mlse_sig_hd = PAMmapper(M,0).quantize(mlse_sig_sd); + + % 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) + + % takes: + % -> M + % -> eq_signal_hd: hard decision signal after eq + % -> tx_symbols: that where used as reference for eq + + switch options.precode_mode + case db_mode.db_emulate + % re + eq_signal_hd = Duobinary().encode(eq_signal_hd,"M",M); + eq_signal_hd = Duobinary().decode(eq_signal_hd,"M",M); + + mlse_sig_hd = Duobinary().encode(mlse_sig_hd,"M",M); + mlse_sig_hd = Duobinary().decode(mlse_sig_hd,"M",M); + + tx_symbols_precoded = Duobinary().encode(tx_symbols); + tx_symbols_precoded = Duobinary().decode(tx_symbols_precoded); + + tx_bits = PAMmapper(M,0).demap(tx_symbols_precoded); + + case db_mode.db_discard + + % normal dsp for precoded sequence == discard/omit/ignore precode + tx_bits = PAMmapper(M,0).demap(tx_symbols); + + case db_mode.db_encoded + + % normal DB encoded data (only for 10KM) + + case db_mode.db_precoded + + eq_signal_hd = Duobinary().encode(eq_signal_hd,"M",M); + eq_signal_hd = Duobinary().decode(eq_signal_hd,"M",M); + + mlse_sig_hd = Duobinary().encode(mlse_sig_hd,"M",M); + mlse_sig_hd = Duobinary().decode(mlse_sig_hd,"M",M); + + end + + % METRICS OF VNLE % + rx_bits_vnle = PAMmapper(M,0).demap(eq_signal_hd); + [~,~,ber_vnle,~] = calc_ber(rx_bits_vnle.signal,tx_bits.signal,"skip_front",100,"skip_end",150,"returnErrorLocation",1); + + % correct TUM implementation of AIR + [inf_rate_vnle] = calc_air(eq_signal_sd,tx_symbols,"skip_front",10000,"skip_end",10000); + [evm_vnle_total,evm_vnle_lvl] = calc_evm(eq_signal_sd,tx_symbols); + + % METRICS OF MLSE (HD-VITERBI) + rx_bits_mlse = PAMmapper(M,0).demap(mlse_sig_hd); + [~,~,ber_mlse,~] = calc_ber(rx_bits_mlse.signal,tx_bits.signal,"skip_front",100,"skip_end",150,"returnErrorLocation",1); + + + eq_package.ber_mlse = ber_mlse; + eq_package.ber_vnle = ber_vnle; + eq_package.evm_vnle_total = evm_vnle_total; + eq_package.evm_vnle_lvl = evm_vnle_lvl; + eq_package.air = inf_rate_vnle; + + eq_package.eq = eq_; + eq_package.pf = pf_; + eq_package.mlse = mlse_; + + + if options.showAnalysis + + % fprintf(['VNLE EVM lvl: ',repmat('%.3f ',1,numel(evm_lvl)),' \n'],evm_lvl); + + fprintf('VNLE BER: %.2e \n',ber_vnle); + + fprintf('MLSE BER: %.2e \n',ber_mlse); + + showEQNoisePSD(eq_noise,"fignum",336,"displayname",'VNLE+DFE','postfilter_taps',pf_.coefficients); + + + rx_signal.spectrum("normalizeTo0dB",1,"fignum",337,"displayname",'Rx Signal'); + + tx_symbols.spectrum("normalizeTo0dB",1,"fignum",337,'displayname','Tx Signal'); + + showLevelHistogram(eq_signal_sd,tx_symbols) + % showLevelHistogram(mlse_sig_sd,tx_symbols) + + showEQcoefficients(eq_.e,eq_.e2,eq_.e3,"displayname",'Coefficients'); + + showEQNoiseSNR(tx_symbols,eq_noise,"displayname",'vnle snr','fignum',101); + + %%% EQ SNR Spectrum %230 + %snr + snr_vnle = snr(tx_symbols.signal,eq_noise.signal); + + % showErrorBurstCount(eq_signal_sd,tx_symbols) + + + end + +end \ No newline at end of file diff --git a/Functions/EQ_visuals/analyzeEQperformance.m b/Functions/EQ_visuals/analyzeEQperformance.m new file mode 100644 index 0000000..0325fe0 --- /dev/null +++ b/Functions/EQ_visuals/analyzeEQperformance.m @@ -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 \ No newline at end of file diff --git a/Functions/EQ_visuals/showEQNoisePSD.m b/Functions/EQ_visuals/showEQNoisePSD.m new file mode 100644 index 0000000..51b12d7 --- /dev/null +++ b/Functions/EQ_visuals/showEQNoisePSD.m @@ -0,0 +1,44 @@ +function showEQNoisePSD(eq_noise, options) +arguments + eq_noise + options.postfilter_taps = NaN + options.fignum (1,1) double = NaN % Default to NaN if not provided + options.displayname (1,:) char = '' % Default to an empty string if not provided + options.color = [0.2157 0.4941 0.7216]; +end + + % Determine the figure number to use or create a new figure + if isnan(options.fignum) + fig = figure; % Create a new figure and get its handle + else + fig = figure(options.fignum); % Use the specified figure number + end + hold on + ax = gca; + % N = numel(ax.Children); + N = sum(arrayfun(@(x) strcmp(x.LineStyle, '-'), ax.Children)); + cmap = linspecer(8); + options.color = cmap(mod(N, size(cmap, 1)) + 1, :); + + % Ensure the figure is ready before calling spectrum + eq_noise.spectrum("displayname", options.displayname, "fignum", fig.Number, "normalizeTo0dB", 1,"color",options.color); + title('Noise of soft decision signal (not MLSE)') + + if ~isnan(options.postfilter_taps) + % Hold on to the figure for further plotting + hold on; + + % Compute the frequency response of the postfilter + [h, w] = freqz(1, options.postfilter_taps, length(eq_noise), "whole", eq_noise.fs); + h = h / max(abs(h)); % Normalize the filter response + + % Adjust frequency axis to center at 0 + w_ = (w - eq_noise.fs / 2); + + % Plot the inverted postfilter response + plot(w_ * 1e-9, 20 * log10(fftshift(abs(h))), 'DisplayName', ['Burg Coeffs: ', num2str(round(options.postfilter_taps, 2)), ' '], 'LineWidth', 1,'Color',options.color,'LineStyle','--'); + + % Ensure a legend is displayed + legend('show'); + end +end diff --git a/Functions/EQ_visuals/showEQNoiseSNR.m b/Functions/EQ_visuals/showEQNoiseSNR.m new file mode 100644 index 0000000..8b517fd --- /dev/null +++ b/Functions/EQ_visuals/showEQNoiseSNR.m @@ -0,0 +1,70 @@ +function showEQNoiseSNR(tx_signal, rx_signal, options) +arguments + tx_signal + rx_signal + options.fs_tx + options.fs_rx + options.fignum (1,1) double = NaN % Default to NaN if not provided + options.displayname (1,:) char = '' % Default to an empty string if not provided + options.color = [0.2157 0.4941 0.7216]; +end + + % Determine the figure number to use or create a new figure + if isnan(options.fignum) + fig = figure; % Create a new figure and get its handle + else + fig = figure(options.fignum); % Use the specified figure number + end + + if isa(tx_signal,'Signal') + options.fs_tx = tx_signal.fs; + tx_signal = tx_signal.signal; + end + if isa(rx_signal,'Signal') + options.fs_rx = rx_signal.fs; + rx_signal = rx_signal.signal; + end + + + hold on + ax = gca; + + % N = numel(ax.Children); + N = sum(arrayfun(@(x) strcmp(x.LineStyle, '-'), ax.Children)); + cmap = linspecer(8); + options.color = cmap(mod(N, size(cmap, 1)) + 1, :); + + % Ensure the figure is ready before calling spectrum + title('SNR of received Signal') + + fft_length = 2^(nextpow2(length(tx_signal))-7); + + [s_lin,w] = pwelch(tx_signal,hanning(fft_length),fft_length/2,fft_length,options.fs_tx,"centered","psd","mean"); + [n_lin,w] = pwelch(rx_signal,hanning(fft_length),fft_length/2,fft_length,options.fs_rx,"centered","psd","mean"); + + w = w.*1e-9; + snr_dbm = 10*log10(s_lin./n_lin); + + % figure(231) + hold on + plot(w,snr_dbm,'DisplayName','SNR','LineWidth',0.5,'Color',options.color); + xlabel("Frequency in GHz"); + + edgetick = 2^(nextpow2(options.fs_tx*1e-9)); + ticks = -edgetick:16:edgetick; + xticks(ticks); + + [~,b]=min(abs((-edgetick:16:edgetick)-max(w))); + xlim([-ticks(b+1) ticks(b+1)]); + + max_snr = ceil(max(snr_dbm)/10)*10; + min_snr = floor(min(snr_dbm)/10)*10; + ylim([min_snr,max_snr]); + yticks(-200:10:100); + + grid on; grid minor; + legend('Interpreter','none'); + title('Noise of soft decision signal (not MLSE)'); + + +end diff --git a/Functions/EQ_visuals/showEQTimeSignal.m b/Functions/EQ_visuals/showEQTimeSignal.m new file mode 100644 index 0000000..52d01b3 --- /dev/null +++ b/Functions/EQ_visuals/showEQTimeSignal.m @@ -0,0 +1,54 @@ +function showEQTimeSignal(eq_signal,ref_symbols,options) + + arguments + eq_signal + ref_symbols + options.fignum (1,1) double = NaN % Default to NaN if not provided + options.displayname (1,:) char = '' % Default to an empty string if not provided + options.color = [0.2157 0.4941 0.7216]; + end + % Determine the figure number to use or create a new figure + if isnan(options.fignum) + fig = figure; % Create a new figure and get its handle + else + fig = figure(options.fignum); % Use the specified figure number + end + + + M = numel(unique(ref_symbols.signal)); + lvlcol = cbrewer2('Set1',M); + col = cbrewer2('paired',2); + + eq_decisions = PAMmapper(M,0).quantize(eq_signal); + rx_bits = PAMmapper(M,0).demap(eq_signal); + ref_bits = PAMmapper(M,0).demap(ref_symbols); + + %%% 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 + + [~,numerr,ber_sd,errpos] = calc_ber(rx_bits.signal,ref_bits.signal,"skip_front",100,"skip_end",150,"returnErrorLocation",1); + + %%% EQ Time Series %210 + eq_signal.plot("fignum",fig.Number,"displayname",'Equalized Signal','color',col(1,:),'clear',1); + hold on + + try + yline(PAMmapper(M,0).get_demodulation_thresholds,'HandleVisibility','off','LineStyle','--'); + + for c = 1:M + scatter(errpos./eq_signal.fs,received_sd(c,errpos),1,'x','MarkerEdgeColor',lvlcol(c,:),'LineWidth',2,'DisplayName',sprintf('Tx Lvl: %d',c)); + end + end + +end + diff --git a/Functions/EQ_visuals/showEQcoefficients.m b/Functions/EQ_visuals/showEQcoefficients.m new file mode 100644 index 0000000..3794212 --- /dev/null +++ b/Functions/EQ_visuals/showEQcoefficients.m @@ -0,0 +1,58 @@ +function showEQcoefficients(n1, n2, n3, options) + % Show filter coefficients as stem plot + % n1, n2, and n3 in different subplots + % Scale all y-axis to -1 and 1 + + arguments + n1 + n2 + n3 + options.fignum (1,1) double = NaN % Default to NaN if not provided + options.displayname (1,:) char = '' % Default to an empty string if not provided + options.color = [0.2157, 0.4941, 0.7216]; + options.clf = 0; % Clear figure before plotting new + end + + % Determine the figure number to use or create a new figure + if isnan(options.fignum) + fig = figure; % Create a new figure and get its handle + else + fig = figure(options.fignum); % Use the specified figure number + end + + if options.clf + clf(fig); % Clear the figure if requested + end + + hold on + ax = gca; + N = numel(ax.Children); + + % Set up a colormap for consistent coloring + cmap = linspecer(8); + options.color = cmap(mod(N, size(cmap, 1)) + 1, :); + + % Create subplots for n1, n2, n3 + for i = 1:3 + subplot(3, 1, i); + switch i + case 1 + stem(n1, 'Color', options.color, 'LineWidth', 1,'Marker','.','MarkerSize',10); + title(sprintf('1st order Filter Coefficients: %d',numel(n1))); + case 2 + stem(n2, 'Color', options.color, 'LineWidth', 1,'Marker','.','MarkerSize',10); + title(sprintf('2nd order Filter Coefficients: %d',numel(n2))); + case 3 + stem(n3, 'Color', options.color, 'LineWidth', 1,'Marker','.','MarkerSize',10); + title(sprintf('3rd order Filter Coefficients: %d',numel(n3))); + end + ylim([-1, 1]); % Scale y-axis to -1 and 1 + grid on; + grid minor + xlabel('Coefficient Index'); + ylabel('Amplitude'); + end + + % Ensure the layout is tight for better visibility + sgtitle('Filter Coefficients'); % Overall title +end \ No newline at end of file diff --git a/Functions/EQ_visuals/showErrorBurstCount.m b/Functions/EQ_visuals/showErrorBurstCount.m new file mode 100644 index 0000000..cb9e016 --- /dev/null +++ b/Functions/EQ_visuals/showErrorBurstCount.m @@ -0,0 +1,47 @@ +function showErrorBurstCount(eq_signal,ref_symbols,options) +arguments + eq_signal + ref_symbols + options.fignum (1,1) double = NaN % Default to NaN if not provided + options.displayname (1,:) char = '' % Default to an empty string if not provided +end + + % Determine the figure number to use or create a new figure + if isnan(options.fignum) + fig = figure; % Create a new figure and get its handle + else + fig = figure(options.fignum); % Use the specified figure number + end + + if numel(unique(eq_signal.signal)) > 20 + M = numel(unique(ref_symbols.signal)); + eq_signal = PAMmapper(M,0).quantize(eq_signal); + end + + diff_indices = eq_signal.signal == ref_symbols.signal; + + + % 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); + + + +end \ No newline at end of file diff --git a/Functions/EQ_visuals/showLevelConfusionMatrix.m b/Functions/EQ_visuals/showLevelConfusionMatrix.m new file mode 100644 index 0000000..61ea976 --- /dev/null +++ b/Functions/EQ_visuals/showLevelConfusionMatrix.m @@ -0,0 +1,27 @@ +function showLevelConfusionMatrix(decided_symbols,ref_symbols,options) +arguments + decided_symbols + ref_symbols + options.M = NaN + options.fignum (1,1) double = NaN % Default to NaN if not provided + options.displayname (1,:) char = '' % Default to an empty string if not provided +end + +% Determine the figure number to use or create a new figure +if isnan(options.fignum) + fig = figure; % Create a new figure and get its handle +else + fig = figure(options.fignum); % Use the specified figure number +end + +if length(unique(decided_symbols.signal))>20 + assert(~isnan(options.M),'Provide either decided symbol sequence or modulation order M (PAM-4 -> M=4)'); + decided_symbols = PAMmapper(options.M,0).quantize(decided_symbols); +end + +%%% Confusion Matrix +cm = confusionchart(ref_symbols.signal,decided_symbols.signal,'RowSummary','row-normalized','ColumnSummary','column-normalized','Title','Confusion Matrix','XLabel','Decisions','YLabel','Transmitted'); + + +end + diff --git a/Functions/EQ_visuals/showLevelHistogram.m b/Functions/EQ_visuals/showLevelHistogram.m new file mode 100644 index 0000000..40f31f4 --- /dev/null +++ b/Functions/EQ_visuals/showLevelHistogram.m @@ -0,0 +1,50 @@ +function showLevelHistogram(eq_signal,ref_symbols,options) +arguments + eq_signal + ref_symbols + options.fignum (1,1) double = NaN % Default to NaN if not provided + options.displayname (1,:) char = '' % Default to an empty string if not provided +end + + if isa(eq_signal,'Signal') + eq_signal = eq_signal.signal; + end + if isa(ref_symbols,'Signal') + ref_symbols = ref_symbols.signal; + end + + % Determine the figure number to use or create a new figure + if isnan(options.fignum) + fig = figure; % Create a new figure and get its handle + else + fig = figure(options.fignum); % Use the specified figure number + end + + %%% Separate Classes + constellation = unique(ref_symbols); + received_sd = 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==constellation(lvl)) = eq_signal(ref_symbols==constellation(lvl)); + end + + + + %%% FFE histogram + clf + for lvl = 1:numel(constellation) + intermediate = received_sd(lvl,:); + cnt(lvl) = round(numel(intermediate(~isnan(intermediate)))./length(eq_signal),3).*100; + hold on + histogram(received_sd(lvl,:),1000,"EdgeAlpha",0,'DisplayName',['Lvl ',num2str(lvl),' | ',num2str(cnt(lvl)),' %'],'FaceColor',lvlcol(lvl,:),'Normalization','pdf'); + end + legend + grid on + + + +end + diff --git a/Functions/holdAndShowValue.m b/Functions/Lab_helper/holdAndShowValue.m similarity index 100% rename from Functions/holdAndShowValue.m rename to Functions/Lab_helper/holdAndShowValue.m diff --git a/Functions/showCurrentMeasurement.m b/Functions/Lab_helper/showCurrentMeasurement.m similarity index 97% rename from Functions/showCurrentMeasurement.m rename to Functions/Lab_helper/showCurrentMeasurement.m index dc316f6..fb08670 100644 --- a/Functions/showCurrentMeasurement.m +++ b/Functions/Lab_helper/showCurrentMeasurement.m @@ -1,5 +1,8 @@ function showCurrentMeasurement(varargin) - % showCurrentMeasurement displays measurement data in a figure with variable names + + % USEFUL FOR LAB! + + % showCurrentMeasurement displays lab measurement data in a table figure with variable names % as column headers and values listed below. Calling the function multiple times % with the same variable names but different values adds more data points. % diff --git a/Functions/waitUntilClick.m b/Functions/Lab_helper/waitUntilClick.m similarity index 100% rename from Functions/waitUntilClick.m rename to Functions/Lab_helper/waitUntilClick.m diff --git a/Functions/Metrics/air_garcia_implementation.m b/Functions/Metrics/air_garcia_implementation.m new file mode 100644 index 0000000..c71a26a --- /dev/null +++ b/Functions/Metrics/air_garcia_implementation.m @@ -0,0 +1,156 @@ +function air = air_garcia_implementation(x,r,idx_tx,Px,M_training) + +MAX_MEMORY = 200e6; % maximum allowed size for a matrix + +if nargin == 3 + Px = []; + M_training = []; +end + +if nargin == 4 + M_training = []; +end + + +% if input is complex, separate into real and imaginary parts +if any(imag(x(:))~=0) || any(imag(r(:))~=0) + x = [real(x); imag(x)]; + r = [real(r); imag(r)]; +end + +D = size(x, 1); % D = 2 if complex x +N = size(x, 2); % number of constellation points +M = size(r, 2); % number of samples + +% set default training set size +if isempty(M_training) + M_training = ceil(0.3*M); +end + +M_testing = M - M_training; + +% Training: estimate parameters of the conditionally Gaussian model +% sort according to transmit index +[idx_tx_training, idx_sort] = sort(idx_tx(1:M_training)); +r_training = r(:, idx_sort); +i_bounds = zeros(1, N+1); + +% compute conditional means and covariance matrices +C_n = zeros(D, D, N); +det_n = zeros(1, N); + +for n=1:N + % find how many times x(:, n) was transmitted and update i_bounds + N_current_x = find(idx_tx_training((i_bounds(n)+1):end)==n, 1, 'last'); + if isempty(N_current_x), N_current_x=0; end + i_bounds(n+1) = i_bounds(n) + N_current_x; + + if N_current_x > 0 + % Compute mu_n=E[Y|X=x_n] according to Eq. (14) and store it in + % x(:, n) to save space + x(:, n) = sum(r_training(:, (i_bounds(n)+1):i_bounds(n+1)), 2)/(i_bounds(n+1)-i_bounds(n)); + + % compute C_n=cov[Y|X=x_n] according to Eq. (15) + r_meanfree = r_training(:, (i_bounds(n)+1):i_bounds(n+1)) - x(:, n); + C_n(:, :, n) = (r_meanfree*r_meanfree')/(i_bounds(n+1)-i_bounds(n)); + % store also the determinant of C(:, :, n) + det_n(n) = det(C_n(:, :, n)); + + % if the determinant is 0, or if the matrix is badly conditioned, + % regularize by adding a small identity matrix. Note that we do + % need the check for 0 determinant, in case a cloud has exactly 0 + % variance according to the training set + if det_n(n)==0 || cond(C_n(:, :, n))>1e16 + C_n(:, :, n) = C_n(:, :, n) + 5 * eps * eye(D); + det_n(n) = (5*eps)^D; + end + + end +end + +% uniform input pmf Px if not provided +if isempty(Px) + Px = repmat(1/N, [1, N]); +end + + +% extract testing set and sort it according to transmit index +[idx_tx_testing, idx_sort] = sort(idx_tx((M_training+1):M)); +r_testing = r(:, M_training+idx_sort); + +% computation of h(Y|X) +h_Y_X = 0; +i_bounds_testing = zeros(1, N+1); +% loop over constellation points to compute h(Y|X) +for n = 1:N + % find how many times x(:, n) was transmitted and update + % i_bounds_testing + N_current_x = find(idx_tx_testing((i_bounds_testing(n)+1):end)==n, 1, 'last'); + if isempty(N_current_x), N_current_x=0; end + i_bounds_testing(n+1) = i_bounds_testing(n) + N_current_x; + % add the corresponding contribution to the mutual information (two + % first lines of Eq. (17)). This, together with + % D/2*log2(2*pi) after the end of the loop, gives h(Y|X) + h_Y_X = h_Y_X + N_current_x * log2(det_n(n))/2+... + sum(sum(conj(r_testing(:, (i_bounds_testing(n)+1):i_bounds_testing(n+1))-x(:, n)).*(C_n(:, :, n)\(r_testing(:, (i_bounds_testing(n)+1):i_bounds_testing(n+1))-x(:, n)))))/2/log(2); + + +end +h_Y_X = D/2*log2(2*pi) + h_Y_X/M_testing; + +% When computing log(py), we might run out of memory. If necessary, we +% doe the computation in blocks +logpy = zeros(1, M_testing); +BLOCK_SIZE = floor(MAX_MEMORY/N); +N_blocks = ceil(M_testing/BLOCK_SIZE); + +% loop over blocks of symbols. This loop can be replaced by parfor to allow +% parallel computation +for i_block = 1:N_blocks + + logpy_cur = zeros(1, M_testing); + + % beginning of block + i_start = (i_block-1) * BLOCK_SIZE + 1; + % end of block + i_end = min(M_testing, i_block*BLOCK_SIZE); + % block size + current_block_size = i_end-i_start+1; + + % compute exponents of third line of (17) + exponents = zeros(N, current_block_size); + for n = 1:N + exponents(n, :) = -log(det_n(n))/2-real(sum(conj(r_testing(:, i_start:i_end)-x(:, n)).*(C_n(:, :, n)\(r_testing(:, i_start:i_end)-x(:, n))), 1))/2; + %sum über 2 einträge von r + end + + % compute third line of Eq. (17). Use a custom function + % that computes log(sum(exp(x))) avoiding overflow errors + logpy_cur(i_start:i_end) = math_logsumexp(log(Px(:))+exponents, 1); + logpy = logpy + logpy_cur; +end + +% output entropy h(Y) +h_Y = D/2*log2(2*pi) - mean(logpy)/log(2);%log basis change + +% compute mutual information +air = h_Y - h_Y_X; + + +end + + +function [y] = math_logsumexp(x, dim) +%[y] = math_logsumexp(x, dim) +% Computes log(sum(exp(x), dim)), avoiding overflow errors when one of the +% x is large. + +if nargin<2 || isempty(dim) + m = max(x); + y = m + log(sum(exp(x-m))); +else + m = max(x, [], dim); + y = m + log(sum(exp(x-m), dim)); +end +end + diff --git a/Functions/Metrics/calc_air.m b/Functions/Metrics/calc_air.m new file mode 100644 index 0000000..c42ab2f --- /dev/null +++ b/Functions/Metrics/calc_air.m @@ -0,0 +1,48 @@ +function [ach_inf_rate] = calc_air(test_signal,reference_signal,options) +% Calculation of AIR acc. to J. Kozesnik, „Numerically Computing Achievable Rates of Memoryless Channels“, Francisco Javier Garcıa-Gomez, doi: 10.1007/978-94-009-9857-5. +% Implementation is not accessible, I mailed TUM to get the code... + +arguments(Input) + test_signal; + reference_signal; + options.skip_front = 0; + options.skip_end = 0; + options.returnErrorLocation = 0; +end + +options.skip_end = abs(options.skip_end); +options.skip_front = abs(options.skip_front); + +assert((options.skip_end+options.skip_front)', '<', 'p', 'h'}; % Define marker styles + num_markers = length(markers); + + for i = 1:length(lines) + lines(i).LineWidth = 1.3; % Thicker line width + %lines(i).LineStyle = '-'; % Solid lines for simplicity + lines(i).Marker = markers{mod(i-1, num_markers) + 1}; % Assign markers cyclically + lines(i).MarkerSize = 4; % Marker size + lines(i).MarkerFaceColor = 'auto'; % Use line color for marker face + end + + % Change all text interpreters to LaTeX + set(findall(gca, '-property', 'Interpreter'), 'Interpreter', 'latex'); + + % Set figure background to white + set(gcf, 'Color', 'w'); + + + % Set logarithmic scale for y-axis, but only if it makes sense. + % If this is not always desired, you could condition this on the presence of lines or data. + % set(gca, 'YScale', 'log'); + + % Customize grid and box appearance + set(gca, 'Box', 'on', 'LineWidth', 0.8); % Thicker border + grid on; + % grid minor; + + % Adjust font size and style for better readability + set(gca, 'FontSize', 10, 'FontName', 'Times New Roman'); +end diff --git a/Functions/calc_evm.m b/Functions/calc_evm.m deleted file mode 100644 index 9dfe591..0000000 --- a/Functions/calc_evm.m +++ /dev/null @@ -1,19 +0,0 @@ -function [evm,stdev] = calc_evm(vector_received,vector_ideal) - - error_vector = (vector_received-vector_ideal); - - k = unique(vector_ideal); - - error = repmat(zeros(size(vector_ideal)),1,length(k)); - - for lvl = 1:length(k) - error(vector_ideal==k(lvl),lvl) = error_vector(vector_ideal==k(lvl)); - end - - error(error==0) = NaN; - - stdev = std(error,"omitnan"); - - error = sqrt(error.^2); - evm = sqrt( 1/length(error) .* sum(error.^2,1,'omitnan') ) ; -end \ No newline at end of file diff --git a/Functions/channel_structures/awgn_channel.m b/Functions/channel_structures/awgn_channel.m new file mode 100644 index 0000000..6cf5580 --- /dev/null +++ b/Functions/channel_structures/awgn_channel.m @@ -0,0 +1,5 @@ +function signal_out = awgn_channel(signal_in) + + signal_out = signal_in; + +end \ No newline at end of file diff --git a/Functions/copyStylingFrom.m b/Functions/copyStylingFrom.m new file mode 100644 index 0000000..aaf110f --- /dev/null +++ b/Functions/copyStylingFrom.m @@ -0,0 +1,76 @@ +function copyStylingFrom(figNumSource, figNumTgt) + % Get handles to the source and target figures + sourceFig = figure(figNumSource); + targetFig = figure(figNumTgt); + + % Get axes of source and target figures + sourceAxes = findall(sourceFig, 'type', 'axes'); + targetAxes = findall(targetFig, 'type', 'axes'); + + % Ensure the number of axes match + if length(sourceAxes) ~= length(targetAxes) + error('Number of axes in source and target figures must be the same.'); + end + + % Loop through each pair of axes and copy styling properties + for i = 1:length(sourceAxes) + copyAxesProperties(sourceAxes(i), targetAxes(i)); + end + + % Apply general figure properties if desired + targetFig.Color = sourceFig.Color; % Background color +end + +function copyAxesProperties(sourceAx, targetAx) + % List of properties to copy from source to target axes + propsToCopy = {'XColor', 'YColor', 'ZColor', 'FontSize', 'FontName', ... + 'GridColor', 'GridLineStyle', 'MinorGridColor', 'Box', ... + 'XGrid', 'YGrid', 'ZGrid', 'XMinorGrid', 'YMinorGrid', 'ZMinorGrid', ... + 'LineWidth', 'TitleFontSizeMultiplier', 'LabelFontSizeMultiplier'}; + + % Copy properties from source to target + for i = 1:length(propsToCopy) + try + targetAx.(propsToCopy{i}) = sourceAx.(propsToCopy{i}); + catch + % Skip property if it doesn't exist or can't be copied + end + end + + % Copy axis labels and titles + targetAx.Title.String = sourceAx.Title.String; + targetAx.XLabel.String = sourceAx.XLabel.String; + targetAx.YLabel.String = sourceAx.YLabel.String; + targetAx.ZLabel.String = sourceAx.ZLabel.String; + + % Copy children elements like lines, patches, etc. + sourceChildren = allchild(sourceAx); + targetChildren = allchild(targetAx); + + % Ensure the number of children elements match + if length(sourceChildren) ~= length(targetChildren) + warning('Number of elements in source and target axes differ. Styling may not be applied completely.'); + end + + % Copy properties of children (like lines, patches, etc.), except colors and legends + for i = 1:min(length(sourceChildren), length(targetChildren)) + copyObjectProperties(sourceChildren(i), targetChildren(i)); + end +end + +function copyObjectProperties(sourceObj, targetObj) + % List of common properties to copy for plot elements (lines, patches, etc.) + propsToCopy = {'LineStyle', 'LineWidth', 'Marker', 'MarkerSize', ... + 'MarkerEdgeColor', 'MarkerFaceColor', 'DisplayName'}; + + % Copy properties from source to target, excluding colors + for i = 1:length(propsToCopy) + try + if ~contains(propsToCopy{i}, 'Color') % Skip color properties + targetObj.(propsToCopy{i}) = sourceObj.(propsToCopy{i}); + end + catch + % Skip property if it doesn't exist or can't be copied + end + end +end diff --git a/Functions/helper_functions_community/cbrewer2/cbrewer2.m b/Functions/helper_functions_community/cbrewer2/cbrewer2.m deleted file mode 100644 index dcdc2ec..0000000 --- a/Functions/helper_functions_community/cbrewer2/cbrewer2.m +++ /dev/null @@ -1,260 +0,0 @@ -%CBREWER2 Interpolated versions of Cynthia Brewer's ColorBrewer colormaps -% CBREWER2(CNAME, NCOL) returns the colour scheme CNAME with the number -% of colours equal to NCOL. If there is a ColorBrewer scheme with exactly -% this number of colours, the color scheme is returned as-is. If NCOL -% larger (or smaller) than the designed colormaps for this scheme, the -% largest (smallest) one is interpolated to provide enough colours, -% unless the requested colour scheme CNAME is a qualitative palette. For -% a qualitative scheme, the colours are repeated, cycling from the -% beginning again, to output the requested NCOL colours. -% -% CBREWER2(CNAME) without an NCOL input will use the same number of -% colours as the current colormap. -% -% CBREWER2(CNAME, NCOL, INTERP_METHOD) allows you to change the method -% used for the interpolation. The default is 'cubic'. -% -% CBREWER2(CNAME, NCOL, INTERP_METHOD, INTERP_SPACE) allows you to -% change the colorspace used for the interpolation. By default, this is -% in the CIELAB colorspace, which is approximately perceptually uniform. -% Options for INTERP_SPACE are -% 'rgb' : interpolation in sRGB (as used in original CBREWER) -% 'lab' : interpolation in CIELAB (default) -% 'lch' : interpolation in CIELCH_ab (not recommended due to the -% discontinuities at C=0 and H=0) -% Anything else supported by COLORSPACE will also function. -% -% The input format CBREWER2(TYPE, ...) can also be used, where TYPE is -% one of 'seq', 'div', 'qual'. This input is redandant and will be -% ignored. This input format is provided for backwards compatibility with -% the original CBREWER. -% -% Example 1 (sequential heatmap): -% C = [0 2 4 6; 8 10 12 14; 16 18 20 22]; -% imagesc(C); -% colorbar; -% colormap(cbrewer('YlOrRd', 256); -% -% Example 2 (line plot): -% x = 0:0.01:2; -% sc = [0.5; 1; 2]; -% t0 = [0; 0.2; 0.4]; -% t = bsxfun(@rdivide, bsxfun(@plus, x, t0), sc); -% y = sin(t * 2 * pi); -% cmap = cbrewer2('Set1', numel(sc)); -% axes('ColorOrder', cmap, 'NextPlot', 'ReplaceChildren'); -% plot(x, y); -% -% Example 3 (divergent heatmap): -% [X,Y,Z] = peaks(30); -% surfc(X,Y,Z); -% colormap(cbrewer2('RdBu')); -% -% This product includes color specifications and designs developed by -% Cynthia Brewer (http://colorbrewer.org/). For more information on -% ColorBrewer, please visit http://colorbrewer.org/. -% -% CBREWER2 uses a cached copy of the Cynthia Brewer color schemes which -% was converted to .mat format by Charles Robert for use with CBREWER. -% CBREWER is available from the MATLAB FileExchange under the MIT license. -% -% See also CBREWER, BREWERMAP, COLORSPACE, INTERP1. - - -% Copyright (c) 2016 Scott Lowe -% -% Licensed under the Apache License, Version 2.0 (the "License"); -% you may not use this file except in compliance with the License. -% You may obtain a copy of the License at -% -% http://www.apache.org/licenses/LICENSE-2.0 -% -% Unless required by applicable law or agreed to in writing, software -% distributed under the License is distributed on an "AS IS" BASIS, -% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -% See the License for the specific language governing permissions and -% limitations under the License. - - -function colormap = cbrewer2(... - cname, ncol, interp_method, interp_space, varargin) - -% Definitions ------------------------------------------------------------- - -% List of all of Cynthia Brewer's colormaps and their types -% seq: sequential -% div: divergent -% qual: qualitative -cbdict = {... - 'Blues', 'seq'; ... - 'BuGn', 'seq'; ... - 'BuPu', 'seq'; ... - 'GnBu', 'seq'; ... - 'Greens', 'seq'; ... - 'Greys', 'seq'; ... - 'Oranges', 'seq'; ... - 'OrRd', 'seq'; ... - 'PuBu', 'seq'; ... - 'PuBuGn', 'seq'; ... - 'PuRd', 'seq'; ... - 'Purples', 'seq'; ... - 'RdPu', 'seq'; ... - 'Reds', 'seq'; ... - 'YlGn', 'seq'; ... - 'YlGnBu', 'seq'; ... - 'YlOrBr', 'seq'; ... - 'YlOrRd', 'seq'; ... - 'BrBG', 'div'; ... - 'PiYG', 'div'; ... - 'PRGn', 'div'; ... - 'PuOr', 'div'; ... - 'RdBu', 'div'; ... - 'RdGy', 'div'; ... - 'RdYlBu', 'div'; ... - 'RdYlGn', 'div'; ... - 'Spectral', 'div'; ... - 'Accent', 'qual'; ... - 'Dark2', 'qual'; ... - 'Paired', 'qual'; ... - 'Pastel1', 'qual'; ... - 'Pastel2', 'qual'; ... - 'Set1', 'qual'; ... - 'Set2', 'qual'; ... - 'Set3', 'qual'; ... - }; - - -% Input handling ---------------------------------------------------------- - -narginchk(1, 5); - -% Initialise variables if not supplied -if nargin<2 - ncol = []; -end -if nargin<3 - interp_method = []; -end -if nargin<4 - interp_space = []; -end -if nargin<5 - varargin = {[]}; -end - -% Check if the colormap type was unnecessarily input -types = unique(cbdict(:, 2)); -if nargin > 1 && ischar(cname) && ischar(ncol) - LI = ismember({cname ncol}, types); - if ~any(LI); error('Number of colors cannot be a string'); end; - if all(LI); error('Incorrect colormap name'); end; - if LI(1) - vgn = {cname; ncol; interp_method; interp_space}; - cname = vgn{2}; - ncol = vgn{3}; - interp_method = vgn{4}; - interp_space = varargin{1}; - ctype_input = vgn{1}; - elseif LI(2) - vgn = {cname; ncol; interp_method; interp_space}; - cname = vgn{1}; - ncol = vgn{3}; - interp_method = vgn{4}; - interp_space = varargin{1}; - ctype_input = vgn{2}; - end -else - ctype_input = ''; -end - -% Default values -if isempty(ncol) - % Number of colours in the colormap - ncol = size(get(gcf,'colormap'), 1); -end -if isempty(interp_method) - interp_method = 'pchip'; -end -if isempty(interp_space) - interp_space = 'lab'; -end - - -% Load colorbrewer data --------------------------------------------------- -Tmp = load('colorbrewer.mat'); -colorbrewer = Tmp.colorbrewer; - -[TF, idict] = ismember(lower(cname), lower(cbdict(:, 1))); - -if ~TF - error('%s is not a recognised Brewer colormap',cname); -end - -cname = cbdict{idict, 1}; -ctype = cbdict{idict, 2}; - -if (~isfield(colorbrewer.(ctype), cname)) - error('Colormap %s is not present in loaded data',cname); -end - - -% Main script ------------------------------------------------------------- - -if ncol > length(colorbrewer.(ctype).(cname)) - % If we specified too many colours, we take the maximum and interpolate - colormap = colorbrewer.(ctype).(cname){length(colorbrewer.(ctype).(cname))}; - colormap = colormap ./ 255; -elseif isempty(colorbrewer.(ctype).(cname){ncol}) - % If we specified too few colours, we take the minimum and interpolate - nmin = find(~cellfun(@isempty, colorbrewer.(ctype).(cname)), 1); - colormap = colorbrewer.(ctype).(cname){nmin}; - colormap = colormap./255; -else - % If we specified a number of colours in the pre-designed range, no - % need to interpolate - colormap = (colorbrewer.(ctype).(cname){ncol}) ./ 255; - return; -end - -% Don't interpolate if qualitative type -if strcmp(ctype,'qual') - if size(colormap, 1) >= ncol - colormap = colormap(1:ncol, :); - return; - end - warning('CBREWER2:QualTooManyColors', ... - ['Too many colors requested: cannot interpolate a qualitative' ... - ' colorscheme']); - % Cycle the colours from the beginning again, so we have enough to - % return - colormap = repmat(colormap, ceil(ncol / size(colormap, 1)), 1); - colormap = colormap(1:ncol, :); - return; -end - -% Make sure we have colorspace downloaded from the FEX -if ~strcmpi(interp_space, 'rgb') && ~exist('colorspace.m', 'file') - P = requireFEXpackage(28790); - if isempty(P); - error(... - ['You need to download COLORSPACE from the MATLAB FEX and' ... - ' add it to the MATLAB path.']); - end; -end - -% Move to perceptually uniform space -if ~strcmpi(interp_space,'rgb') - colormap = colorspace(['rgb->' interp_space], colormap); -end - -% Linearly interpolate -X = linspace(0, 1, size(colormap, 1)); -XI = linspace(0, 1, ncol); -colormap = interp1(X, colormap, XI, interp_method); - -% Move from perceptually uniform space back to sRGB -if ~strcmpi(interp_space,'rgb') - colormap = colorspace(['rgb<-' interp_space], colormap); -end - -end \ No newline at end of file diff --git a/Functions/helper_functions_community/cbrewer2/colorbrewer.mat b/Functions/helper_functions_community/cbrewer2/colorbrewer.mat deleted file mode 100644 index ec59ef4..0000000 Binary files a/Functions/helper_functions_community/cbrewer2/colorbrewer.mat and /dev/null differ diff --git a/Functions/helper_functions_community/cbrewer2/requireFEXpackage.m b/Functions/helper_functions_community/cbrewer2/requireFEXpackage.m deleted file mode 100644 index 86838cc..0000000 --- a/Functions/helper_functions_community/cbrewer2/requireFEXpackage.m +++ /dev/null @@ -1,194 +0,0 @@ -function AddedPath = requireFEXpackage(FEXSubmissionID) -%Function requireFEXpackage - -%installs Matlab Central File Exchange (FEX) submission -%with given ID into the directory chosen by the user. -%A new FEX submissions may use previous FEX submissions as its part. -%The function 'requireFEXpackage' helps in adding those previous -%submissions to the user's MATLAB installation. -% -%This function is a part of File Exchange submission 31069. -%Download the entire submission: -%http://www.mathworks.com/matlabcentral/fileexchange/31069 -% -% SYNTAX: -% AddedPath = requireFEXpackage(FEXSubmissionID) -% -% INPUT: -% ID of the required submission to File Exchange -% -% OUTPUT: -% the path to that submission added to the user's MATLAB path. -% -% HOW TO CALL: -% The command -% P = requireFEXpackage(8277) -% will download and install the package with ID 8277 -% (namely, nice 'fminsearchbnd' by John D'Errico) -% -% EXAMPLES -- HOW TO USE: -% -% EXAMPLE 1 (using 'exist' command): -% -% % first, somewhere in the very beginning of your code, -% % check if the function 'fminsearchbnd' from the FEX package 8277 -% % is on your MATLAB path, and if it is not there, -% % require the FEX package 8277: -% if ~(exist('fminsearchbnd', 'file') == 2) -% P = requireFEXpackage(8277); % fminsearchbnd is part of 8277 -% end -% -% % Then just use 'fminsearchbnd' where you need it: -% syms x -% RosenbrockBananaFunction = @(x) (1-x(1)).^2 + 100*(x(2)-x(1).^2).^2; -% x = fminsearchbnd(RosenbrockBananaFunction,[3 3]) - -% EXAMPLE 2 (using 'try-catch' command): -% -% syms x -% RosenbrockBananaFunction = @(x) (1-x(1)).^2+100*(x(2)-x(1).^2).^2; -% try -% % if function 'fminsearchbnd' already exists in your MATLAB -% % installation, just use it: -% x = fminsearchbnd(RosenbrockBananaFunction,[3 3]) -% catch -% % if function 'fminsearchbnd' is not present in your MATLAB -% % installation, first get the package 8277 (to which it belongs) -% % from the MATLAB Central File Exchange (FEX) -% P = requireFEXpackage(8277); % fminsearchbnd is part of 8277 -% % and then use that function: -% x = fminsearchbnd(RosenbrockBananaFunction,[3 3]) -% end -% -% -% NOTE: on Mac platform, the title of the dialog box for -% choosing the directory for installing the required FEX package -% is not shown; this is not a bug, this is how UIGETDIR works on Macs -- -% see the documentation for UIGETDIR -% http://www.mathworks.com/help/techdoc/ref/uigetdir.html -% -% (C) Igor Podlubny, 2011 - -% Copyright (c) 2011, Igor Podlubny -% All rights reserved. -% -% Redistribution and use in source and binary forms, with or without -% modification, are permitted provided that the following conditions are -% met: -% -% * Redistributions of source code must retain the above copyright -% notice, this list of conditions and the following disclaimer. -% * Redistributions in binary form must reproduce the above copyright -% notice, this list of conditions and the following disclaimer in -% the documentation and/or other materials provided with the distribution -% -% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -% AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -% IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -% ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE -% LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -% CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -% SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -% INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -% CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -% ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -% POSSIBILITY OF SUCH DAMAGE. - - -ID = num2str(FEXSubmissionID); - -% Ask user for the confirmation of the installation -% of the required FEX package -yes = ['YES, Install package ' ID]; -no = 'NO, do not install'; -userchoice = questdlg(['The Matlab function/toolbox, which you are running, ' ... - 'requires the presence of the package ' ID ... - ' from Matlab Central File Exchange.' ... - sprintf('\n\n') ... - 'Would you like to install the FEX package ' ID ' now?'] , ... - ['Required package ' ID], ... - yes, no, yes); - -% Handle response -switch userchoice - case yes, - install = 1; - case no, - install = 0; - otherwise, - install = 0; -end - - -if install == 1 - baseURL = 'http://www.mathworks.com/matlabcentral/fileexchange/'; - query = '?download=true'; - - location = uigetdir(pwd, ['Select the directory for installing the required FEX package' ID ]); - if location ~= 0 - % download package 'ID' from Matlab Central File Exchange - filetosave = [location filesep ID '.zip']; - FEXpackage = [baseURL ID query]; - [f,status] = urlwrite(FEXpackage,filetosave); - if status==0 - warndlg(['No connection to Matlab Central File Exchange,' ' or package ' ID ' does not exist.' ... - ' Package ' ID ' has not been installed. ' ... - ' Check you internet settings and the ID of the required package, and try again. '] , ... - ['No connection to Matlab Central File Exchange' ' or package ' ID ' does not exist'], ... - 'modal'); - AddedPath = ''; - return - end - % unzip the downloaded file to the subdirectory 'ID' - todir = [location filesep ID]; - % if the directory 'ID' doesn't exist at given location, create it - if ~(exist([location filesep ID], 'dir') == 7) - mkdir(location, ID); - end - try - unzip(filetosave, todir); - % after unzipping, delete the downloaded ZIP file - delete(filetosave); - % prepend the paths to the downloaded package to the MATLAB path - P = genpath([location filesep ID]); - path(P,path); - catch - % if the FEX package is not ZIP, then it is a single m-file - % just move the file to the ID directory - [pathstr, name, ext] = fileparts(filetosave); - movefile(filetosave, [todir filesep name '.m']); - P = genpath([location filesep ID]); - path(P,path); - end - else - P = ''; - end - - AddedPath = P; -else - AddedPath = ''; -end - - -if install == 1, - % Ask user about reviewing and saving the modified MATLAB path, - % and take him to PATHTOOL, if the user wants to save the modified path - yes = 'YES, I want to review and save the MATLAB path'; - no = 'NO, I don''t want to save the path permanently'; - userchoice = questdlg(['After adding the package ' ID ... - ' from Matlab Central File Exchange to your MATLAB installation,' ... - ' the MATLAB path has been modified accordingly. ', ... - 'Would you like to review and save the modified MATLAB path?'] , ... - 'Review and save the modified MATLAB path for future use?', ... - yes, no, yes); - - % Handle response - switch userchoice - case yes, - pathtool; - case no, - otherwise, - end -end - - - diff --git a/Functions/helper_functions_community/linspecer.m b/Functions/helper_functions_community/linspecer.m deleted file mode 100644 index 31c5e6e..0000000 --- a/Functions/helper_functions_community/linspecer.m +++ /dev/null @@ -1,261 +0,0 @@ -% function lineStyles = linspecer(N) -% This function creates an Nx3 array of N [R B G] colors -% These can be used to plot lots of lines with distinguishable and nice -% looking colors. -% -% lineStyles = linspecer(N); makes N colors for you to use: lineStyles(ii,:) -% -% colormap(linspecer); set your colormap to have easily distinguishable -% colors and a pleasing aesthetic -% -% lineStyles = linspecer(N,'qualitative'); forces the colors to all be distinguishable (up to 12) -% lineStyles = linspecer(N,'sequential'); forces the colors to vary along a spectrum -% -% % Examples demonstrating the colors. -% -% LINE COLORS -% N=6; -% X = linspace(0,pi*3,1000); -% Y = bsxfun(@(x,n)sin(x+2*n*pi/N), X.', 1:N); -% C = linspecer(N); -% axes('NextPlot','replacechildren', 'ColorOrder',C); -% plot(X,Y,'linewidth',5) -% ylim([-1.1 1.1]); -% -% SIMPLER LINE COLOR EXAMPLE -% N = 6; X = linspace(0,pi*3,1000); -% C = linspecer(N) -% hold off; -% for ii=1:N -% Y = sin(X+2*ii*pi/N); -% plot(X,Y,'color',C(ii,:),'linewidth',3); -% hold on; -% end -% -% COLORMAP EXAMPLE -% A = rand(15); -% figure; imagesc(A); % default colormap -% figure; imagesc(A); colormap(linspecer); % linspecer colormap -% -% See also NDHIST, NHIST, PLOT, COLORMAP, 43700-cubehelix-colormaps -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -% by Jonathan Lansey, March 2009-2013 Lansey at gmail.com % -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -% -%% credits and where the function came from -% The colors are largely taken from: -% http://colorbrewer2.org and Cynthia Brewer, Mark Harrower and The Pennsylvania State University -% -% -% She studied this from a phsychometric perspective and crafted the colors -% beautifully. -% -% I made choices from the many there to decide the nicest once for plotting -% lines in Matlab. I also made a small change to one of the colors I -% thought was a bit too bright. In addition some interpolation is going on -% for the sequential line styles. -% -% -%% - -function lineStyles=linspecer(N,varargin) - -if nargin==0 % return a colormap - lineStyles = linspecer(128); - return; -end - -if ischar(N) - lineStyles = linspecer(128,N); - return; -end - -if N<=0 % its empty, nothing else to do here - lineStyles=[]; - return; -end - -% interperet varagin -qualFlag = 0; -colorblindFlag = 0; - -if ~isempty(varargin)>0 % you set a parameter? - switch lower(varargin{1}) - case {'qualitative','qua'} - if N>12 % go home, you just can't get this. - warning('qualitiative is not possible for greater than 12 items, please reconsider'); - else - if N>9 - warning(['Default may be nicer for ' num2str(N) ' for clearer colors use: whitebg(''black''); ']); - end - end - qualFlag = 1; - case {'sequential','seq'} - lineStyles = colorm(N); - return; - case {'white','whitefade'} - lineStyles = whiteFade(N);return; - case 'red' - lineStyles = whiteFade(N,'red');return; - case 'blue' - lineStyles = whiteFade(N,'blue');return; - case 'green' - lineStyles = whiteFade(N,'green');return; - case {'gray','grey'} - lineStyles = whiteFade(N,'gray');return; - case {'colorblind'} - colorblindFlag = 1; - otherwise - warning(['parameter ''' varargin{1} ''' not recognized']); - end -end -% *.95 -% predefine some colormaps - set3 = colorBrew2mat({[141, 211, 199];[ 255, 237, 111];[ 190, 186, 218];[ 251, 128, 114];[ 128, 177, 211];[ 253, 180, 98];[ 179, 222, 105];[ 188, 128, 189];[ 217, 217, 217];[ 204, 235, 197];[ 252, 205, 229];[ 255, 255, 179]}'); -set1JL = brighten(colorBrew2mat({[228, 26, 28];[ 55, 126, 184]; [ 77, 175, 74];[ 255, 127, 0];[ 255, 237, 111]*.85;[ 166, 86, 40];[ 247, 129, 191];[ 153, 153, 153];[ 152, 78, 163]}')); -set1 = brighten(colorBrew2mat({[ 55, 126, 184]*.85;[228, 26, 28];[ 77, 175, 74];[ 255, 127, 0];[ 152, 78, 163]}),.8); - -% colorblindSet = {[215,25,28];[253,174,97];[171,217,233];[44,123,182]}; -colorblindSet = {[215,25,28];[253,174,97];[171,217,233]*.8;[44,123,182]*.8}; - -set3 = dim(set3,.93); - -if colorblindFlag - switch N - % sorry about this line folks. kind of legacy here because I used to - % use individual 1x3 cells instead of nx3 arrays - case 4 - lineStyles = colorBrew2mat(colorblindSet); - otherwise - colorblindFlag = false; - warning('sorry unsupported colorblind set for this number, using regular types'); - end -end -if ~colorblindFlag - switch N - case 1 - lineStyles = { [ 55, 126, 184]/255}; - case {2, 3, 4, 5 } - lineStyles = set1(1:N); - case {6 , 7, 8, 9} - lineStyles = set1JL(1:N)'; - case {10, 11, 12} - if qualFlag % force qualitative graphs - lineStyles = set3(1:N)'; - else % 10 is a good number to start with the sequential ones. - lineStyles = cmap2linspecer(colorm(N)); - end - otherwise % any old case where I need a quick job done. - lineStyles = cmap2linspecer(colorm(N)); - end -end -lineStyles = cell2mat(lineStyles); - -end - -% extra functions -function varIn = colorBrew2mat(varIn) -for ii=1:length(varIn) % just divide by 255 - varIn{ii}=varIn{ii}/255; -end -end - -function varIn = brighten(varIn,varargin) % increase the brightness - -if isempty(varargin), - frac = .9; -else - frac = varargin{1}; -end - -for ii=1:length(varIn) - varIn{ii}=varIn{ii}*frac+(1-frac); -end -end - -function varIn = dim(varIn,f) - for ii=1:length(varIn) - varIn{ii} = f*varIn{ii}; - end -end - -function vOut = cmap2linspecer(vIn) % changes the format from a double array to a cell array with the right format -vOut = cell(size(vIn,1),1); -for ii=1:size(vIn,1) - vOut{ii} = vIn(ii,:); -end -end -%% -% colorm returns a colormap which is really good for creating informative -% heatmap style figures. -% No particular color stands out and it doesn't do too badly for colorblind people either. -% It works by interpolating the data from the -% 'spectral' setting on http://colorbrewer2.org/ set to 11 colors -% It is modified a little to make the brightest yellow a little less bright. -function cmap = colorm(varargin) -n = 100; -if ~isempty(varargin) - n = varargin{1}; -end - -if n==1 - cmap = [0.2005 0.5593 0.7380]; - return; -end -if n==2 - cmap = [0.2005 0.5593 0.7380; - 0.9684 0.4799 0.2723]; - return; -end - -frac=.95; % Slight modification from colorbrewer here to make the yellows in the center just a bit darker -cmapp = [158, 1, 66; 213, 62, 79; 244, 109, 67; 253, 174, 97; 254, 224, 139; 255*frac, 255*frac, 191*frac; 230, 245, 152; 171, 221, 164; 102, 194, 165; 50, 136, 189; 94, 79, 162]; -x = linspace(1,n,size(cmapp,1)); -xi = 1:n; -cmap = zeros(n,3); -for ii=1:3 - cmap(:,ii) = pchip(x,cmapp(:,ii),xi); -end -cmap = flipud(cmap/255); -end - -function cmap = whiteFade(varargin) -n = 100; -if nargin>0 - n = varargin{1}; -end - -thisColor = 'blue'; - -if nargin>1 - thisColor = varargin{2}; -end -switch thisColor - case {'gray','grey'} - cmapp = [255,255,255;240,240,240;217,217,217;189,189,189;150,150,150;115,115,115;82,82,82;37,37,37;0,0,0]; - case 'green' - cmapp = [247,252,245;229,245,224;199,233,192;161,217,155;116,196,118;65,171,93;35,139,69;0,109,44;0,68,27]; - case 'blue' - cmapp = [247,251,255;222,235,247;198,219,239;158,202,225;107,174,214;66,146,198;33,113,181;8,81,156;8,48,107]; - case 'red' - cmapp = [255,245,240;254,224,210;252,187,161;252,146,114;251,106,74;239,59,44;203,24,29;165,15,21;103,0,13]; - otherwise - warning(['sorry your color argument ' thisColor ' was not recognized']); -end - -cmap = interpomap(n,cmapp); -end - -% Eat a approximate colormap, then interpolate the rest of it up. -function cmap = interpomap(n,cmapp) - x = linspace(1,n,size(cmapp,1)); - xi = 1:n; - cmap = zeros(n,3); - for ii=1:3 - cmap(:,ii) = pchip(x,cmapp(:,ii),xi); - end - cmap = (cmap/255); % flipud?? -end - - - diff --git a/Functions/removeDotsFromFileNames.m b/Functions/removeDotsFromFileNames.m new file mode 100644 index 0000000..6fc0754 --- /dev/null +++ b/Functions/removeDotsFromFileNames.m @@ -0,0 +1,47 @@ + + +folderPath = "/Volumes/NT-Labor/2024/sioe/High Speed Messungen Oktober/"; + +% Get list of all files in the folder and subfolders +fileList = dir(fullfile(folderPath, '**', '*')); + +% Loop through each file +for i = 1:length(fileList) + % Get the file name and path + oldFileName = fileList(i).name; + oldFilePath = fullfile(fileList(i).folder, oldFileName); + + % Skip if it’s a directory or hidden file + if fileList(i).isdir || startsWith(oldFileName, '.') + continue; + end + + ismat = strfind(oldFileName, '.mat'); + + if ismat + continue; + else + + % Find position of last dot (for file extension) + dotIndex = strfind(oldFileName, '.'); + + % Only proceed if there is more than one dot in the file name + if ~isempty(dotIndex) + + % Replace all dots in the "base name" with underscores + sanitizedBaseName = strrep(oldFileName, '.', '_'); + + % Create the new file name with the corrected extension + newFileName = [sanitizedBaseName, '.mat']; + + % Full path of the new file + newFilePath = fullfile(fileList(i).folder, newFileName); + + % Rename the file + movefile(oldFilePath, newFilePath); + fprintf('Renamed: %s -> %s\n', oldFilePath, newFilePath); + end + + end +end + diff --git a/Functions/helper_functions_community/Violinplot-Matlab-master/LICENSE b/Libs/Violinplot-Matlab-master/LICENSE similarity index 100% rename from Functions/helper_functions_community/Violinplot-Matlab-master/LICENSE rename to Libs/Violinplot-Matlab-master/LICENSE diff --git a/Functions/helper_functions_community/Violinplot-Matlab-master/README.md b/Libs/Violinplot-Matlab-master/README.md similarity index 100% rename from Functions/helper_functions_community/Violinplot-Matlab-master/README.md rename to Libs/Violinplot-Matlab-master/README.md diff --git a/Functions/helper_functions_community/Violinplot-Matlab-master/Violin.m b/Libs/Violinplot-Matlab-master/Violin.m similarity index 100% rename from Functions/helper_functions_community/Violinplot-Matlab-master/Violin.m rename to Libs/Violinplot-Matlab-master/Violin.m diff --git a/Functions/helper_functions_community/Violinplot-Matlab-master/example.png b/Libs/Violinplot-Matlab-master/example.png similarity index 100% rename from Functions/helper_functions_community/Violinplot-Matlab-master/example.png rename to Libs/Violinplot-Matlab-master/example.png diff --git a/Functions/helper_functions_community/Violinplot-Matlab-master/example2.png b/Libs/Violinplot-Matlab-master/example2.png similarity index 100% rename from Functions/helper_functions_community/Violinplot-Matlab-master/example2.png rename to Libs/Violinplot-Matlab-master/example2.png diff --git a/Functions/helper_functions_community/Violinplot-Matlab-master/test_cases/testviolinplot.m b/Libs/Violinplot-Matlab-master/test_cases/testviolinplot.m similarity index 100% rename from Functions/helper_functions_community/Violinplot-Matlab-master/test_cases/testviolinplot.m rename to Libs/Violinplot-Matlab-master/test_cases/testviolinplot.m diff --git a/Functions/helper_functions_community/Violinplot-Matlab-master/violinplot.m b/Libs/Violinplot-Matlab-master/violinplot.m similarity index 100% rename from Functions/helper_functions_community/Violinplot-Matlab-master/violinplot.m rename to Libs/Violinplot-Matlab-master/violinplot.m diff --git a/Functions/helper_functions_community/autoArrangeFigures.m b/Libs/autoArrangeFigures.m similarity index 100% rename from Functions/helper_functions_community/autoArrangeFigures.m rename to Libs/autoArrangeFigures.m diff --git a/Functions/helper_functions_community/boundedlines/.gitignore b/Libs/boundedlines/.gitignore similarity index 100% rename from Functions/helper_functions_community/boundedlines/.gitignore rename to Libs/boundedlines/.gitignore diff --git a/Functions/helper_functions_community/boundedlines/Inpaint_nans/.gitignore b/Libs/boundedlines/Inpaint_nans/.gitignore similarity index 100% rename from Functions/helper_functions_community/boundedlines/Inpaint_nans/.gitignore rename to Libs/boundedlines/Inpaint_nans/.gitignore diff --git a/Functions/helper_functions_community/boundedlines/Inpaint_nans/demo/html/inpaint_nans_demo.html b/Libs/boundedlines/Inpaint_nans/demo/html/inpaint_nans_demo.html similarity index 100% rename from Functions/helper_functions_community/boundedlines/Inpaint_nans/demo/html/inpaint_nans_demo.html rename to Libs/boundedlines/Inpaint_nans/demo/html/inpaint_nans_demo.html diff --git a/Functions/helper_functions_community/boundedlines/Inpaint_nans/demo/html/inpaint_nans_demo.png b/Libs/boundedlines/Inpaint_nans/demo/html/inpaint_nans_demo.png similarity index 100% rename from Functions/helper_functions_community/boundedlines/Inpaint_nans/demo/html/inpaint_nans_demo.png rename to Libs/boundedlines/Inpaint_nans/demo/html/inpaint_nans_demo.png diff --git a/Functions/helper_functions_community/boundedlines/Inpaint_nans/demo/html/inpaint_nans_demo_01.png b/Libs/boundedlines/Inpaint_nans/demo/html/inpaint_nans_demo_01.png similarity index 100% rename from Functions/helper_functions_community/boundedlines/Inpaint_nans/demo/html/inpaint_nans_demo_01.png rename to Libs/boundedlines/Inpaint_nans/demo/html/inpaint_nans_demo_01.png diff --git a/Functions/helper_functions_community/boundedlines/Inpaint_nans/demo/html/inpaint_nans_demo_02.png b/Libs/boundedlines/Inpaint_nans/demo/html/inpaint_nans_demo_02.png similarity index 100% rename from Functions/helper_functions_community/boundedlines/Inpaint_nans/demo/html/inpaint_nans_demo_02.png rename to Libs/boundedlines/Inpaint_nans/demo/html/inpaint_nans_demo_02.png diff --git a/Functions/helper_functions_community/boundedlines/Inpaint_nans/demo/html/inpaint_nans_demo_03.png b/Libs/boundedlines/Inpaint_nans/demo/html/inpaint_nans_demo_03.png similarity index 100% rename from Functions/helper_functions_community/boundedlines/Inpaint_nans/demo/html/inpaint_nans_demo_03.png rename to Libs/boundedlines/Inpaint_nans/demo/html/inpaint_nans_demo_03.png diff --git a/Functions/helper_functions_community/boundedlines/Inpaint_nans/demo/html/inpaint_nans_demo_04.png b/Libs/boundedlines/Inpaint_nans/demo/html/inpaint_nans_demo_04.png similarity index 100% rename from Functions/helper_functions_community/boundedlines/Inpaint_nans/demo/html/inpaint_nans_demo_04.png rename to Libs/boundedlines/Inpaint_nans/demo/html/inpaint_nans_demo_04.png diff --git a/Functions/helper_functions_community/boundedlines/Inpaint_nans/demo/html/inpaint_nans_demo_05.png b/Libs/boundedlines/Inpaint_nans/demo/html/inpaint_nans_demo_05.png similarity index 100% rename from Functions/helper_functions_community/boundedlines/Inpaint_nans/demo/html/inpaint_nans_demo_05.png rename to Libs/boundedlines/Inpaint_nans/demo/html/inpaint_nans_demo_05.png diff --git a/Functions/helper_functions_community/boundedlines/Inpaint_nans/demo/html/inpaint_nans_demo_06.png b/Libs/boundedlines/Inpaint_nans/demo/html/inpaint_nans_demo_06.png similarity index 100% rename from Functions/helper_functions_community/boundedlines/Inpaint_nans/demo/html/inpaint_nans_demo_06.png rename to Libs/boundedlines/Inpaint_nans/demo/html/inpaint_nans_demo_06.png diff --git a/Functions/helper_functions_community/boundedlines/Inpaint_nans/demo/inpaint_nans_demo_old.m b/Libs/boundedlines/Inpaint_nans/demo/inpaint_nans_demo_old.m similarity index 100% rename from Functions/helper_functions_community/boundedlines/Inpaint_nans/demo/inpaint_nans_demo_old.m rename to Libs/boundedlines/Inpaint_nans/demo/inpaint_nans_demo_old.m diff --git a/Functions/helper_functions_community/boundedlines/Inpaint_nans/doc/Nomination comments.rtf b/Libs/boundedlines/Inpaint_nans/doc/Nomination comments.rtf similarity index 100% rename from Functions/helper_functions_community/boundedlines/Inpaint_nans/doc/Nomination comments.rtf rename to Libs/boundedlines/Inpaint_nans/doc/Nomination comments.rtf diff --git a/Functions/helper_functions_community/boundedlines/Inpaint_nans/doc/methods_of_inpaint_nans.m b/Libs/boundedlines/Inpaint_nans/doc/methods_of_inpaint_nans.m similarity index 100% rename from Functions/helper_functions_community/boundedlines/Inpaint_nans/doc/methods_of_inpaint_nans.m rename to Libs/boundedlines/Inpaint_nans/doc/methods_of_inpaint_nans.m diff --git a/Functions/helper_functions_community/boundedlines/Inpaint_nans/garden50.jpg b/Libs/boundedlines/Inpaint_nans/garden50.jpg similarity index 100% rename from Functions/helper_functions_community/boundedlines/Inpaint_nans/garden50.jpg rename to Libs/boundedlines/Inpaint_nans/garden50.jpg diff --git a/Functions/helper_functions_community/boundedlines/Inpaint_nans/inpaint_nans.m b/Libs/boundedlines/Inpaint_nans/inpaint_nans.m similarity index 100% rename from Functions/helper_functions_community/boundedlines/Inpaint_nans/inpaint_nans.m rename to Libs/boundedlines/Inpaint_nans/inpaint_nans.m diff --git a/Functions/helper_functions_community/boundedlines/Inpaint_nans/inpaint_nans_bc.m b/Libs/boundedlines/Inpaint_nans/inpaint_nans_bc.m similarity index 100% rename from Functions/helper_functions_community/boundedlines/Inpaint_nans/inpaint_nans_bc.m rename to Libs/boundedlines/Inpaint_nans/inpaint_nans_bc.m diff --git a/Functions/helper_functions_community/boundedlines/Inpaint_nans/inpaint_nans_demo.m b/Libs/boundedlines/Inpaint_nans/inpaint_nans_demo.m similarity index 100% rename from Functions/helper_functions_community/boundedlines/Inpaint_nans/inpaint_nans_demo.m rename to Libs/boundedlines/Inpaint_nans/inpaint_nans_demo.m diff --git a/Functions/helper_functions_community/boundedlines/Inpaint_nans/license.txt b/Libs/boundedlines/Inpaint_nans/license.txt similarity index 100% rename from Functions/helper_functions_community/boundedlines/Inpaint_nans/license.txt rename to Libs/boundedlines/Inpaint_nans/license.txt diff --git a/Functions/helper_functions_community/boundedlines/Inpaint_nans/monet_adresse.jpg b/Libs/boundedlines/Inpaint_nans/monet_adresse.jpg similarity index 100% rename from Functions/helper_functions_community/boundedlines/Inpaint_nans/monet_adresse.jpg rename to Libs/boundedlines/Inpaint_nans/monet_adresse.jpg diff --git a/Functions/helper_functions_community/boundedlines/Inpaint_nans/test/test_main.m b/Libs/boundedlines/Inpaint_nans/test/test_main.m similarity index 100% rename from Functions/helper_functions_community/boundedlines/Inpaint_nans/test/test_main.m rename to Libs/boundedlines/Inpaint_nans/test/test_main.m diff --git a/Functions/helper_functions_community/boundedlines/LICENSE.txt b/Libs/boundedlines/LICENSE.txt similarity index 100% rename from Functions/helper_functions_community/boundedlines/LICENSE.txt rename to Libs/boundedlines/LICENSE.txt diff --git a/Functions/helper_functions_community/boundedlines/README.html b/Libs/boundedlines/README.html similarity index 100% rename from Functions/helper_functions_community/boundedlines/README.html rename to Libs/boundedlines/README.html diff --git a/Functions/helper_functions_community/boundedlines/README.m b/Libs/boundedlines/README.m similarity index 100% rename from Functions/helper_functions_community/boundedlines/README.m rename to Libs/boundedlines/README.m diff --git a/Functions/helper_functions_community/boundedlines/README.md b/Libs/boundedlines/README.md similarity index 100% rename from Functions/helper_functions_community/boundedlines/README.md rename to Libs/boundedlines/README.md diff --git a/Functions/helper_functions_community/boundedlines/boundedline/.gitignore b/Libs/boundedlines/boundedline/.gitignore similarity index 100% rename from Functions/helper_functions_community/boundedlines/boundedline/.gitignore rename to Libs/boundedlines/boundedline/.gitignore diff --git a/Functions/helper_functions_community/boundedlines/boundedline/boundedline.m b/Libs/boundedlines/boundedline/boundedline.m similarity index 100% rename from Functions/helper_functions_community/boundedlines/boundedline/boundedline.m rename to Libs/boundedlines/boundedline/boundedline.m diff --git a/Functions/helper_functions_community/boundedlines/boundedline/outlinebounds.m b/Libs/boundedlines/boundedline/outlinebounds.m similarity index 100% rename from Functions/helper_functions_community/boundedlines/boundedline/outlinebounds.m rename to Libs/boundedlines/boundedline/outlinebounds.m diff --git a/Functions/helper_functions_community/boundedlines/catuneven/.gitignore b/Libs/boundedlines/catuneven/.gitignore similarity index 100% rename from Functions/helper_functions_community/boundedlines/catuneven/.gitignore rename to Libs/boundedlines/catuneven/.gitignore diff --git a/Functions/helper_functions_community/boundedlines/catuneven/catuneven.m b/Libs/boundedlines/catuneven/catuneven.m similarity index 100% rename from Functions/helper_functions_community/boundedlines/catuneven/catuneven.m rename to Libs/boundedlines/catuneven/catuneven.m diff --git a/Functions/helper_functions_community/boundedlines/readmeExtras/README_01.png b/Libs/boundedlines/readmeExtras/README_01.png similarity index 100% rename from Functions/helper_functions_community/boundedlines/readmeExtras/README_01.png rename to Libs/boundedlines/readmeExtras/README_01.png diff --git a/Functions/helper_functions_community/boundedlines/readmeExtras/README_02.png b/Libs/boundedlines/readmeExtras/README_02.png similarity index 100% rename from Functions/helper_functions_community/boundedlines/readmeExtras/README_02.png rename to Libs/boundedlines/readmeExtras/README_02.png diff --git a/Functions/helper_functions_community/boundedlines/readmeExtras/README_03.png b/Libs/boundedlines/readmeExtras/README_03.png similarity index 100% rename from Functions/helper_functions_community/boundedlines/readmeExtras/README_03.png rename to Libs/boundedlines/readmeExtras/README_03.png diff --git a/Functions/helper_functions_community/boundedlines/readmeExtras/README_04.png b/Libs/boundedlines/readmeExtras/README_04.png similarity index 100% rename from Functions/helper_functions_community/boundedlines/readmeExtras/README_04.png rename to Libs/boundedlines/readmeExtras/README_04.png diff --git a/Functions/helper_functions_community/boundedlines/readmeExtras/README_05.png b/Libs/boundedlines/readmeExtras/README_05.png similarity index 100% rename from Functions/helper_functions_community/boundedlines/readmeExtras/README_05.png rename to Libs/boundedlines/readmeExtras/README_05.png diff --git a/Functions/helper_functions_community/boundedlines/readmeExtras/README_06.png b/Libs/boundedlines/readmeExtras/README_06.png similarity index 100% rename from Functions/helper_functions_community/boundedlines/readmeExtras/README_06.png rename to Libs/boundedlines/readmeExtras/README_06.png diff --git a/Functions/helper_functions_community/boundedlines/readmeExtras/README_07.png b/Libs/boundedlines/readmeExtras/README_07.png similarity index 100% rename from Functions/helper_functions_community/boundedlines/readmeExtras/README_07.png rename to Libs/boundedlines/readmeExtras/README_07.png diff --git a/Functions/helper_functions_community/boundedlines/readmeExtras/README_08.png b/Libs/boundedlines/readmeExtras/README_08.png similarity index 100% rename from Functions/helper_functions_community/boundedlines/readmeExtras/README_08.png rename to Libs/boundedlines/readmeExtras/README_08.png diff --git a/Functions/helper_functions_community/boundedlines/singlepatch/.gitignore b/Libs/boundedlines/singlepatch/.gitignore similarity index 100% rename from Functions/helper_functions_community/boundedlines/singlepatch/.gitignore rename to Libs/boundedlines/singlepatch/.gitignore diff --git a/Functions/helper_functions_community/boundedlines/singlepatch/singlepatch.m b/Libs/boundedlines/singlepatch/singlepatch.m similarity index 100% rename from Functions/helper_functions_community/boundedlines/singlepatch/singlepatch.m rename to Libs/boundedlines/singlepatch/singlepatch.m diff --git a/Functions/helper_functions_community/colorspace/colorspace.c b/Libs/colorspace/colorspace.c similarity index 100% rename from Functions/helper_functions_community/colorspace/colorspace.c rename to Libs/colorspace/colorspace.c diff --git a/Functions/helper_functions_community/colorspace/colorspace.h b/Libs/colorspace/colorspace.h similarity index 100% rename from Functions/helper_functions_community/colorspace/colorspace.h rename to Libs/colorspace/colorspace.h diff --git a/Functions/helper_functions_community/colorspace/colorspace.m b/Libs/colorspace/colorspace.m similarity index 100% rename from Functions/helper_functions_community/colorspace/colorspace.m rename to Libs/colorspace/colorspace.m diff --git a/Functions/helper_functions_community/mat2tikz/.gitignore b/Libs/mat2tikz/.gitignore similarity index 100% rename from Functions/helper_functions_community/mat2tikz/.gitignore rename to Libs/mat2tikz/.gitignore diff --git a/Functions/helper_functions_community/mat2tikz/.travis.yml b/Libs/mat2tikz/.travis.yml similarity index 100% rename from Functions/helper_functions_community/mat2tikz/.travis.yml rename to Libs/mat2tikz/.travis.yml diff --git a/Functions/helper_functions_community/mat2tikz/AUTHORS.md b/Libs/mat2tikz/AUTHORS.md similarity index 100% rename from Functions/helper_functions_community/mat2tikz/AUTHORS.md rename to Libs/mat2tikz/AUTHORS.md diff --git a/Functions/helper_functions_community/mat2tikz/CHANGELOG.md b/Libs/mat2tikz/CHANGELOG.md similarity index 100% rename from Functions/helper_functions_community/mat2tikz/CHANGELOG.md rename to Libs/mat2tikz/CHANGELOG.md diff --git a/Functions/helper_functions_community/mat2tikz/CONTRIBUTING.md b/Libs/mat2tikz/CONTRIBUTING.md similarity index 100% rename from Functions/helper_functions_community/mat2tikz/CONTRIBUTING.md rename to Libs/mat2tikz/CONTRIBUTING.md diff --git a/Functions/helper_functions_community/mat2tikz/LICENSE.md b/Libs/mat2tikz/LICENSE.md similarity index 100% rename from Functions/helper_functions_community/mat2tikz/LICENSE.md rename to Libs/mat2tikz/LICENSE.md diff --git a/Functions/helper_functions_community/mat2tikz/README.md b/Libs/mat2tikz/README.md similarity index 100% rename from Functions/helper_functions_community/mat2tikz/README.md rename to Libs/mat2tikz/README.md diff --git a/Functions/helper_functions_community/mat2tikz/logos/matlab2tikz.svg b/Libs/mat2tikz/logos/matlab2tikz.svg similarity index 100% rename from Functions/helper_functions_community/mat2tikz/logos/matlab2tikz.svg rename to Libs/mat2tikz/logos/matlab2tikz.svg diff --git a/Functions/helper_functions_community/mat2tikz/matlab2tikz.sublime-project b/Libs/mat2tikz/matlab2tikz.sublime-project similarity index 100% rename from Functions/helper_functions_community/mat2tikz/matlab2tikz.sublime-project rename to Libs/mat2tikz/matlab2tikz.sublime-project diff --git a/Functions/helper_functions_community/mat2tikz/runtests.sh b/Libs/mat2tikz/runtests.sh similarity index 100% rename from Functions/helper_functions_community/mat2tikz/runtests.sh rename to Libs/mat2tikz/runtests.sh diff --git a/Functions/helper_functions_community/mat2tikz/src/cleanfigure.m b/Libs/mat2tikz/src/cleanfigure.m similarity index 100% rename from Functions/helper_functions_community/mat2tikz/src/cleanfigure.m rename to Libs/mat2tikz/src/cleanfigure.m diff --git a/Functions/helper_functions_community/mat2tikz/src/dev/formatWhitespace.m b/Libs/mat2tikz/src/dev/formatWhitespace.m similarity index 100% rename from Functions/helper_functions_community/mat2tikz/src/dev/formatWhitespace.m rename to Libs/mat2tikz/src/dev/formatWhitespace.m diff --git a/Functions/helper_functions_community/mat2tikz/src/figure2dot.m b/Libs/mat2tikz/src/figure2dot.m similarity index 100% rename from Functions/helper_functions_community/mat2tikz/src/figure2dot.m rename to Libs/mat2tikz/src/figure2dot.m diff --git a/Functions/helper_functions_community/mat2tikz/src/m2tInputParser.m b/Libs/mat2tikz/src/m2tInputParser.m similarity index 100% rename from Functions/helper_functions_community/mat2tikz/src/m2tInputParser.m rename to Libs/mat2tikz/src/m2tInputParser.m diff --git a/Functions/helper_functions_community/mat2tikz/src/m2tcustom.m b/Libs/mat2tikz/src/m2tcustom.m similarity index 100% rename from Functions/helper_functions_community/mat2tikz/src/m2tcustom.m rename to Libs/mat2tikz/src/m2tcustom.m diff --git a/Functions/helper_functions_community/mat2tikz/src/matlab2tikz.m b/Libs/mat2tikz/src/matlab2tikz.m similarity index 100% rename from Functions/helper_functions_community/mat2tikz/src/matlab2tikz.m rename to Libs/mat2tikz/src/matlab2tikz.m diff --git a/Functions/helper_functions_community/mat2tikz/src/private/errorUnknownEnvironment.m b/Libs/mat2tikz/src/private/errorUnknownEnvironment.m similarity index 100% rename from Functions/helper_functions_community/mat2tikz/src/private/errorUnknownEnvironment.m rename to Libs/mat2tikz/src/private/errorUnknownEnvironment.m diff --git a/Functions/helper_functions_community/mat2tikz/src/private/getEnvironment.m b/Libs/mat2tikz/src/private/getEnvironment.m similarity index 100% rename from Functions/helper_functions_community/mat2tikz/src/private/getEnvironment.m rename to Libs/mat2tikz/src/private/getEnvironment.m diff --git a/Functions/helper_functions_community/mat2tikz/src/private/guitypes.m b/Libs/mat2tikz/src/private/guitypes.m similarity index 100% rename from Functions/helper_functions_community/mat2tikz/src/private/guitypes.m rename to Libs/mat2tikz/src/private/guitypes.m diff --git a/Functions/helper_functions_community/mat2tikz/src/private/isAxis3D.m b/Libs/mat2tikz/src/private/isAxis3D.m similarity index 100% rename from Functions/helper_functions_community/mat2tikz/src/private/isAxis3D.m rename to Libs/mat2tikz/src/private/isAxis3D.m diff --git a/Functions/helper_functions_community/mat2tikz/src/private/isVersionBelow.m b/Libs/mat2tikz/src/private/isVersionBelow.m similarity index 100% rename from Functions/helper_functions_community/mat2tikz/src/private/isVersionBelow.m rename to Libs/mat2tikz/src/private/isVersionBelow.m diff --git a/Functions/helper_functions_community/mat2tikz/src/private/m2tUpdater.m b/Libs/mat2tikz/src/private/m2tUpdater.m similarity index 100% rename from Functions/helper_functions_community/mat2tikz/src/private/m2tUpdater.m rename to Libs/mat2tikz/src/private/m2tUpdater.m diff --git a/Functions/helper_functions_community/mat2tikz/src/private/m2tstrjoin.m b/Libs/mat2tikz/src/private/m2tstrjoin.m similarity index 100% rename from Functions/helper_functions_community/mat2tikz/src/private/m2tstrjoin.m rename to Libs/mat2tikz/src/private/m2tstrjoin.m diff --git a/Functions/helper_functions_community/mat2tikz/src/private/versionArray.m b/Libs/mat2tikz/src/private/versionArray.m similarity index 100% rename from Functions/helper_functions_community/mat2tikz/src/private/versionArray.m rename to Libs/mat2tikz/src/private/versionArray.m diff --git a/Functions/helper_functions_community/mat2tikz/src/private/versionString.m b/Libs/mat2tikz/src/private/versionString.m similarity index 100% rename from Functions/helper_functions_community/mat2tikz/src/private/versionString.m rename to Libs/mat2tikz/src/private/versionString.m diff --git a/Functions/helper_functions_community/mat2tikz/test/README.md b/Libs/mat2tikz/test/README.md similarity index 100% rename from Functions/helper_functions_community/mat2tikz/test/README.md rename to Libs/mat2tikz/test/README.md diff --git a/Functions/helper_functions_community/mat2tikz/test/codeReport.m b/Libs/mat2tikz/test/codeReport.m similarity index 100% rename from Functions/helper_functions_community/mat2tikz/test/codeReport.m rename to Libs/mat2tikz/test/codeReport.m diff --git a/Functions/helper_functions_community/mat2tikz/test/compareTimings.m b/Libs/mat2tikz/test/compareTimings.m similarity index 100% rename from Functions/helper_functions_community/mat2tikz/test/compareTimings.m rename to Libs/mat2tikz/test/compareTimings.m diff --git a/Functions/helper_functions_community/mat2tikz/test/examples/example_bar_plot.m b/Libs/mat2tikz/test/examples/example_bar_plot.m similarity index 100% rename from Functions/helper_functions_community/mat2tikz/test/examples/example_bar_plot.m rename to Libs/mat2tikz/test/examples/example_bar_plot.m diff --git a/Functions/helper_functions_community/mat2tikz/test/examples/example_quivers.m b/Libs/mat2tikz/test/examples/example_quivers.m similarity index 100% rename from Functions/helper_functions_community/mat2tikz/test/examples/example_quivers.m rename to Libs/mat2tikz/test/examples/example_quivers.m diff --git a/Functions/helper_functions_community/mat2tikz/test/makeLatexReport.m b/Libs/mat2tikz/test/makeLatexReport.m similarity index 100% rename from Functions/helper_functions_community/mat2tikz/test/makeLatexReport.m rename to Libs/mat2tikz/test/makeLatexReport.m diff --git a/Functions/helper_functions_community/mat2tikz/test/makeTapReport.m b/Libs/mat2tikz/test/makeTapReport.m similarity index 100% rename from Functions/helper_functions_community/mat2tikz/test/makeTapReport.m rename to Libs/mat2tikz/test/makeTapReport.m diff --git a/Functions/helper_functions_community/mat2tikz/test/makeTravisReport.m b/Libs/mat2tikz/test/makeTravisReport.m similarity index 100% rename from Functions/helper_functions_community/mat2tikz/test/makeTravisReport.m rename to Libs/mat2tikz/test/makeTravisReport.m diff --git a/Functions/helper_functions_community/mat2tikz/test/output/.gitignore b/Libs/mat2tikz/test/output/.gitignore similarity index 100% rename from Functions/helper_functions_community/mat2tikz/test/output/.gitignore rename to Libs/mat2tikz/test/output/.gitignore diff --git a/Functions/helper_functions_community/mat2tikz/test/private/OSVersion.m b/Libs/mat2tikz/test/private/OSVersion.m similarity index 100% rename from Functions/helper_functions_community/mat2tikz/test/private/OSVersion.m rename to Libs/mat2tikz/test/private/OSVersion.m diff --git a/Functions/helper_functions_community/mat2tikz/test/private/StreamMaker.m b/Libs/mat2tikz/test/private/StreamMaker.m similarity index 100% rename from Functions/helper_functions_community/mat2tikz/test/private/StreamMaker.m rename to Libs/mat2tikz/test/private/StreamMaker.m diff --git a/Functions/helper_functions_community/mat2tikz/test/private/VersionControlIdentifier.m b/Libs/mat2tikz/test/private/VersionControlIdentifier.m similarity index 100% rename from Functions/helper_functions_community/mat2tikz/test/private/VersionControlIdentifier.m rename to Libs/mat2tikz/test/private/VersionControlIdentifier.m diff --git a/Functions/helper_functions_community/mat2tikz/test/private/calculateMD5Hash.m b/Libs/mat2tikz/test/private/calculateMD5Hash.m similarity index 100% rename from Functions/helper_functions_community/mat2tikz/test/private/calculateMD5Hash.m rename to Libs/mat2tikz/test/private/calculateMD5Hash.m diff --git a/Functions/helper_functions_community/mat2tikz/test/private/cleanFiles.m b/Libs/mat2tikz/test/private/cleanFiles.m similarity index 100% rename from Functions/helper_functions_community/mat2tikz/test/private/cleanFiles.m rename to Libs/mat2tikz/test/private/cleanFiles.m diff --git a/Functions/helper_functions_community/mat2tikz/test/private/countNumberOfErrors.m b/Libs/mat2tikz/test/private/countNumberOfErrors.m similarity index 100% rename from Functions/helper_functions_community/mat2tikz/test/private/countNumberOfErrors.m rename to Libs/mat2tikz/test/private/countNumberOfErrors.m diff --git a/Functions/helper_functions_community/mat2tikz/test/private/emptyStage.m b/Libs/mat2tikz/test/private/emptyStage.m similarity index 100% rename from Functions/helper_functions_community/mat2tikz/test/private/emptyStage.m rename to Libs/mat2tikz/test/private/emptyStage.m diff --git a/Functions/helper_functions_community/mat2tikz/test/private/emptyStatus.m b/Libs/mat2tikz/test/private/emptyStatus.m similarity index 100% rename from Functions/helper_functions_community/mat2tikz/test/private/emptyStatus.m rename to Libs/mat2tikz/test/private/emptyStatus.m diff --git a/Functions/helper_functions_community/mat2tikz/test/private/errorHandler.m b/Libs/mat2tikz/test/private/errorHandler.m similarity index 100% rename from Functions/helper_functions_community/mat2tikz/test/private/errorHandler.m rename to Libs/mat2tikz/test/private/errorHandler.m diff --git a/Functions/helper_functions_community/mat2tikz/test/private/errorHasOccurred.m b/Libs/mat2tikz/test/private/errorHasOccurred.m similarity index 100% rename from Functions/helper_functions_community/mat2tikz/test/private/errorHasOccurred.m rename to Libs/mat2tikz/test/private/errorHasOccurred.m diff --git a/Functions/helper_functions_community/mat2tikz/test/private/execute_hash_stage.m b/Libs/mat2tikz/test/private/execute_hash_stage.m similarity index 100% rename from Functions/helper_functions_community/mat2tikz/test/private/execute_hash_stage.m rename to Libs/mat2tikz/test/private/execute_hash_stage.m diff --git a/Functions/helper_functions_community/mat2tikz/test/private/execute_plot_stage.m b/Libs/mat2tikz/test/private/execute_plot_stage.m similarity index 100% rename from Functions/helper_functions_community/mat2tikz/test/private/execute_plot_stage.m rename to Libs/mat2tikz/test/private/execute_plot_stage.m diff --git a/Functions/helper_functions_community/mat2tikz/test/private/execute_save_stage.m b/Libs/mat2tikz/test/private/execute_save_stage.m similarity index 100% rename from Functions/helper_functions_community/mat2tikz/test/private/execute_save_stage.m rename to Libs/mat2tikz/test/private/execute_save_stage.m diff --git a/Functions/helper_functions_community/mat2tikz/test/private/execute_tikz_stage.m b/Libs/mat2tikz/test/private/execute_tikz_stage.m similarity index 100% rename from Functions/helper_functions_community/mat2tikz/test/private/execute_tikz_stage.m rename to Libs/mat2tikz/test/private/execute_tikz_stage.m diff --git a/Functions/helper_functions_community/mat2tikz/test/private/execute_type_stage.m b/Libs/mat2tikz/test/private/execute_type_stage.m similarity index 100% rename from Functions/helper_functions_community/mat2tikz/test/private/execute_type_stage.m rename to Libs/mat2tikz/test/private/execute_type_stage.m diff --git a/Functions/helper_functions_community/mat2tikz/test/private/fillStruct.m b/Libs/mat2tikz/test/private/fillStruct.m similarity index 100% rename from Functions/helper_functions_community/mat2tikz/test/private/fillStruct.m rename to Libs/mat2tikz/test/private/fillStruct.m diff --git a/Functions/helper_functions_community/mat2tikz/test/private/getEnvironment.m b/Libs/mat2tikz/test/private/getEnvironment.m similarity index 100% rename from Functions/helper_functions_community/mat2tikz/test/private/getEnvironment.m rename to Libs/mat2tikz/test/private/getEnvironment.m diff --git a/Functions/helper_functions_community/mat2tikz/test/private/getStagesFromStatus.m b/Libs/mat2tikz/test/private/getStagesFromStatus.m similarity index 100% rename from Functions/helper_functions_community/mat2tikz/test/private/getStagesFromStatus.m rename to Libs/mat2tikz/test/private/getStagesFromStatus.m diff --git a/Functions/helper_functions_community/mat2tikz/test/private/hasTestFailed.m b/Libs/mat2tikz/test/private/hasTestFailed.m similarity index 100% rename from Functions/helper_functions_community/mat2tikz/test/private/hasTestFailed.m rename to Libs/mat2tikz/test/private/hasTestFailed.m diff --git a/Functions/helper_functions_community/mat2tikz/test/private/hashTableName.m b/Libs/mat2tikz/test/private/hashTableName.m similarity index 100% rename from Functions/helper_functions_community/mat2tikz/test/private/hashTableName.m rename to Libs/mat2tikz/test/private/hashTableName.m diff --git a/Functions/helper_functions_community/mat2tikz/test/private/initializeGlobalState.m b/Libs/mat2tikz/test/private/initializeGlobalState.m similarity index 100% rename from Functions/helper_functions_community/mat2tikz/test/private/initializeGlobalState.m rename to Libs/mat2tikz/test/private/initializeGlobalState.m diff --git a/Functions/helper_functions_community/mat2tikz/test/private/loadHashTable.m b/Libs/mat2tikz/test/private/loadHashTable.m similarity index 100% rename from Functions/helper_functions_community/mat2tikz/test/private/loadHashTable.m rename to Libs/mat2tikz/test/private/loadHashTable.m diff --git a/Functions/helper_functions_community/mat2tikz/test/private/m2troot.m b/Libs/mat2tikz/test/private/m2troot.m similarity index 100% rename from Functions/helper_functions_community/mat2tikz/test/private/m2troot.m rename to Libs/mat2tikz/test/private/m2troot.m diff --git a/Functions/helper_functions_community/mat2tikz/test/private/m2tstrjoin.m b/Libs/mat2tikz/test/private/m2tstrjoin.m similarity index 100% rename from Functions/helper_functions_community/mat2tikz/test/private/m2tstrjoin.m rename to Libs/mat2tikz/test/private/m2tstrjoin.m diff --git a/Functions/helper_functions_community/mat2tikz/test/private/restoreGlobalState.m b/Libs/mat2tikz/test/private/restoreGlobalState.m similarity index 100% rename from Functions/helper_functions_community/mat2tikz/test/private/restoreGlobalState.m rename to Libs/mat2tikz/test/private/restoreGlobalState.m diff --git a/Functions/helper_functions_community/mat2tikz/test/private/splitPassFailSkippedTests.m b/Libs/mat2tikz/test/private/splitPassFailSkippedTests.m similarity index 100% rename from Functions/helper_functions_community/mat2tikz/test/private/splitPassFailSkippedTests.m rename to Libs/mat2tikz/test/private/splitPassFailSkippedTests.m diff --git a/Functions/helper_functions_community/mat2tikz/test/private/splitUnreliableTests.m b/Libs/mat2tikz/test/private/splitUnreliableTests.m similarity index 100% rename from Functions/helper_functions_community/mat2tikz/test/private/splitUnreliableTests.m rename to Libs/mat2tikz/test/private/splitUnreliableTests.m diff --git a/Functions/helper_functions_community/mat2tikz/test/private/testMatlab2tikz.m b/Libs/mat2tikz/test/private/testMatlab2tikz.m similarity index 100% rename from Functions/helper_functions_community/mat2tikz/test/private/testMatlab2tikz.m rename to Libs/mat2tikz/test/private/testMatlab2tikz.m diff --git a/Functions/helper_functions_community/mat2tikz/test/runMatlab2TikzTests.m b/Libs/mat2tikz/test/runMatlab2TikzTests.m similarity index 100% rename from Functions/helper_functions_community/mat2tikz/test/runMatlab2TikzTests.m rename to Libs/mat2tikz/test/runMatlab2TikzTests.m diff --git a/Functions/helper_functions_community/mat2tikz/test/saveHashTable.m b/Libs/mat2tikz/test/saveHashTable.m similarity index 100% rename from Functions/helper_functions_community/mat2tikz/test/saveHashTable.m rename to Libs/mat2tikz/test/saveHashTable.m diff --git a/Functions/helper_functions_community/mat2tikz/test/suites/ACID.MATLAB.8.3.md5 b/Libs/mat2tikz/test/suites/ACID.MATLAB.8.3.md5 similarity index 100% rename from Functions/helper_functions_community/mat2tikz/test/suites/ACID.MATLAB.8.3.md5 rename to Libs/mat2tikz/test/suites/ACID.MATLAB.8.3.md5 diff --git a/Functions/helper_functions_community/mat2tikz/test/suites/ACID.MATLAB.8.4.md5 b/Libs/mat2tikz/test/suites/ACID.MATLAB.8.4.md5 similarity index 100% rename from Functions/helper_functions_community/mat2tikz/test/suites/ACID.MATLAB.8.4.md5 rename to Libs/mat2tikz/test/suites/ACID.MATLAB.8.4.md5 diff --git a/Functions/helper_functions_community/mat2tikz/test/suites/ACID.Octave.3.8.0.md5 b/Libs/mat2tikz/test/suites/ACID.Octave.3.8.0.md5 similarity index 100% rename from Functions/helper_functions_community/mat2tikz/test/suites/ACID.Octave.3.8.0.md5 rename to Libs/mat2tikz/test/suites/ACID.Octave.3.8.0.md5 diff --git a/Functions/helper_functions_community/mat2tikz/test/suites/ACID.Octave.4.2.0.md5 b/Libs/mat2tikz/test/suites/ACID.Octave.4.2.0.md5 similarity index 100% rename from Functions/helper_functions_community/mat2tikz/test/suites/ACID.Octave.4.2.0.md5 rename to Libs/mat2tikz/test/suites/ACID.Octave.4.2.0.md5 diff --git a/Functions/helper_functions_community/mat2tikz/test/suites/ACID.Octave.4.2.2.md5 b/Libs/mat2tikz/test/suites/ACID.Octave.4.2.2.md5 similarity index 100% rename from Functions/helper_functions_community/mat2tikz/test/suites/ACID.Octave.4.2.2.md5 rename to Libs/mat2tikz/test/suites/ACID.Octave.4.2.2.md5 diff --git a/Functions/helper_functions_community/mat2tikz/test/suites/ACID.m b/Libs/mat2tikz/test/suites/ACID.m similarity index 100% rename from Functions/helper_functions_community/mat2tikz/test/suites/ACID.m rename to Libs/mat2tikz/test/suites/ACID.m diff --git a/Functions/helper_functions_community/mat2tikz/test/suites/issues.m b/Libs/mat2tikz/test/suites/issues.m similarity index 100% rename from Functions/helper_functions_community/mat2tikz/test/suites/issues.m rename to Libs/mat2tikz/test/suites/issues.m diff --git a/Functions/helper_functions_community/mat2tikz/test/suites/private/getEnvironment.m b/Libs/mat2tikz/test/suites/private/getEnvironment.m similarity index 100% rename from Functions/helper_functions_community/mat2tikz/test/suites/private/getEnvironment.m rename to Libs/mat2tikz/test/suites/private/getEnvironment.m diff --git a/Functions/helper_functions_community/mat2tikz/test/suites/private/herrorbar.m b/Libs/mat2tikz/test/suites/private/herrorbar.m similarity index 100% rename from Functions/helper_functions_community/mat2tikz/test/suites/private/herrorbar.m rename to Libs/mat2tikz/test/suites/private/herrorbar.m diff --git a/Functions/helper_functions_community/mat2tikz/test/suites/private/isEnvironment.m b/Libs/mat2tikz/test/suites/private/isEnvironment.m similarity index 100% rename from Functions/helper_functions_community/mat2tikz/test/suites/private/isEnvironment.m rename to Libs/mat2tikz/test/suites/private/isEnvironment.m diff --git a/Functions/helper_functions_community/mat2tikz/test/suites/private/isMATLAB.m b/Libs/mat2tikz/test/suites/private/isMATLAB.m similarity index 100% rename from Functions/helper_functions_community/mat2tikz/test/suites/private/isMATLAB.m rename to Libs/mat2tikz/test/suites/private/isMATLAB.m diff --git a/Functions/helper_functions_community/mat2tikz/test/suites/private/isOctave.m b/Libs/mat2tikz/test/suites/private/isOctave.m similarity index 100% rename from Functions/helper_functions_community/mat2tikz/test/suites/private/isOctave.m rename to Libs/mat2tikz/test/suites/private/isOctave.m diff --git a/Functions/helper_functions_community/mat2tikz/test/suites/private/isVersionBelow.m b/Libs/mat2tikz/test/suites/private/isVersionBelow.m similarity index 100% rename from Functions/helper_functions_community/mat2tikz/test/suites/private/isVersionBelow.m rename to Libs/mat2tikz/test/suites/private/isVersionBelow.m diff --git a/Functions/helper_functions_community/mat2tikz/test/suites/private/versionCompare.m b/Libs/mat2tikz/test/suites/private/versionCompare.m similarity index 100% rename from Functions/helper_functions_community/mat2tikz/test/suites/private/versionCompare.m rename to Libs/mat2tikz/test/suites/private/versionCompare.m diff --git a/Functions/helper_functions_community/mat2tikz/test/suites/testPatches.m b/Libs/mat2tikz/test/suites/testPatches.m similarity index 100% rename from Functions/helper_functions_community/mat2tikz/test/suites/testPatches.m rename to Libs/mat2tikz/test/suites/testPatches.m diff --git a/Functions/helper_functions_community/mat2tikz/test/suites/testSurfshader.m b/Libs/mat2tikz/test/suites/testSurfshader.m similarity index 100% rename from Functions/helper_functions_community/mat2tikz/test/suites/testSurfshader.m rename to Libs/mat2tikz/test/suites/testSurfshader.m diff --git a/Functions/helper_functions_community/mat2tikz/test/template/.gitignore b/Libs/mat2tikz/test/template/.gitignore similarity index 100% rename from Functions/helper_functions_community/mat2tikz/test/template/.gitignore rename to Libs/mat2tikz/test/template/.gitignore diff --git a/Functions/helper_functions_community/mat2tikz/test/template/Makefile b/Libs/mat2tikz/test/template/Makefile similarity index 100% rename from Functions/helper_functions_community/mat2tikz/test/template/Makefile rename to Libs/mat2tikz/test/template/Makefile diff --git a/Functions/helper_functions_community/mat2tikz/test/template/data/.gitignore b/Libs/mat2tikz/test/template/data/.gitignore similarity index 100% rename from Functions/helper_functions_community/mat2tikz/test/template/data/.gitignore rename to Libs/mat2tikz/test/template/data/.gitignore diff --git a/Functions/helper_functions_community/mat2tikz/test/template/data/converted/Makefile b/Libs/mat2tikz/test/template/data/converted/Makefile similarity index 100% rename from Functions/helper_functions_community/mat2tikz/test/template/data/converted/Makefile rename to Libs/mat2tikz/test/template/data/converted/Makefile diff --git a/Functions/helper_functions_community/mat2tikz/test/template/data/reference/Makefile b/Libs/mat2tikz/test/template/data/reference/Makefile similarity index 100% rename from Functions/helper_functions_community/mat2tikz/test/template/data/reference/Makefile rename to Libs/mat2tikz/test/template/data/reference/Makefile diff --git a/Functions/helper_functions_community/mat2tikz/test/testGraphical.m b/Libs/mat2tikz/test/testGraphical.m similarity index 100% rename from Functions/helper_functions_community/mat2tikz/test/testGraphical.m rename to Libs/mat2tikz/test/testGraphical.m diff --git a/Functions/helper_functions_community/mat2tikz/test/testHeadless.m b/Libs/mat2tikz/test/testHeadless.m similarity index 100% rename from Functions/helper_functions_community/mat2tikz/test/testHeadless.m rename to Libs/mat2tikz/test/testHeadless.m diff --git a/Functions/helper_functions_community/png/nt_.png b/Libs/png/nt_.png similarity index 100% rename from Functions/helper_functions_community/png/nt_.png rename to Libs/png/nt_.png diff --git a/Functions/helper_functions_community/schemer/.gitattributes b/Libs/schemer/.gitattributes similarity index 100% rename from Functions/helper_functions_community/schemer/.gitattributes rename to Libs/schemer/.gitattributes diff --git a/Functions/helper_functions_community/schemer/.gitignore b/Libs/schemer/.gitignore similarity index 100% rename from Functions/helper_functions_community/schemer/.gitignore rename to Libs/schemer/.gitignore diff --git a/Functions/helper_functions_community/schemer/CONTRIBUTING.md b/Libs/schemer/CONTRIBUTING.md similarity index 100% rename from Functions/helper_functions_community/schemer/CONTRIBUTING.md rename to Libs/schemer/CONTRIBUTING.md diff --git a/Functions/helper_functions_community/schemer/LICENSE b/Libs/schemer/LICENSE similarity index 100% rename from Functions/helper_functions_community/schemer/LICENSE rename to Libs/schemer/LICENSE diff --git a/Functions/helper_functions_community/schemer/README.md b/Libs/schemer/README.md similarity index 100% rename from Functions/helper_functions_community/schemer/README.md rename to Libs/schemer/README.md diff --git a/Functions/helper_functions_community/schemer/develop/RGBint2hex.m b/Libs/schemer/develop/RGBint2hex.m similarity index 100% rename from Functions/helper_functions_community/schemer/develop/RGBint2hex.m rename to Libs/schemer/develop/RGBint2hex.m diff --git a/Functions/helper_functions_community/schemer/develop/annotated_default.png b/Libs/schemer/develop/annotated_default.png similarity index 100% rename from Functions/helper_functions_community/schemer/develop/annotated_default.png rename to Libs/schemer/develop/annotated_default.png diff --git a/Functions/helper_functions_community/schemer/develop/color2javaRGBint.m b/Libs/schemer/develop/color2javaRGBint.m similarity index 100% rename from Functions/helper_functions_community/schemer/develop/color2javaRGBint.m rename to Libs/schemer/develop/color2javaRGBint.m diff --git a/Functions/helper_functions_community/schemer/develop/sample.cpp b/Libs/schemer/develop/sample.cpp similarity index 100% rename from Functions/helper_functions_community/schemer/develop/sample.cpp rename to Libs/schemer/develop/sample.cpp diff --git a/Functions/helper_functions_community/schemer/develop/sample.html b/Libs/schemer/develop/sample.html similarity index 100% rename from Functions/helper_functions_community/schemer/develop/sample.html rename to Libs/schemer/develop/sample.html diff --git a/Functions/helper_functions_community/schemer/develop/sample.java b/Libs/schemer/develop/sample.java similarity index 100% rename from Functions/helper_functions_community/schemer/develop/sample.java rename to Libs/schemer/develop/sample.java diff --git a/Functions/helper_functions_community/schemer/develop/sample.m b/Libs/schemer/develop/sample.m similarity index 100% rename from Functions/helper_functions_community/schemer/develop/sample.m rename to Libs/schemer/develop/sample.m diff --git a/Functions/helper_functions_community/schemer/develop/sample.tlc b/Libs/schemer/develop/sample.tlc similarity index 100% rename from Functions/helper_functions_community/schemer/develop/sample.tlc rename to Libs/schemer/develop/sample.tlc diff --git a/Functions/helper_functions_community/schemer/develop/sample.v b/Libs/schemer/develop/sample.v similarity index 100% rename from Functions/helper_functions_community/schemer/develop/sample.v rename to Libs/schemer/develop/sample.v diff --git a/Functions/helper_functions_community/schemer/develop/sample.vhdl b/Libs/schemer/develop/sample.vhdl similarity index 100% rename from Functions/helper_functions_community/schemer/develop/sample.vhdl rename to Libs/schemer/develop/sample.vhdl diff --git a/Functions/helper_functions_community/schemer/develop/sample.x3d b/Libs/schemer/develop/sample.x3d similarity index 100% rename from Functions/helper_functions_community/schemer/develop/sample.x3d rename to Libs/schemer/develop/sample.x3d diff --git a/Functions/helper_functions_community/schemer/develop/sample.x3dv b/Libs/schemer/develop/sample.x3dv similarity index 100% rename from Functions/helper_functions_community/schemer/develop/sample.x3dv rename to Libs/schemer/develop/sample.x3dv diff --git a/Functions/helper_functions_community/schemer/develop/sample.xml b/Libs/schemer/develop/sample.xml similarity index 100% rename from Functions/helper_functions_community/schemer/develop/sample.xml rename to Libs/schemer/develop/sample.xml diff --git a/Functions/helper_functions_community/schemer/develop/short_sample.m b/Libs/schemer/develop/short_sample.m similarity index 100% rename from Functions/helper_functions_community/schemer/develop/short_sample.m rename to Libs/schemer/develop/short_sample.m diff --git a/Functions/helper_functions_community/schemer/develop/template_scheme.prf b/Libs/schemer/develop/template_scheme.prf similarity index 100% rename from Functions/helper_functions_community/schemer/develop/template_scheme.prf rename to Libs/schemer/develop/template_scheme.prf diff --git a/Functions/helper_functions_community/schemer/logo.png b/Libs/schemer/logo.png similarity index 100% rename from Functions/helper_functions_community/schemer/logo.png rename to Libs/schemer/logo.png diff --git a/Functions/helper_functions_community/schemer/schemer_export.m b/Libs/schemer/schemer_export.m similarity index 100% rename from Functions/helper_functions_community/schemer/schemer_export.m rename to Libs/schemer/schemer_export.m diff --git a/Functions/helper_functions_community/schemer/schemer_import.m b/Libs/schemer/schemer_import.m similarity index 100% rename from Functions/helper_functions_community/schemer/schemer_import.m rename to Libs/schemer/schemer_import.m diff --git a/Functions/helper_functions_community/schemer/schemes/.gitattributes b/Libs/schemer/schemes/.gitattributes similarity index 100% rename from Functions/helper_functions_community/schemer/schemes/.gitattributes rename to Libs/schemer/schemes/.gitattributes diff --git a/Functions/helper_functions_community/schemer/schemes/.gitignore b/Libs/schemer/schemes/.gitignore similarity index 100% rename from Functions/helper_functions_community/schemer/schemes/.gitignore rename to Libs/schemer/schemes/.gitignore diff --git a/Functions/helper_functions_community/schemer/schemes/CONTRIBUTING.md b/Libs/schemer/schemes/CONTRIBUTING.md similarity index 100% rename from Functions/helper_functions_community/schemer/schemes/CONTRIBUTING.md rename to Libs/schemer/schemes/CONTRIBUTING.md diff --git a/Functions/helper_functions_community/schemer/schemes/LICENSE b/Libs/schemer/schemes/LICENSE similarity index 100% rename from Functions/helper_functions_community/schemer/schemes/LICENSE rename to Libs/schemer/schemes/LICENSE diff --git a/Functions/helper_functions_community/schemer/schemes/README.md b/Libs/schemer/schemes/README.md similarity index 100% rename from Functions/helper_functions_community/schemer/schemes/README.md rename to Libs/schemer/schemes/README.md diff --git a/Functions/helper_functions_community/schemer/schemes/SilasColorSchemeForMATLAB.prf b/Libs/schemer/schemes/SilasColorSchemeForMATLAB.prf similarity index 100% rename from Functions/helper_functions_community/schemer/schemes/SilasColorSchemeForMATLAB.prf rename to Libs/schemer/schemes/SilasColorSchemeForMATLAB.prf diff --git a/Functions/helper_functions_community/schemer/schemes/cobalt.prf b/Libs/schemer/schemes/cobalt.prf similarity index 100% rename from Functions/helper_functions_community/schemer/schemes/cobalt.prf rename to Libs/schemer/schemes/cobalt.prf diff --git a/Functions/helper_functions_community/schemer/schemes/darkmate.prf b/Libs/schemer/schemes/darkmate.prf similarity index 100% rename from Functions/helper_functions_community/schemer/schemes/darkmate.prf rename to Libs/schemer/schemes/darkmate.prf diff --git a/Functions/helper_functions_community/schemer/schemes/darksteel.prf b/Libs/schemer/schemes/darksteel.prf similarity index 100% rename from Functions/helper_functions_community/schemer/schemes/darksteel.prf rename to Libs/schemer/schemes/darksteel.prf diff --git a/Functions/helper_functions_community/schemer/schemes/default.prf b/Libs/schemer/schemes/default.prf similarity index 100% rename from Functions/helper_functions_community/schemer/schemes/default.prf rename to Libs/schemer/schemes/default.prf diff --git a/Functions/helper_functions_community/schemer/schemes/matrix.prf b/Libs/schemer/schemes/matrix.prf similarity index 100% rename from Functions/helper_functions_community/schemer/schemes/matrix.prf rename to Libs/schemer/schemes/matrix.prf diff --git a/Functions/helper_functions_community/schemer/schemes/monokai.prf b/Libs/schemer/schemes/monokai.prf similarity index 100% rename from Functions/helper_functions_community/schemer/schemes/monokai.prf rename to Libs/schemer/schemes/monokai.prf diff --git a/Functions/helper_functions_community/schemer/schemes/oblivion.prf b/Libs/schemer/schemes/oblivion.prf similarity index 100% rename from Functions/helper_functions_community/schemer/schemes/oblivion.prf rename to Libs/schemer/schemes/oblivion.prf diff --git a/Functions/helper_functions_community/schemer/schemes/screenshots/cobalt.png b/Libs/schemer/schemes/screenshots/cobalt.png similarity index 100% rename from Functions/helper_functions_community/schemer/schemes/screenshots/cobalt.png rename to Libs/schemer/schemes/screenshots/cobalt.png diff --git a/Functions/helper_functions_community/schemer/schemes/screenshots/darkmate.png b/Libs/schemer/schemes/screenshots/darkmate.png similarity index 100% rename from Functions/helper_functions_community/schemer/schemes/screenshots/darkmate.png rename to Libs/schemer/schemes/screenshots/darkmate.png diff --git a/Functions/helper_functions_community/schemer/schemes/screenshots/darksteel.png b/Libs/schemer/schemes/screenshots/darksteel.png similarity index 100% rename from Functions/helper_functions_community/schemer/schemes/screenshots/darksteel.png rename to Libs/schemer/schemes/screenshots/darksteel.png diff --git a/Functions/helper_functions_community/schemer/schemes/screenshots/default.png b/Libs/schemer/schemes/screenshots/default.png similarity index 100% rename from Functions/helper_functions_community/schemer/schemes/screenshots/default.png rename to Libs/schemer/schemes/screenshots/default.png diff --git a/Functions/helper_functions_community/schemer/schemes/screenshots/matrix.png b/Libs/schemer/schemes/screenshots/matrix.png similarity index 100% rename from Functions/helper_functions_community/schemer/schemes/screenshots/matrix.png rename to Libs/schemer/schemes/screenshots/matrix.png diff --git a/Functions/helper_functions_community/schemer/schemes/screenshots/monokai.png b/Libs/schemer/schemes/screenshots/monokai.png similarity index 100% rename from Functions/helper_functions_community/schemer/schemes/screenshots/monokai.png rename to Libs/schemer/schemes/screenshots/monokai.png diff --git a/Functions/helper_functions_community/schemer/schemes/screenshots/oblivion.png b/Libs/schemer/schemes/screenshots/oblivion.png similarity index 100% rename from Functions/helper_functions_community/schemer/schemes/screenshots/oblivion.png rename to Libs/schemer/schemes/screenshots/oblivion.png diff --git a/Functions/helper_functions_community/schemer/schemes/screenshots/solarized-dark.png b/Libs/schemer/schemes/screenshots/solarized-dark.png similarity index 100% rename from Functions/helper_functions_community/schemer/schemes/screenshots/solarized-dark.png rename to Libs/schemer/schemes/screenshots/solarized-dark.png diff --git a/Functions/helper_functions_community/schemer/schemes/screenshots/solarized-light.png b/Libs/schemer/schemes/screenshots/solarized-light.png similarity index 100% rename from Functions/helper_functions_community/schemer/schemes/screenshots/solarized-light.png rename to Libs/schemer/schemes/screenshots/solarized-light.png diff --git a/Functions/helper_functions_community/schemer/schemes/screenshots/tango.png b/Libs/schemer/schemes/screenshots/tango.png similarity index 100% rename from Functions/helper_functions_community/schemer/schemes/screenshots/tango.png rename to Libs/schemer/schemes/screenshots/tango.png diff --git a/Functions/helper_functions_community/schemer/schemes/screenshots/vibrant.png b/Libs/schemer/schemes/screenshots/vibrant.png similarity index 100% rename from Functions/helper_functions_community/schemer/schemes/screenshots/vibrant.png rename to Libs/schemer/schemes/screenshots/vibrant.png diff --git a/Functions/helper_functions_community/schemer/schemes/solarized-dark.prf b/Libs/schemer/schemes/solarized-dark.prf similarity index 100% rename from Functions/helper_functions_community/schemer/schemes/solarized-dark.prf rename to Libs/schemer/schemes/solarized-dark.prf diff --git a/Functions/helper_functions_community/schemer/schemes/solarized-light.prf b/Libs/schemer/schemes/solarized-light.prf similarity index 100% rename from Functions/helper_functions_community/schemer/schemes/solarized-light.prf rename to Libs/schemer/schemes/solarized-light.prf diff --git a/Functions/helper_functions_community/schemer/schemes/tango.prf b/Libs/schemer/schemes/tango.prf similarity index 100% rename from Functions/helper_functions_community/schemer/schemes/tango.prf rename to Libs/schemer/schemes/tango.prf diff --git a/Functions/helper_functions_community/schemer/schemes/vibrant.prf b/Libs/schemer/schemes/vibrant.prf similarity index 100% rename from Functions/helper_functions_community/schemer/schemes/vibrant.prf rename to Libs/schemer/schemes/vibrant.prf diff --git a/Functions/helper_functions_community/sendolmail.m b/Libs/sendolmail.m similarity index 100% rename from Functions/helper_functions_community/sendolmail.m rename to Libs/sendolmail.m diff --git a/Functions/settingsdlg/.gitignore b/Libs/settingsdlg/.gitignore similarity index 100% rename from Functions/settingsdlg/.gitignore rename to Libs/settingsdlg/.gitignore diff --git a/Functions/settingsdlg/License.txt b/Libs/settingsdlg/License.txt similarity index 98% rename from Functions/settingsdlg/License.txt rename to Libs/settingsdlg/License.txt index b808cd3..bedf626 100644 --- a/Functions/settingsdlg/License.txt +++ b/Libs/settingsdlg/License.txt @@ -1,26 +1,26 @@ -Copyright (c) 2018, Rody Oldenhuis -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - -1. Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. -2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR -ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -The views and conclusions contained in the software and documentation are those -of the authors and should not be interpreted as representing official policies, -either expressed or implied, of this project. +Copyright (c) 2018, Rody Oldenhuis +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +The views and conclusions contained in the software and documentation are those +of the authors and should not be interpreted as representing official policies, +either expressed or implied, of this project. diff --git a/Functions/settingsdlg/README.md b/Libs/settingsdlg/README.md similarity index 100% rename from Functions/settingsdlg/README.md rename to Libs/settingsdlg/README.md diff --git a/Functions/settingsdlg/Screen.png b/Libs/settingsdlg/Screen.png similarity index 100% rename from Functions/settingsdlg/Screen.png rename to Libs/settingsdlg/Screen.png diff --git a/Functions/settingsdlg/settingsdlg.m b/Libs/settingsdlg/settingsdlg.m similarity index 100% rename from Functions/settingsdlg/settingsdlg.m rename to Libs/settingsdlg/settingsdlg.m diff --git a/Functions/settingsdlg/settingsdlg.odt b/Libs/settingsdlg/settingsdlg.odt similarity index 100% rename from Functions/settingsdlg/settingsdlg.odt rename to Libs/settingsdlg/settingsdlg.odt diff --git a/Functions/settingsdlg/settingsdlg.pdf b/Libs/settingsdlg/settingsdlg.pdf similarity index 100% rename from Functions/settingsdlg/settingsdlg.pdf rename to Libs/settingsdlg/settingsdlg.pdf diff --git a/projects/400G_FTN_setups/imdd_mpi_dsp.m b/projects/400G_FTN_setups/imdd_mpi_dsp.m index 068cf5a..2016158 100644 --- a/projects/400G_FTN_setups/imdd_mpi_dsp.m +++ b/projects/400G_FTN_setups/imdd_mpi_dsp.m @@ -3,30 +3,30 @@ params = struct; params.M = [4]; -params.datarate = [250]; -params.rop = [-10]; -params.sir = 40;%15:1:40; -params.random_key_laser_phase = 1; +params.datarate = [448]; +params.rop = [0]; +params.sir = 45; +params.random_key_laser_phase = 10:20; precomp_mode = 0; %0=do nothing ; 1= measure; 2=precomp active -postfilter = 0; % noise whiten. approach -> Postfilter + MLSE +postfilter = 1; % noise whiten. approach -> Postfilter + MLSE db_precode = 0; db_encode = 0; -db_channelapproach = 1; +db_channelapproach = 0; -laser_linewidth = 0e5; +laser_linewidth = 5e5; random_key_sequence = 15; random_key_laser_phase = 66; -sir = 60; +sir = 20; if ismac precomp_path = "/Users/silasoettinghaus/Documents/MATLAB/imdd_simulation/projects/standard_system"; else - precomp_path = "C:\Users\sioe\Documents\MATLAB\imdd_simulation\projects\standard_system\"; + precomp_path = "C:\Users\Silas\Documents\MATLAB\imdd_simulation\projects\standard_system\"; end -precomp_fn = "400G_simulative_setup_meas"; +precomp_fn = "400G_simulative_setup"; usemrds = 0; @@ -47,130 +47,130 @@ disp(['Start Simulation of ',num2str(endcnt),' loops...']) tic for random_key_laser_phase = wh.parameter.random_key_laser_phase.values - for M = wh.parameter.M.values - for datarate = wh.parameter.datarate.values +for M = wh.parameter.M.values + for datarate = wh.parameter.datarate.values - % SETUP HERE: %% - kover = 16; - M8199 = M8199B("kover",kover); - fdac = M8199.fdac; - fsym = round(datarate / log2(M)) * 1e9; - rrcalpha = 0.05; - Pform = Pulseformer("fsym",fsym,"fdac",4*fsym,"pulse","rrc","pulselength",16,"rrcalpha",rrcalpha); + % SETUP HERE: %% + kover = 16; + M8199 = M8199B("kover",kover); + fdac = M8199.fdac; + fsym = round(datarate / log2(M)) * 1e9; + rrcalpha = 0.05; + Pform = Pulseformer("fsym",fsym,"fdac",4*fsym,"pulse","rrc","pulselength",16,"rrcalpha",rrcalpha); - % MAIN SIGNAL + % MAIN SIGNAL - %%%%% Symbol Generation MAIN %%%%%% - [Digi_sig,Symbols,Bits] = PAMsource("fsym",fsym,"M",M,"order",18,"useprbs",1,... - "fs_out",M8199.fdac,"applyclipping",0,"clipfactor",1.5,... - "applypulseform",0,"pulseformer",Pform,"randkey",random_key_sequence,... - "db_precode",db_precode,"db_encode",db_encode,... - "mrds_code",usemrds,"mrds_blocklength",512).process(); + %%%%% Symbol Generation MAIN %%%%%% + [Digi_sig,Symbols,Bits] = PAMsource("fsym",fsym,"M",M,"order",19,"useprbs",1,... + "fs_out",M8199.fdac,"applyclipping",0,"clipfactor",1.5,... + "applypulseform",0,"pulseformer",Pform,"randkey",random_key_sequence,... + "db_precode",db_precode,"db_encode",db_encode,... + "mrds_code",usemrds,"mrds_blocklength",512).process(); - %%%%% Symbol Generation INTERFERENCE %%%%%% - [Digi_sig_I,Symbols_I,Bits_I] = PAMsource("fsym",fsym,"M",M,"order",18,"useprbs",0,... - "fs_out",M8199.fdac,"applyclipping",0,"clipfactor",1.5,... - "applypulseform",0,"pulseformer",Pform,"randkey",random_key_sequence+1,... - "db_precode",db_precode,"db_encode",db_encode,... - "mrds_code",usemrds,"mrds_blocklength",512).process(); + %%%%% Symbol Generation INTERFERENCE %%%%%% + [Digi_sig_I,Symbols_I,Bits_I] = PAMsource("fsym",fsym,"M",M,"order",19,"useprbs",0,... + "fs_out",M8199.fdac,"applyclipping",0,"clipfactor",1.5,... + "applypulseform",0,"pulseformer",Pform,"randkey",random_key_sequence+1,... + "db_precode",db_precode,"db_encode",db_encode,... + "mrds_code",usemrds,"mrds_blocklength",512).process(); - % Digi_sig.eye(fsym,M); - % Digi_sig.normalize("mode","rms").spectrum("displayname",'Tx Signal','fignum',10); + % Digi_sig.eye(fsym,M); + % Digi_sig.normalize("mode","rms").spectrum("displayname",'Tx Signal','fignum',10); - if precomp_mode == 1 %measure - precomp_est = ChannelFreqResp("Nacq",1024,"Navg",64,"Ncp",63,'f_ref',Digi_sig.fs); - Digi_sig = precomp_est.buildOFDM(); - Digi_sig_I = precomp_est.buildOFDM(); - elseif precomp_mode == 2 %apply - Digi_sig = ChannelFreqResp("Nacq",1024,"Navg",64,"Ncp",63,'f_ref',Digi_sig.fs).precomp(Digi_sig,'maxampdb',3,'loadPath',precomp_path,'fileName',precomp_fn); - Digi_sig_I = ChannelFreqResp("Nacq",1024,"Navg",64,"Ncp",63,'f_ref',Digi_sig_I.fs).precomp(Digi_sig_I,'maxampdb',3,'loadPath',precomp_path,'fileName',precomp_fn); - Digi_sig.spectrum("fignum",11,"displayname",'after precomp'); - end + if precomp_mode == 1 %measure + freqresp = ChannelFreqResp("Nacq",1024,"Navg",64,"Ncp",63,'f_ref',Digi_sig.fs); + Digi_sig = freqresp.buildOFDM(); + Digi_sig_I = freqresp.buildOFDM(); + elseif precomp_mode == 2 %apply + Digi_sig = ChannelFreqResp("Nacq",1024,"Navg",64,"Ncp",63,'f_ref',Digi_sig.fs).precomp(Digi_sig,'maxampdb',3,'loadPath',precomp_path,'fileName',precomp_fn); + Digi_sig_I = ChannelFreqResp("Nacq",1024,"Navg",64,"Ncp",63,'f_ref',Digi_sig_I.fs).precomp(Digi_sig_I,'maxampdb',3,'loadPath',precomp_path,'fileName',precomp_fn); + Digi_sig.spectrum("fignum",11,"displayname",'after precomp'); + end - %%%%% AWG MAIN %%%%%% - El_sig = M8199.process(Digi_sig); + %%%%% AWG MAIN %%%%%% + El_sig = M8199.process(Digi_sig); - %%%%% Lowpass el. components %%%%%% - El_sig = Filter('filtdegree',2,"f_cutoff",100e9,"fs",fdac*kover,"filterType",filtertypes.butterworth,"active",true).process(El_sig); + %%%%% Lowpass el. components %%%%%% + El_sig = Filter('filtdegree',2,"f_cutoff",100e9,"fs",fdac*kover,"filterType",filtertypes.butterworth,"active",true).process(El_sig); - %%%%% Electrical Driver Amplifier %%%%%% - El_sig = Amplifier("amp_mode","ideal_no_noise","gain_mode","gain","amplification_db",3).process(El_sig); + %%%%% Electrical Driver Amplifier %%%%%% + El_sig = Amplifier("amp_mode","ideal_no_noise","gain_mode","gain","amplification_db",3).process(El_sig); - fprintf('Driver output power: %s dBm\n', num2str(El_sig.power)); - fprintf('Driver output peak voltage: %s Vpp \n', num2str(max(El_sig.signal)-min(El_sig.signal))); + fprintf('Driver output power: %s dBm\n', num2str(El_sig.power)); + fprintf('Driver output peak voltage: %s Vpp \n', num2str(max(El_sig.signal)-min(El_sig.signal))); - % El_sig.spectrum("displayname",'Transmit PDS','fignum',10); + % El_sig.spectrum("displayname",'Transmit PDS','fignum',10); - %%%%% AWG INTERFERENCE %%%%%% - El_sig_I = M8199.process(Digi_sig_I); + %%%%% AWG INTERFERENCE %%%%%% + El_sig_I = M8199.process(Digi_sig_I); - %%%%% Lowpass el. components %%%%%% - El_sig_I = Filter('filtdegree',3,"f_cutoff",100e9,"fs",fdac*kover,"filterType",filtertypes.butterworth,"active",true).process(El_sig_I); + %%%%% Lowpass el. components %%%%%% + El_sig_I = Filter('filtdegree',3,"f_cutoff",100e9,"fs",fdac*kover,"filterType",filtertypes.butterworth,"active",true).process(El_sig_I); - %%%%% Electrical Driver Amplifier %%%%%% - El_sig_I = Amplifier("amp_mode","ideal_no_noise","gain_mode","gain","amplification_db",3).process(El_sig_I); + %%%%% Electrical Driver Amplifier %%%%%% + El_sig_I = Amplifier("amp_mode","ideal_no_noise","gain_mode","gain","amplification_db",3).process(El_sig_I); - % MAIN SIGNAL - %%%%% MODULATE E/O CONVERSION %%%%%% - vbias_rel = 0.7; - u_pi = 2.9; - vbias = -vbias_rel*u_pi; + % MAIN SIGNAL + %%%%% MODULATE E/O CONVERSION %%%%%% + vbias_rel = 0.5; + u_pi = 2.9; + vbias = -vbias_rel*u_pi; - [Opt_sig] = EML("mode",eml_mode.im_cosinus,"power",3,"fsimu",El_sig.fs,"lambda",1290,"bias",vbias,"u_pi",u_pi,"linewidth",laser_linewidth,"randomkey",random_key_laser_phase).process(El_sig); - Optfilter = Filter('filtdegree',3,"f_cutoff",110e9,"fs",fdac*kover,"filterType",filtertypes.gaussian,"active",true); - Opt_sig = Optfilter.process(Opt_sig); - Opt_sig = Amplifier("amp_mode","ideal_no_noise","gain_mode","output_power","amplification_db",0).process(Opt_sig); + [Opt_sig] = EML("mode",eml_mode.im_cosinus,"power",3,"fsimu",El_sig.fs,"lambda",1290,"bias",vbias,"u_pi",u_pi,"linewidth",laser_linewidth,"randomkey",random_key_laser_phase).process(El_sig); + Optfilter = Filter('filtdegree',3,"f_cutoff",110e9,"fs",fdac*kover,"filterType",filtertypes.gaussian,"active",true); + Opt_sig = Optfilter.process(Opt_sig); + Opt_sig = Amplifier("amp_mode","ideal_no_noise","gain_mode","output_power","amplification_db",0).process(Opt_sig); - [Opt_sig_I] = EML("mode",eml_mode.im_cosinus,"power",3,"fsimu",El_sig_I.fs,"lambda",1290,"bias",vbias,"u_pi",u_pi,"linewidth",laser_linewidth,"randomkey",random_key_laser_phase+1).process(El_sig_I); - Optfilter = Filter('filtdegree',3,"f_cutoff",110e9,"fs",fdac*kover,"filterType",filtertypes.gaussian,"active",true); - Opt_sig_I = Optfilter.process(Opt_sig_I); - Opt_sig_I = Amplifier("amp_mode","ideal_no_noise","gain_mode","output_power","amplification_db",0).process(Opt_sig_I); + [Opt_sig_I] = EML("mode",eml_mode.im_cosinus,"power",3,"fsimu",El_sig_I.fs,"lambda",1290,"bias",vbias,"u_pi",u_pi,"linewidth",laser_linewidth,"randomkey",random_key_laser_phase+1).process(El_sig_I); + Optfilter = Filter('filtdegree',3,"f_cutoff",110e9,"fs",fdac*kover,"filterType",filtertypes.gaussian,"active",true); + Opt_sig_I = Optfilter.process(Opt_sig_I); + Opt_sig_I = Amplifier("amp_mode","ideal_no_noise","gain_mode","output_power","amplification_db",0).process(Opt_sig_I); - %%%%% Interference Signal Fiber Prop 2x fiber length %%%%%% - Opt_sig_I = Fiber("fsimu",Opt_sig_I.fs,"fiber_length",2*link_length/1000,"alpha",0.3,"D",0,"lambda0",1310,"gamma",0,"Dslope",0.07).process(Opt_sig_I); + %%%%% Interference Signal Fiber Prop 2x fiber length %%%%%% + Opt_sig_I = Fiber("fsimu",Opt_sig_I.fs,"fiber_length",2*link_length/1000,"alpha",0.3,"D",0,"lambda0",1310,"gamma",0,"Dslope",0.07).process(Opt_sig_I); - % ber=zeros(i_); - % patten=zeros(i_); - i_ = wh.parameter.rop.length; - j_ = wh.parameter.sir.length; - - ber_vnle=zeros(i_,j_); - ber_mlse=zeros(i_,j_,3); - - for j = 1:j_ - - sir = wh.parameter.sir.values(j); - - %%%%% Set SIR %%%%%% - Opt_sig_I_atten = Amplifier("amp_mode","ideal_no_noise","gain_mode","output_power","amplification_db",Opt_sig.power-sir).process(Opt_sig_I); - - %%%%% ADD Interference and Main Signal %%%%%% - Opt_sig_MPI = Opt_sig_I_atten + Opt_sig; - - %%%%% Interference Signal Fiber Prop %%%%%% - Opt_sig_MPI = Fiber("fsimu",Opt_sig.fs,"fiber_length",link_length/1000,"alpha",0.3,"D",0,"lambda0",1310,"gamma",0,"Dslope",0.07).process(Opt_sig_MPI); + % ber=zeros(i_); + % patten=zeros(i_); + i_ = wh.parameter.rop.length; + j_ = wh.parameter.sir.length; + ber_vnle=zeros(i_,j_); + ber_mlse=zeros(i_,j_,3); + for j = 1:j_ + + sir = wh.parameter.sir.values(j); + + %%%%% Set SIR %%%%%% + Opt_sig_I_atten = Amplifier("amp_mode","ideal_no_noise","gain_mode","output_power","amplification_db",Opt_sig.power-sir).process(Opt_sig_I); + + %%%%% ADD Interference and Main Signal %%%%%% + Opt_sig_MPI = Opt_sig_I_atten + Opt_sig; + + %%%%% Interference Signal Fiber Prop %%%%%% + Opt_sig_MPI = Fiber("fsimu",Opt_sig.fs,"fiber_length",link_length/1000,"alpha",0.3,"D",0,"lambda0",1310,"gamma",0,"Dslope",0.07).process(Opt_sig_MPI); + + % Receiver ROP curve for i = 1:i_ rop=wh.parameter.rop.values(i); - + % Set ROP Rx_sig = Amplifier("amp_mode","ideal_no_noise","gain_mode","output_power","amplification_db",rop).process(Opt_sig_MPI); % patten(i) = Rx_sig.power; - + %%%%%% Square Law %%%%%% Rx_sig = Photodiode("fsimu",fdac*kover,"dark_current",2e-08,"responsivity",1,"temperature",20,"nep",1.8e-11).process(Rx_sig); - + %%%%%% Lowpass PhDiode %%%%%% Rx_sig = Filter('filtdegree',2,"f_cutoff",70e9,"fs",fdac*kover,"filterType",filtertypes.gaussian,"active",true).process(Rx_sig); - + %%%%%% Scope %%%%%% fadc = 256e9; Lp_scpe = Filter('filtdegree',4,"f_cutoff",100e9,"fs",fadc,"filterType",filtertypes.butterworth,"active",true); @@ -178,161 +178,122 @@ for random_key_laser_phase = wh.parameter.random_key_laser_phase.values "delay",0,"fixed_delay",0,"filtertype",filtertypes.butterworth,... "samplingdelay",0,"rand_samplingdelay",0,"freq_offset",0,"samp_jitter",0,... "adcresolution",10,"quantbuffer",0.1,'block_dc',1,'lpf_active',1,'H_lpf',Lp_scpe).process(Rx_sig); - + if precomp_mode == 1 - precomp_est.estimate(Scpe_sig,"save",true,"savePath",precomp_path,"fileName",precomp_fn); - precomp_est.plot(); + freqresp.estimate(Scpe_sig,"save",true,"savePath",precomp_path,"fileName",precomp_fn); + freqresp.plot(); end - - % Scpe_sig_normalized = Scpe_sig.normalize("mode","rms"); - - % Scpe_sig.normalize("mode","rms").spectrum("displayname",'After Scope','fignum',10); - + % + % Scpe_sig_normalized.normalize("mode","rms").spectrum("displayname",'After Scope','fignum',23); + %%%%%% Sample to 2x fsym %%%%%% Scpe_sig = Scpe_sig.resample("fs_in",fadc,"fs_out",2*fsym); - + %%%%%% Sync Rx signal with reference %%%%%% [Scpe_sig,S] = Scpe_sig.tsynch("reference",Symbols,"fs_ref",fsym); - - Scpe_sig.eye(fsym,M,"fignum",50,"displayname",'Simulated after Scope'); - + %%%%% EQUALIZE %%%%%% - Eq = FFE("epochs_tr",5,"epochs_dd",5,"len_tr",4096*2,"mu_dd",1e-4,"mu_tr",0,"order",25,"sps",2,"decide",0); + Eq = FFE("epochs_tr",5,"epochs_dd",5,"len_tr",4096*2,"mu_dd",1e-4,"mu_tr",0,"order",25,"sps",2,"decide",0); % Eq = VNLE("epochs_tr",5,"epochs_dd",5,"len_tr",4096*2,"mu_dd",[0.0004 0.0005 0.0006],"mu_tr",0,"order",[50,7,7],"sps",2,"decide",1); - - % Eq = EQ("Ne",[50,7,7],"Nb",[0,0,0],"training_length",4096*2,"training_loops",5,"dd_loops",5,"K",2,"DCmu",0.0,"DDmu",[0.0004 0.0004 0.0004 0.0004 ],"DFEmu",0.005,"FFEmu",0,"plotfinal",0,"ideal_dfe",1); - + + % Eq = EQ("Ne",[50,7,7],"Nb",[0,0,0],"training_length",4096*2,"training_loops",5,"dd_loops",5,"K",2,"DCmu",0.0,"DDmu",[0.0004 0.0004 0.0004 0.0004 ],"DFEmu",0.005,"FFEmu",0,"plotfinal",0,"ideal_dfe",1); + % Eq = FFE_Kalman("epochs_tr",5,"epochs_dd",5,"len_tr",4096*2,"mu_dd",1e-4,"mu_tr",0,"order",25,"sps",2,"decide",0); - - % Eq = FFE_Kalman_Feedback("epochs_tr",5,"epochs_dd",5,"len_tr",4096*2,"mu_dd",1e-4,"mu_tr",0,"order",25,"sps",2,"decide",0); - + + % Eq = FFE_Kalman_Feedback("epochs_tr",5,"epochs_dd",5,"len_tr",4096*2,"mu_dd",1e-4,"mu_tr",0,"order",25,"sps",2,"decide",0); + % Eq = FFE_adaptive_decision("epochs_tr",5,"epochs_dd",5,"len_tr",4096*2,"mu_dd",1e-4,"mu_tr",0,"order",25,"sps",2,"decide",1,"buffer_length",80); - - % Eq = FFE_DCremoval("epochs_tr",5,"epochs_dd",5,"len_tr",4096*2,"mu_dd",1e-4,"mu_tr",0,"order",25,"sps",2,"decide",0,"mu_dc",0.05,"dc_buffer_len",100); - % - % Eq = EQ("Ne",[50,7,7],"Nb",[0,0,0],"training_length",4096*2,"training_loops",5,"dd_loops",5,"K",2,"DCmu",0.0,"DDmu",[0.0004 0.0004 0.0004 0.0004 ],"DFEmu",0.005,"FFEmu",0,"plotfinal",0,"ideal_dfe",1); - + + % Eq = FFE_DCremoval("epochs_tr",5,"epochs_dd",5,"len_tr",4096*2,"mu_dd",1e-4,"mu_tr",0,"order",25,"sps",2,"decide",0,"mu_dc",0.05,"dc_buffer_len",100); + % + % Eq = EQ("Ne",[50,7,7],"Nb",[0,0,0],"training_length",4096*2,"training_loops",5,"dd_loops",5,"K",2,"DCmu",0.0,"DDmu",[0.0004 0.0004 0.0004 0.0004 ],"DFEmu",0.005,"FFEmu",0,"plotfinal",0,"ideal_dfe",1); + if db_channelapproach % ref symbols and transm. sequence are precoded - if db_precode - [EQ_sig, Noi] = Eq.process(Scpe_sig,Duobinary().encode(Symbols)); - EQ_sig = MLSE("DIR",[1,1],"duobinary_output",1,"M",M,"trellis_states",PAMmapper(M,0).levels).process(EQ_sig); - EQ_sig = Duobinary().decode(EQ_sig); - Rx_bits = PAMmapper(M,0).demap(EQ_sig); - [~,~,ber_vnle(i,j),~] = calc_ber(Rx_bits.signal,Bits.signal,"skip_front",100,"skip_end",150,"returnErrorLocation",1); - else + [EQ_sig, Noi] = Eq.process(Scpe_sig,Duobinary().encode(Symbols)); - [EQ_sig, Noi] = Eq.process(Scpe_sig,Duobinary().encode(Symbols)); + EQ_sig = MLSE("DIR",[1,1],"duobinary_output",1,"M",M,"trellis_states",PAMmapper(M,0).levels).process(EQ_sig); + EQ_sig = Duobinary().decode(EQ_sig); + Rx_bits = PAMmapper(M,0).demap(EQ_sig); + [~,~,ber_vnle(i,j),~] = calc_ber(Rx_bits.signal,Bits.signal,"skip_front",100,"skip_end",150,"returnErrorLocation",1); - EQ_sig.spectrum("displayname","Signal Spectrum after Postfilter","fignum",1234,"normalizeToNyquist",0); + + EQ_sig.spectrum('displayname','EQ DB Out','fignum',12345,'normalizeTo0dB',0,'normalizeToNyquist',0,'color',cols(3,:)); + Noi.spectrum('displayname','Noise PSD optimal','fignum',1234,'normalizeTo0dB',0,'normalizeToNyquist',0,'color',cols(4,:)); - EQ_sig = MLSE("DIR",[1,1],"duobinary_output",0,"M",M,"trellis_states",PAMmapper(M,0).levels).process(EQ_sig); - % 2: Entschiedene Symbole codieren - EQ_sig = Duobinary().encode(EQ_sig); - - % 3. Entschiedene und codierte Symbole dekodieren - EQ_sig = Duobinary().decode(EQ_sig); - - % 4. Demap EQ'd symbols - Rx_bits = PAMmapper(M,0).demap(EQ_sig); - - Symbols_db = Duobinary().precode(Symbols); - Bits_ = PAMmapper(M,0).demap(Symbols_db); - - [~,num_errors,ber_db,pos_errors] = calc_ber(Rx_bits.signal,Bits_.signal,"skip_front",100,"skip_end",150,"returnErrorLocation",1); - - disp([' DB Precode -> Channel -> FFE -> Decode/ Mod ',sprintf('%.1E',ber_db),' | PD_in: ',num2str(pd_in),' dBm']); - - end elseif db_encode - + [EQ_sig, Noi] = Eq.process(Scpe_sig,Symbols); EQ_sig = MLSE("DIR",[1,1],"duobinary_output",1,"M",M,"trellis_states",PAMmapper(M,0).levels).process(EQ_sig); EQ_sig = Duobinary().decode(EQ_sig); - + elseif postfilter - + [EQ_sig, Noi] = Eq.process(Scpe_sig,Symbols); - % EQ_sig.plot("displayname",'After VNLE','fignum',90,'clear',1); + %%% REMOVE DC peak from Noi PSD + S = Noi.signal; + N1 = 1001; - % Quantization is too far from orig. symbols -> - % error psd is quite different - % Sym_ = PAMmapper(M,0).quantize(EQ_sig); - % Noi_ = Sym_-EQ_sig; - % Noi_.normalize('mode','rms').spectrum('displayname','Noise PSD','fignum',1234,'normalizeTo0dB',1,'normalizeToNyquist',1,'color',cols(nc+1,:)); + % recursion + % Initialize the moving sum for the first window + half_window = (N1 - 1) / 2; + moving_sum = sum(S(1:N1)); - Rx_bits = PAMmapper(M,0).demap(EQ_sig); - [~,~,ber_ffe(i,j),~] = calc_ber(Rx_bits.signal,Bits.signal,"skip_front",100,"skip_end",150,"returnErrorLocation",1); + % Calculate the first element of R1 + S_(1:half_window+1) = S(1:half_window+1) - (moving_sum / N1); - if 1 - figure(55); - clf - title(sprintf('PAM %d ; BER: %1.2e',M, ber_ffe(i,j))); - constellation = unique(Symbols.signal); - received = NaN(numel(constellation),length(Symbols)); - for lvl = 1:numel(constellation) - %Separate the equalized signal into the - %respective levels based on the actually - %transmitted level! - received(lvl,Symbols.signal==constellation(lvl)) = EQ_sig.signal(Symbols.signal==constellation(lvl)); - intermediate = received(lvl,:); - cnt(lvl) = numel(intermediate(~isnan(intermediate))); - hold on - histogram(received(lvl,:),1000,"EdgeAlpha",0,'DisplayName',['Lvl ',num2str(lvl),' | ',num2str(cnt(lvl)),' entries']); - end - legend + % Loop over the signal and apply the recursive moving average subtraction + for n = (half_window+2):(length(S)-half_window) + % Update the moving sum by subtracting the oldest value and adding the new one + moving_sum = moving_sum - S(n-half_window-1) + S(n+half_window); + + % Calculate the new value of R1 + S_(n) = S(n) - (moving_sum / N1); end + S_(n+1:length(S)) = S(n+1:end) - (moving_sum / N1); + Noi.signal = S_; + %%% END REMOVE DC PEAK %%% - - - - - - cols = linspecer(8); - EQ_sig.normalize('mode','rms').spectrum('displayname','EQ Out','fignum',1234,'normalizeTo0dB',1,'normalizeToNyquist',1,'color',cols(nc,:)); - - Noi.normalize('mode','rms').spectrum('displayname','Noise PSD optimal','fignum',1234,'normalizeTo0dB',1,'normalizeToNyquist',1,'color',cols(nc+1,:)); + Rx_bits = PAMmapper(M,0).demap(EQ_sig); + [~,~,ber_vnle(i,j),~] = calc_ber(Rx_bits.signal,Bits.signal,"skip_front",100,"skip_end",150,"returnErrorLocation",1); + + EQ_sig.spectrum('displayname','EQ Out','fignum',12345,'normalizeTo0dB',0,'normalizeToNyquist',0,'color',cols(1,:)); + + + Noi.spectrum('displayname','Noise PSD optimal','fignum',22,'normalizeTo0dB',1,'normalizeToNyquist',0,'color',cols(2,:)); for nc = 1:3 - + burg_coeff = arburg(Noi.signal,nc); - + EQ_sig_filt = EQ_sig.filter(burg_coeff,1); - + % EQ_sig.spectrum("displayname","Signal Spectrum after Postfilter","fignum",1234); - + EQ_sig_mlse = MLSE("DIR",burg_coeff,"duobinary_output",0,"M",M,"trellis_states",PAMmapper(M,0).levels).process(EQ_sig_filt); - + % EQ_sig.spectrum("displayname","Signal Spectrum after MLSE","fignum",1234); - + if 1 + cols = linspecer(12); + % EQ_sig_filt.normalize('mode','rms').spectrum('displayname','Noise PSD','fignum',1234,'normalizeTo0dB',1,'normalizeToNyquist',0,'color',cols(nc+2,:)); - - - EQ_sig_filt.normalize('mode','rms').spectrum('displayname','Noise PSD','fignum',1234,'normalizeTo0dB',1,'normalizeToNyquist',1,'color',cols(nc+2,:)); - - % [h,w] = freqz(1,burg_coeff,length(Noi),"whole",Noi.fs); - % h = h/max(abs(h)); - % hold on - % w_ = (w - Noi.fs/2); - % figure(123) - % plot(w_.*1e-9,20*log10(fftshift(h)),'DisplayName',['', num2str(nc), ' coefficients for burg alg.']); - - [h,w] = freqz(1,burg_coeff,length(Noi),"whole"); + [h,w] = freqz(1,burg_coeff,length(Noi),"whole",Noi.fs); + % h = 1./h; h = h/max(abs(h)); hold on - w_ = (w - pi); - plot(w_,20*log10(fftshift(h)),'DisplayName',['', num2str(nc), ' coefficients for burg alg.']); - + w_ = (w - Noi.fs/2); + figure(22) + plot(w_.*1e-9,20*log10(fftshift(h)),'DisplayName',['', num2str(nc), ' coefficients for burg alg.']); end - + Rx_bits = PAMmapper(M,0).demap(EQ_sig_mlse); [~,errors_bm,ber_mlse(i,j,nc),errors] = calc_ber(Rx_bits.signal,Bits.signal,"skip_front",100,"skip_end",150,"returnErrorLocation",1); % disp(['BER: ',sprintf('%.1E',ber_mlse(i,j)),' - - ROP: ',num2str(patten(i)),'dBm - - PAM-',num2str(M),' - - ',num2str(fsym*1e-9),' GBd']); @@ -341,41 +302,7 @@ for random_key_laser_phase = wh.parameter.random_key_laser_phase.values else - % S = Scpe_sig.signal; - % N1 = 101; - % - % % Initialize the running sum with the first window's sum - % running_sum = mean( S(1:N1) ); - % - % % Calculate the first output value - % S_(1) = S(1) - running_sum; - % - % % Recursive running sum filter - % for n = 2 : length(S) - N1 - % % Update running sum by removing the oldest sample and adding the newest - % avg_win(n) = mean( S(n:n+N1) ); - % S_(n) = S(n) - avg_win(n); - % end - % - % % movmean - % S__ = S - movmean(S,[floor(N1/2),ceil(N1/2)]); - % - % % recursion - % % Initialize the moving sum for the first window - % half_window = (N1 - 1) / 2; - % moving_sum = sum(S(1:N1)); - % - % % Calculate the first element of R1 - % S___(half_window+1) = S(half_window+1) - (moving_sum / N1); - % - % % Loop over the signal and apply the recursive moving average subtraction - % for n = (half_window+2):(length(S)-half_window) - % % Update the moving sum by subtracting the oldest value and adding the new one - % moving_sum = moving_sum - S(n-half_window-1) + S(n+half_window); - % - % % Calculate the new value of R1 - % S___(n) = S(n) - (moving_sum / N1); - % end + [EQ_sig, Noi] = Eq.process(Scpe_sig,Symbols); @@ -384,41 +311,41 @@ for random_key_laser_phase = wh.parameter.random_key_laser_phase.values Noi.spectrum('displayname','Noise PSD','fignum',123,'normalizeTo0dB',1,'normalizeToNyquist',1); EQ_sig.plot("displayname",'After EQ','fignum',1113); end - % + % Rx_bits = PAMmapper(M,0).demap(EQ_sig); [~,errors_bm,ber_vnle(i,j),errors] = calc_ber(Rx_bits.signal,Bits.signal,"skip_front",100,"skip_end",150,"returnErrorLocation",1); end - - - + + + end - - end - - for j = 1:j_ - sir = wh.parameter.sir.values(j); - for i = 1:i_ - rop=wh.parameter.rop.values(i); - - wh.addValueToStorage(ber_vnle(i,j),'ber_vnle',M,datarate,rop,sir,random_key_laser_phase); - wh.addValueToStorage(ber_mlse(i,j,:),'ber_mlse',M,datarate,rop,sir,random_key_laser_phase); - - end - end - - toc - - % wh.save('C:\Users\Silas\Documents\MATLAB\imdd_simulation\projects\MPI_August\auswertung\') - + end + + for j = 1:j_ + sir = wh.parameter.sir.values(j); + for i = 1:i_ + rop=wh.parameter.rop.values(i); + + wh.addValueToStorage(ber_vnle(i,j),'ber_vnle',M,datarate,rop,sir,random_key_laser_phase); + wh.addValueToStorage(ber_mlse(i,j,:),'ber_mlse',M,datarate,rop,sir,random_key_laser_phase); + + end + end + + toc + + % wh.save('C:\Users\Silas\Documents\MATLAB\imdd_simulation\projects\MPI_August\auswertung\') + end end +end disp('Simulation Done!') - + ber_mlse=[]; ber_vnle=[]; cols = linspecer(8); @@ -434,16 +361,16 @@ ber_mlse=squeeze(mean(ber_mlse,1)); ber_vnle = mean(ber_vnle,1); % Create the initial plot -figure(44); +figure(466); a = gca; hold on; % Retain the plot so new points can be added without complete redraw dispname = ['Lw: ',num2str(laser_linewidth.*1e-6),' MHz']; - -plot(wh.parameter.sir.values,ber_vnle,"LineWidth",0.5,"LineStyle","-","Marker",".","MarkerSize",15,"DisplayName",['VNLE ',dispname]); -plot(wh.parameter.sir.values,ber_mlse(:,1),"LineWidth",0.5,"LineStyle","-","Marker",".","MarkerSize",15,"DisplayName",['MLSE 1 ',dispname]); -plot(wh.parameter.sir.values,ber_mlse(:,2),"LineWidth",0.5,"LineStyle","-","Marker",".","MarkerSize",15,"DisplayName",['MLSE 2',dispname]); -plot(wh.parameter.sir.values,ber_mlse(:,3),"LineWidth",0.5,"LineStyle","-","Marker",".","MarkerSize",15,"DisplayName",['MLSE 3',dispname]); +cols = linspecer(6); +plot(wh.parameter.sir.values,ber_vnle,"LineWidth",0.5,"LineStyle","--","Marker",".","MarkerSize",15,"DisplayName",['PAM',num2str(M),' VNLE ',dispname],'Color',cols(1,:)); +plot(wh.parameter.sir.values,ber_mlse(:,1),"LineWidth",0.5,"LineStyle","--","Marker",".","MarkerSize",15,"DisplayName",['PAM',num2str(M),'MLSE 1 ',dispname],'Color',cols(2,:)); +plot(wh.parameter.sir.values,ber_mlse(:,2),"LineWidth",0.5,"LineStyle","--","Marker",".","MarkerSize",15,"DisplayName",['PAM',num2str(M),'MLSE 2',dispname],'Color',cols(3,:)); +plot(wh.parameter.sir.values,ber_mlse(:,3),"LineWidth",0.5,"LineStyle","--","Marker",".","MarkerSize",15,"DisplayName",['PAM',num2str(M),'MLSE 3',dispname],'Color',cols(4,:)); yline(3.8e-3,'DisplayName','HD-FEC','LineStyle','--','HandleVisibility','off'); xlabel('Received Optical Power (dBm)'); diff --git a/projects/HighSpeedExperiment_2024/analysis_script.m b/projects/HighSpeedExperiment_2024/analysis_script.m new file mode 100644 index 0000000..5f677a7 --- /dev/null +++ b/projects/HighSpeedExperiment_2024/analysis_script.m @@ -0,0 +1,84 @@ + +% cleanup measurement data +% remove fots from files +% merge measurments into database + + +if 1 + +folderPath = "/Volumes/NT-Labor/2024/sioe/High Speed Messungen Oktober/mpi_measurement"; + +% Get list of all files in the folder and subfolders +fileList = dir(fullfile(folderPath, '**', '*')); + + +% Loop through each file +big_wh_list = {}; +small_wh_list = {}; + +for i = 1:length(fileList) + + fileName = fileList(i).name; + iswh = strfind(fileName, 'wh'); + if ~isempty(iswh) + + wh = load(fullfile(fileList(i).folder, fileName)); + wh = wh.obj; + + if isa(wh,'DataStorage') + if prod(wh.dim) > 2 + big_wh_list{end+1} = wh; + + else + small_wh_list{end+1} = wh; + end + end + end +end +end + +%%% merge MPI structs by copying the values %%% +params.M = [4,6,8]; +params.bitrate = [224,336,448].*1e9; +params.duobinary = [0,1]; +params.interference_atten = [0 3 6 9 12 15 18 21 24 27 30 45]; +wh_new=DataStorage(params); + + +for w = 1:numel(big_wh_list) + wh = big_wh_list{w}; + for m = wh.parameter.M.values + for br = wh.parameter.bitrate.values + for db = wh.parameter.duobinary.values + for iatten = wh.parameter.interference_atten.values + + storage_names = fieldnames(wh.sto); + for i = 1:length(storage_names) + + %get two things: + %1) current data storage name + cur_storage = storage_names{i}; + %2) the value saved at this storage and dimension + value = wh.getStoValue(cur_storage,m,br,db,iatten); + + % check if storage name already exists, if not + % .addStorgae(...) + if ~isfield(wh_new.sto,cur_storage) + wh_new.addStorage(cur_storage); + end + + + if isempty(wh_new.getStoValue(cur_storage,m,br,db,iatten)) + % Finally, add the value to the repsective storage + wh_new.addValueToStorage(value,cur_storage,m,br,db,iatten); + else + warning('double vaue?') + end + + end + + end + end + end + end +end \ No newline at end of file diff --git a/projects/HighSpeedExperiment_2024/auswertung/App/Block_Diagram.svg b/projects/HighSpeedExperiment_2024/auswertung/App/Block_Diagram.svg new file mode 100644 index 0000000..202800c --- /dev/null +++ b/projects/HighSpeedExperiment_2024/auswertung/App/Block_Diagram.svg @@ -0,0 +1,150 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + AWG + + + + + + + + + + + + + + + + + + + + + + P + + + launch + + + + + + + + + + + + + + PD + + + in + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + RTO + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/projects/HighSpeedExperiment_2024/auswertung/App/auswertungs_app.mlapp b/projects/HighSpeedExperiment_2024/auswertung/App/auswertungs_app.mlapp new file mode 100644 index 0000000..375605d Binary files /dev/null and b/projects/HighSpeedExperiment_2024/auswertung/App/auswertungs_app.mlapp differ diff --git a/projects/HighSpeedExperiment_2024/auswertung/App/database_24dp_E8EAED_FILL0_wght400_GRAD0_opsz24.svg b/projects/HighSpeedExperiment_2024/auswertung/App/database_24dp_E8EAED_FILL0_wght400_GRAD0_opsz24.svg new file mode 100644 index 0000000..e1dfb1c --- /dev/null +++ b/projects/HighSpeedExperiment_2024/auswertung/App/database_24dp_E8EAED_FILL0_wght400_GRAD0_opsz24.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/projects/HighSpeedExperiment_2024/auswertung/App/query_stats_24dp_E8EAED_FILL0_wght400_GRAD0_opsz24.svg b/projects/HighSpeedExperiment_2024/auswertung/App/query_stats_24dp_E8EAED_FILL0_wght400_GRAD0_opsz24.svg new file mode 100644 index 0000000..93430ca --- /dev/null +++ b/projects/HighSpeedExperiment_2024/auswertung/App/query_stats_24dp_E8EAED_FILL0_wght400_GRAD0_opsz24.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/projects/HighSpeedExperiment_2024/auswertung/App/table_convert_24dp_E8EAED_FILL0_wght400_GRAD0_opsz24.svg b/projects/HighSpeedExperiment_2024/auswertung/App/table_convert_24dp_E8EAED_FILL0_wght400_GRAD0_opsz24.svg new file mode 100644 index 0000000..a94012f --- /dev/null +++ b/projects/HighSpeedExperiment_2024/auswertung/App/table_convert_24dp_E8EAED_FILL0_wght400_GRAD0_opsz24.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/projects/HighSpeedExperiment_2024/auswertung/analyzeDB_shortened.m b/projects/HighSpeedExperiment_2024/auswertung/analyzeDB_shortened.m new file mode 100644 index 0000000..3480251 --- /dev/null +++ b/projects/HighSpeedExperiment_2024/auswertung/analyzeDB_shortened.m @@ -0,0 +1,137 @@ +basePath = 'C:\Users\Silas\Documents\MATLAB\Datensätze\sioe_labor\'; +useGui = 0; +pamlvls = [4, 6, 8]; +wlengths = [1310]; +db = DBHandler("pathToDB", [basePath, 'silas_labor.db']); + +for w = 1:numel(wlengths) + for p = 1:numel(pamlvls) + % Load data from database + joinedData = loadDataFromDB(db, pamlvls(p), wlengths(w), useGui); + + % Plot filtered data + figure(pamlvls(p)); + hold on; + plotFilteredData(joinedData, wlengths(w)); + % Continue with the rest of your plot settings + finalizePlot(); + end +end + + +% Custom function to load data from database +function joinedData = loadDataFromDB(db, pamlvl, wlength, useGui) + if useGui + filterParams = db.promptFilterParameters(); + selectedFields = db.promptSelectFields(); + else + filterParams = db.tables; + filterParams.Configurations = struct( ... + 'bitrate', [], 'db_mode', [], 'fiber_length', 1, ... + 'interference_attenuation', [], 'interference_path_length', [], ... + 'is_mpi', 0, 'pam_level', pamlvl, 'precomp_amp', [], ... + 'rop_attenuation', 0, 'symbolrate', [], 'v_awg', [], 'v_bias', [], ... + 'wavelength', wlength ... + ); + + selectedFields = {'Runs.run_id', 'BERs.ber_id', 'Equalizer.eq_id', 'Equalizer.eq_type', 'BERs.ber', 'BERs.occurrence', ... + 'Configurations.db_mode', 'Configurations.pam_level', 'Configurations.bitrate', 'Configurations.symbolrate', ... + 'Configurations.fiber_length', 'Configurations.wavelength', 'Configurations.precomp_amp', ... + 'Measurements.power_rop', 'Measurements.power_laser', 'Measurements.power_pd_in'}; + end + + % Get data table from DB + [dataTable, ~] = db.queryDB(filterParams, selectedFields); + + % Extract unique rows for each run_id + uniqueConfigFields = {'run_id', 'pam_level', 'bitrate', 'symbolrate', 'fiber_length', 'wavelength', 'precomp_amp', 'db_mode'}; + [~, uniqueIdx] = unique(dataTable.run_id); + configDetails = dataTable(uniqueIdx, uniqueConfigFields); + + % Calculate the mean BER for each combination of 'run_id' and 'eq_type' + groupedData = groupsummary(dataTable, {'run_id', 'eq_type'}, {'mean', 'min', @(x) meanExcludingOutliers(x)}, {'ber', 'power_rop', 'power_pd_in'}); + + % Join groupedData with configDetails on the run_id field + joinedData = join(groupedData, configDetails, 'Keys', 'run_id'); +end + +% Custom function to plot filtered data +function plotFilteredData(joinedData, wlength) + filterFields = {'eq_type'}; + cols = linspecer(8); + lst = ["-", ":", "--"]; + + % Loop over each field you want to filter by + for f = 1:numel(filterFields) + currentField = filterFields{f}; + uniqueValues = unique(joinedData.(currentField)); + + for i = 1:numel(uniqueValues) + currentValue = uniqueValues(i); + + % Filter joinedData for the current value + if isnumeric(currentValue) + filteredData = joinedData(joinedData.(currentField) == currentValue, :); + else + filteredData = joinedData(strcmp(joinedData.(currentField), currentValue), :); + end + + % Group and average BERs of several run ids => repeated measurements in lab! + groupVars = {'bitrate'}; + groupedDataWithMeans = groupsummary(filteredData, groupVars, {'mean', 'min'}, {'mean_ber', 'min_ber', 'fun1_ber', 'mean_power_rop', 'mean_power_pd_in'}); + [~, uniqueIdx] = unique(filteredData.bitrate); + constantFields = filteredData(uniqueIdx, {'bitrate', 'GroupCount', 'pam_level', 'symbolrate', 'fiber_length', 'wavelength', 'precomp_amp', 'db_mode'}); + groupedRunIDs = varfun(@(x) {unique(x)}, filteredData, 'GroupingVariables', groupVars, 'InputVariables', 'run_id'); + groupedRunIDs.Properties.VariableNames(end) = {'GroupedRunIDs'}; + groupedDataWithMeans = join(groupedDataWithMeans, constantFields, 'Keys', 'bitrate'); + groupedDataWithMeans = join(groupedDataWithMeans, groupedRunIDs, 'Keys', 'bitrate'); + filteredData = groupedDataWithMeans; + + % Plotting + a = plot(filteredData.bitrate .* 1e-9, filteredData.mean_fun1_ber, ... + 'Color', cols(i, :), 'MarkerSize', 4, 'LineWidth', 1, 'LineStyle', lst(mod(wlength - 1, numel(lst)) + 1), ... + 'Marker', 'o', 'MarkerFaceColor', 'auto', 'MarkerEdgeColor', cols(i, :), ... + 'DisplayName', [char(currentValue), '; ', num2str(wlength), ' nm']); + + a.DataTipTemplate.DataTipRows(1).Label = 'Bitrate'; + a.DataTipTemplate.DataTipRows(1).Format = ['%.1f', ' Gbit/s']; + a.DataTipTemplate.DataTipRows(2).Label = 'BER'; + a.DataTipTemplate.DataTipRows(2).Format = '%.1e'; + a.DataTipTemplate.DataTipRows(3).Label = 'P_{out}'; + a.DataTipTemplate.DataTipRows(3).Value = filteredData.mean_mean_power_rop; + a.DataTipTemplate.DataTipRows(3).Format = ['%.2f', ' dBm']; + a.DataTipTemplate.DataTipRows(4).Label = 'Baudr'; + a.DataTipTemplate.DataTipRows(4).Value = filteredData.bitrate .* 1e-9; + a.DataTipTemplate.DataTipRows(4).Format = ['%.1f', ' GBd']; + a.DataTipTemplate.DataTipRows(5).Label = 'Run ID'; + a.DataTipTemplate.DataTipRows(5).Value = filteredData.GroupedRunIDs; + a.DataTipTemplate.FontSize = 9; + a.DataTipTemplate.FontName = 'arial'; + end + end +end + +% Custom function to finalize the plot settings +function finalizePlot() + yline(2e-2, 'DisplayName', '20% O-FEC', 'LineStyle', '--', 'HandleVisibility', 'off'); + yline(3.8e-3, 'DisplayName', 'HD-FEC', 'LineStyle', '--', 'HandleVisibility', 'off'); + xlabel('Bit Rate in GBps'); + ylabel('Bit Error Rate (BER)'); + xlim([300, 480]); + set(gca, 'yscale', 'log'); + set(gca, 'Box', 'on'); + grid on; + grid minor; + legend('Interpreter', 'none'); +end + +% Custom function using rmoutliers to calculate mean after removing outliers +function meanWithoutOutliers = meanExcludingOutliers(x) + [xWithoutOutliers,outlierpos] = rmoutliers(x); + if isempty(xWithoutOutliers) + meanWithoutOutliers = NaN; + else + meanWithoutOutliers = mean(xWithoutOutliers); + end + +end diff --git a/projects/HighSpeedExperiment_2024/auswertung/analyze_mu_dc.m b/projects/HighSpeedExperiment_2024/auswertung/analyze_mu_dc.m new file mode 100644 index 0000000..ce35867 --- /dev/null +++ b/projects/HighSpeedExperiment_2024/auswertung/analyze_mu_dc.m @@ -0,0 +1,89 @@ + + +if 0 + uloops = struct; + uloops.precomp = [0,1]; + uloops.db_precode = [0,1]; + uloops.bitrate = [300,330,360,390,420,450,480].*1e9; %[300,330,360,390,420,450,480] + uloops.laser_wavelength = [1293,1302,1310,1318,1327.4]; + uloops.M = [4,6,8]; + uloops.link_length = [2]; % 1,2,3,5,6,8,10 + wh = DataStorage(uloops); + wh.addStorage("ber"); + wh = submit_simulations(wh,"parallel",1,"simulation_mode",0); + save('wh_2km',"wh"); +end + + + +for wavelength = wh.parameter.laser_wavelength.values + + cols = linspecer(6);%cbrewer2('Set2',10); + figcnt = 0; + figWidth = 21; % Full-width for IEEE double-column papers (~7 inches) + figHeight = 6; % Adjust height as needed (~3.5 inches) + figure('Units','centimeters','Position', [1 1 figWidth figHeight],'PaperUnits','centimeters','PaperPosition', [0 0 figWidth figHeight]) + tiledlayout(1,3, 'Padding', 'compact', 'TileSpacing', 'compact'); + for m = uloops.M + + + + figcnt = figcnt+1; + % subplot(1,3,figcnt) + nexttile + hold on + title(sprintf('%d km | %d nm | PAM %d',uloops.link_length,wavelength,m)); + + precomp = 1; + db_precode = 0; + a = wh.getStoValue('ber',precomp, db_precode, uloops.bitrate , wavelength, m, uloops.link_length); + ber_vnle = cellfun(@(x) x.vnle_pf_package{1,1}.ber_vnle, a); + ber_vnle_cell = cellfun(@(s) cellfun(@(p) p.ber_vnle, s.vnle_pf_package, 'UniformOutput', true), a, 'UniformOutput', false); + ber_vnle_best = cellfun(@(c) min(c), ber_vnle_cell); + plot(uloops.bitrate.*1e-9,ber_vnle_best,'DisplayName',sprintf('Tx precomp + VNLE'),'Color',cols(3,:),'LineStyle','-','HandleVisibility','on'); + xticks(uloops.bitrate.*1e-9); + xlim([min(uloops.bitrate.*1e-9) max(uloops.bitrate.*1e-9)]); + + precomp = 0; %0 + db_precode = 1; + a = wh.getStoValue('ber',precomp, db_precode, uloops.bitrate , wavelength, m, uloops.link_length); + % ber_db = cellfun(@(x) x.dbtgt_package{1,1}.ber, a); + ber_db_cell = cellfun(@(s) cellfun(@(p) p.ber, s.dbtgt_package, 'UniformOutput', true), a, 'UniformOutput', false); + ber_db_best = cellfun(@(c) min(c), ber_db_cell); + plot(uloops.bitrate.*1e-9,ber_db_best,'DisplayName',sprintf('DB tgt. + MLSE',uloops.link_length,uloops.M),'Color',cols(1,:),'LineStyle','-','HandleVisibility','on'); + xticks(uloops.bitrate.*1e-9); + xlim([min(uloops.bitrate.*1e-9) max(uloops.bitrate.*1e-9)]); + + precomp = 0; %0 + db_precode = 0; %1 + a = wh.getStoValue('ber',precomp, db_precode, uloops.bitrate , wavelength, m, uloops.link_length); + % ber_mlse = cellfun(@(x) x.vnle_pf_package{1,1}.ber_mlse, a); + ber_mlse_cell = cellfun(@(s) cellfun(@(p) p.ber_mlse, s.vnle_pf_package, 'UniformOutput', true), a, 'UniformOutput', false); + ber_mlse_best = cellfun(@(c) min(c), ber_mlse_cell); + plot(uloops.bitrate.*1e-9,ber_mlse_best,'DisplayName',sprintf('VNLE + 1 tap post-filter + MLSE',uloops.link_length,uloops.M),'Color',cols(4,:),'LineStyle','-','HandleVisibility','on'); + xticks(uloops.bitrate.*1e-9); + xlim([min(uloops.bitrate.*1e-9) max(uloops.bitrate.*1e-9)]); + + set(gca, 'YScale', 'log'); + ylim([8e-5 0.3]); + yline([4.8e-3, 2e-2],'HandleVisibility','off','LineWidth',1,'LineStyle','--','Color',[0.1 0.1 0.1]); + % legend + beautifyBERplot() + xlabel('Bit Rate in Gbps'); + ylabel('BER'); + + if m ==4 + text(310,6.8e-3,"4.8e-3","FontSize",10,"Interpreter","latex") + text(310,3e-2,"2e-2","FontSize",10,"Interpreter","latex") + end + + % text(0.5,1,sprintf('%d km %d nm PAM %d',uloops.link_length,wavelength,m),... + % 'Units', 'normalized',"FontSize",10,"Interpreter","latex","BackgroundColor",[1 1 1],"EdgeColor",[0 0 0],'HorizontalAlignment','center','VerticalAlignment','top') + end + + lgd = legend; + % Place the legend underneath the tiled layout + lgd.NumColumns = 3; + lgd.Layout.Tile = 'south'; + +end \ No newline at end of file diff --git a/projects/HighSpeedExperiment_2024/auswertung/ber_vs_bitrate.m b/projects/HighSpeedExperiment_2024/auswertung/ber_vs_bitrate.m new file mode 100644 index 0000000..ce23d75 --- /dev/null +++ b/projects/HighSpeedExperiment_2024/auswertung/ber_vs_bitrate.m @@ -0,0 +1,170 @@ +basePath = 'C:\Users\Silas\Documents\MATLAB\Datensätze\sioe_labor\'; +useGui = 0; +pamlvls = [4,6,8]; +wlengths = [1302]; +figoffset = 0; + +figure(30) +tiledlayout(1, 3, 'TileSpacing', 'compact', 'Padding', 'compact'); + +for p = 1:numel(pamlvls) + nexttile; + + for w = 1:numel(wlengths) + sgtitle(['Lambda: ',num2str(wlengths),' nm']) + + hold on + pamlvl = pamlvls(p); + wlength = wlengths(w); + db = DBHandler("pathToDB",[basePath,'silas_labor.db']); + if useGui + filterParams = db.promptFilterParameters(); + selectedFields = db.promptSelectFields(); + else + filterParams = db.tables; + filterParams.Configurations = struct( ... + 'bitrate', [], ... + 'db_mode', [], ... + 'fiber_length', 10, ... + 'interference_attenuation', [], ... + 'interference_path_length', [], ... + 'is_mpi', 0, ... + 'pam_level', pamlvl, ... + 'precomp_amp', [], ... + 'rop_attenuation', 0, ... + 'symbolrate', [], ... + 'v_awg', [], ... + 'v_bias', [], ... + 'wavelength', wlength ... + ); + + selectedFields = {'Runs.run_id','BERs.ber_id','Equalizer.eq_id','Equalizer.eq_type','BERs.ber','BERs.occurrence',... + 'Configurations.db_mode','Configurations.pam_level','Configurations.bitrate','Configurations.symbolrate','Configurations.fiber_length','Configurations.wavelength','Configurations.precomp_amp',... + 'Measurements.power_rop','Measurements.power_laser','Measurements.power_pd_in'}; + end + + % Get data table from DB + [dataTable,~] = db.queryDB(filterParams, selectedFields); + + % Grouping variables: 'bitrate' and 'eq_type' + groupVars = {'bitrate', 'eq_type'}; + + % Calculate mean BER for each combination of 'bitrate' and 'eq_type' + groupedData = groupsummary(dataTable, groupVars, {'mean', 'min', @(x) meanExcludingOutliers(x)}, {'ber', 'power_rop','power_pd_in'}); + + % Collect the run_id values for each group + groupedRunIDs = varfun(@(x) {unique(x)}, dataTable, 'GroupingVariables', groupVars, 'InputVariables', 'run_id'); + groupedRunIDs.Properties.VariableNames(end) = {'GroupedRunIDs'}; + + % Join the grouped data with the grouped run_id list + avgdBerTable = join(groupedData, groupedRunIDs, 'Keys', groupVars); + + % Define the fields that you want to use for filtering + filterFields = {'eq_type'}; + + % Loop over each field you want to filter by + for f = 1:numel(filterFields) + currentField = filterFields{f}; + + % Determine unique values for the current field + uniqueValues = unique(avgdBerTable.(currentField)); + + % Loop over each unique value for the current field + for i = 1:numel(uniqueValues) + currentValue = uniqueValues(i); + + % Filter joinedData for the current value + if isnumeric(currentValue) + filteredData = avgdBerTable(avgdBerTable.(currentField) == currentValue, :); + else + filteredData = avgdBerTable(strcmp(avgdBerTable.(currentField), currentValue), :); + end + + cols = linspecer(8); + + lst = ["-",":","--"]; + a=plot(filteredData.bitrate.*1e-9,filteredData.min_ber,... + 'Color',cols(i,:),'MarkerSize',4,'LineWidth',1,'LineStyle',lst(w),... + 'Marker','o','MarkerFaceColor','auto','MarkerEdgeColor',cols(i,:),... + 'DisplayName',[char(currentValue),'; ',num2str(wlength),' nm' ]); + a.DataTipTemplate.DataTipRows(1).Label = 'Bitrate'; + a.DataTipTemplate.DataTipRows(1).Format = ['%.1f',' Gbit/s']; + + a.DataTipTemplate.DataTipRows(2).Label = 'BER'; + a.DataTipTemplate.DataTipRows(2).Format ='%.1e'; + + a.DataTipTemplate.DataTipRows(3).Label = 'P_{out}'; + a.DataTipTemplate.DataTipRows(3).Value = filteredData.mean_power_rop; + a.DataTipTemplate.DataTipRows(3).Format = ['%.2f',' dBm']; + + a.DataTipTemplate.DataTipRows(4).Label = 'Run ID'; + a.DataTipTemplate.DataTipRows(4).Value = filteredData.GroupedRunIDs; + a.DataTipTemplate.DataTipRows(4).Format = ['%d',' ']; + + + a.DataTipTemplate.FontSize = 9; + a.DataTipTemplate.FontName = 'arial'; + % + % a=scatter(filteredData.bitrate.*1e-9,filteredData.min_ber,5,'Marker','diamond',... + % 'Color',cols(i,:),'LineWidth',1,... + % 'MarkerFaceColor','auto','MarkerEdgeColor',cols(i,:),... + % 'DisplayName',currentValue); + % + % a.DataTipTemplate.DataTipRows(1).Label = 'Bitrate'; + % a.DataTipTemplate.DataTipRows(1).Format = ['%.1f',' Gbit/s']; + % + % a.DataTipTemplate.DataTipRows(2).Label = 'BER'; + % a.DataTipTemplate.DataTipRows(2).Format ='%.1e'; + % + % a.DataTipTemplate.DataTipRows(3).Label = 'P_{out}'; + % a.DataTipTemplate.DataTipRows(3).Value = filteredData.mean_power_rop; + % a.DataTipTemplate.DataTipRows(3).Format = ['%.2f',' dBm']; + % + % a.DataTipTemplate.DataTipRows(4).Label = 'Run ID'; + % a.DataTipTemplate.DataTipRows(4).Value = filteredData.GroupedRunIDs; + % a.DataTipTemplate.DataTipRows(4).Format = ['%d',' ']; + % + % + % a.DataTipTemplate.FontSize = 9; + % a.DataTipTemplate.FontName = 'arial'; + + + + + end + end + + + + % Continue with the rest of your plot settings + title(sprintf('%d km | %d nm | PAM %d',unique(filterParams.Configurations.fiber_length),wlength,pamlvl)); + yline(2e-2, 'DisplayName', '20% O-FEC', 'LineStyle', '--', 'HandleVisibility', 'off','LineWidth',1); + yline(3.8e-3, 'DisplayName', 'HD-FEC', 'LineStyle', '--', 'HandleVisibility', 'off','LineWidth',1); + xlabel('Bit Rate in Gbps'); + ylabel('Bit Error Rate'); + xlim([300, 480]) + ylim([8e-4,0.5]) + set(gca, 'yscale', 'log'); + set(gca, 'Box', 'on'); + grid on; + grid minor; + + + end +end +legend('Interpreter', 'none'); +set(gcf, 'Units', 'pixels', 'Position', 1.0e+03 * [0.2483 0.7303 1.2093 0.3980]); + +% Custom function using rmoutliers to calculate mean after removing outliers +function meanWithoutOutliers = meanExcludingOutliers(x) +% Remove outliers using rmoutliers with default method (based on median) +xWithoutOutliers = rmoutliers(x); + +% Calculate the mean of the non-outliers +if isempty(xWithoutOutliers) + % Handle the case where all values are outliers + meanWithoutOutliers = NaN; +else + meanWithoutOutliers = mean(xWithoutOutliers); +end +end \ No newline at end of file diff --git a/projects/HighSpeedExperiment_2024/auswertung/ber_vs_length.m b/projects/HighSpeedExperiment_2024/auswertung/ber_vs_length.m new file mode 100644 index 0000000..bd7032b --- /dev/null +++ b/projects/HighSpeedExperiment_2024/auswertung/ber_vs_length.m @@ -0,0 +1,192 @@ +basePath = 'C:\Users\Silas\Documents\MATLAB\Datensätze\sioe_labor\'; +useGui = 0; +pamlvls = [6]; +wlengths = [1293,1302,1310];%db.distinctValues.Configurations.wavelength +figoffset = 20; + +figure(21) +tiledlayout(1, 3, 'TileSpacing', 'compact', 'Padding', 'compact'); + + +for w = 1:numel(wlengths) + nexttile; + for p = 1:numel(pamlvls) + pamlvl = pamlvls(p); + wlength = wlengths(w); + db = DBHandler("pathToDB",[basePath,'silas_labor.db']); + if useGui + filterParams = db.promptFilterParameters(); + selectedFields = db.promptSelectFields(); + else + filterParams = db.tables; + filterParams.Configurations = struct( ... + 'bitrate', 420e9, ... + 'db_mode', [], ... + 'fiber_length', [], ... + 'interference_attenuation', [], ... + 'interference_path_length', [], ... + 'is_mpi', 0, ... + 'pam_level', pamlvl, ... + 'precomp_amp', [], ... + 'rop_attenuation', 0, ... + 'symbolrate', [], ... + 'v_awg', [], ... + 'v_bias', [], ... + 'wavelength', wlength ... + ); + % filterParams.Equalizer.eq_type = equalizer_structure.vnle; + + selectedFields = {'Runs.run_id','BERs.ber_id','Equalizer.eq_id','Equalizer.eq_type','BERs.ber','BERs.occurrence',... + 'Configurations.db_mode','Configurations.pam_level','Configurations.bitrate','Configurations.symbolrate','Configurations.fiber_length','Configurations.wavelength','Configurations.precomp_amp',... + 'Measurements.power_rop','Measurements.power_laser','Measurements.power_pd_in'}; + end + sgtitle(['Rate: ',num2str(filterParams.Configurations.bitrate),' Gbit/s']) + % Get data table from DB + [dataTable,~] = db.queryDB(filterParams, selectedFields); + + % Extract unique rows from dataTable for each run_id with relevant configuration details + uniqueConfigFields = {'run_id', 'pam_level', 'bitrate','symbolrate', 'fiber_length', 'wavelength', 'precomp_amp', 'db_mode'}; + [~, uniqueIdx] = unique(dataTable.run_id); % Get unique run_id indices + configDetails = dataTable(uniqueIdx, uniqueConfigFields); % Extract unique configurations for each run_id + + % Calculate the mean BER for each combination of 'run_id' and 'eq_type' + groupedData = groupsummary(dataTable, {'run_id', 'eq_type'}, {'mean','min'}, {'ber', 'power_rop','power_pd_in'}); + groupedData = groupsummary(dataTable, {'run_id', 'eq_type'}, {'mean', 'min', @(x) meanExcludingOutliers(x)}, {'ber', 'power_rop','power_pd_in'}); + + % Join groupedData with configDetails on the run_id field + joinedData = join(groupedData, configDetails, 'Keys', 'run_id'); + + + % Define the fields that you want to use for filtering + filterFields = {'eq_type'}; + + % Create a cell array to store filtered data tables for each filter field + filteredDataByField = struct(); + + hold on + % Loop over each field you want to filter by + for f = 1:numel(filterFields) + currentField = filterFields{f}; + + % Determine unique values for the current field + uniqueValues = unique(joinedData.(currentField)); + + % Create a struct entry for the current field + filteredDataByField.(currentField) = cell(numel(uniqueValues), 1); + + % Loop over each unique value for the current field + for i = 1:numel(uniqueValues) + currentValue = uniqueValues(i); + + % Filter joinedData for the current value + if isnumeric(currentValue) + filteredData = joinedData(joinedData.(currentField) == currentValue, :); + else + filteredData = joinedData(strcmp(joinedData.(currentField), currentValue), :); + end + + %%% workaround to average the BERs of several runs (ie in 1km case or trials) + %%% Workaround to average the BERs of several runs (e.g., in 1 km case or trials) + + % Grouping variable(s) + groupVars = {'fiber_length'}; + + % Use groupsummary to calculate the mean and min of relevant fields + groupedDataWithMeans = groupsummary(filteredData, groupVars, {'mean', 'min'}, {'mean_ber', 'min_ber', 'fun1_ber', 'mean_power_rop', 'mean_power_pd_in'}); + + % Extract representative values for constant fields + [~, uniqueIdx] = unique(filteredData.(groupVars{1})); % Get the first occurrence of each bitrate value + constantFields = filteredData(uniqueIdx, {'bitrate', 'GroupCount', 'pam_level', 'symbolrate', 'fiber_length', 'wavelength', 'precomp_amp', 'db_mode'}); + + % Keep track of which run_id values were grouped + groupedRunIDs = varfun(@(x) {unique(x)}, filteredData, 'GroupingVariables', groupVars, 'InputVariables', 'run_id'); + groupedRunIDs.Properties.VariableNames(end) = {'GroupedRunIDs'}; + + % Join the grouped data with the constant fields + groupedDataWithMeans = join(groupedDataWithMeans, constantFields, 'Keys', groupVars); + + % Join the grouped data with the grouped run_id list + groupedDataWithMeans = join(groupedDataWithMeans, groupedRunIDs, 'Keys', groupVars); + + % Update filteredData to include the grouped information + filteredData = groupedDataWithMeans; + %%% end of workaround + + + + cols = linspecer(8); + % a=plot(filteredData.bitrate.*1e-9,filteredData.mean_mean_ber,... + % 'Color',cols(i,:),'MarkerSize',4,'LineWidth',1,'LineStyle',':',... + % 'Marker','o','MarkerFaceColor','auto','MarkerEdgeColor',cols(i,:),... + % 'DisplayName',currentValue); + + lst = ["-",":","--"]; + a=plot(filteredData.(groupVars{1}),filteredData.mean_fun1_ber,... + 'Color',cols(i,:),'MarkerSize',4,'LineWidth',1,'LineStyle',lst(1),... + 'Marker','o','MarkerFaceColor','auto','MarkerEdgeColor',cols(i,:),... + 'DisplayName',[char(currentValue),'; ',num2str(wlength),' nm' ]); + % + % scatter(filteredData.symbolrate.*1e-9,filteredData.min_min_ber,5,'Marker','_',... + % 'Color',cols(i,:),'LineWidth',1,... + % 'MarkerFaceColor',cols(i,:),'MarkerEdgeColor','black',... + % 'DisplayName',currentValue); + + a.DataTipTemplate.DataTipRows(1).Label = groupVars{1}; + a.DataTipTemplate.DataTipRows(1).Format = ['%.1f','']; + + a.DataTipTemplate.DataTipRows(2).Label = 'BER'; + a.DataTipTemplate.DataTipRows(2).Format ='%.1e'; + + a.DataTipTemplate.DataTipRows(3).Label = 'P_{out}'; + a.DataTipTemplate.DataTipRows(3).Value = filteredData.mean_mean_power_rop; + a.DataTipTemplate.DataTipRows(3).Format = ['%.2f',' dBm']; + + a.DataTipTemplate.DataTipRows(4).Label = 'Baudr'; + a.DataTipTemplate.DataTipRows(4).Value = filteredData.bitrate .*1e-9; + a.DataTipTemplate.DataTipRows(4).Format = ['%.1f',' GBd']; + + a.DataTipTemplate.DataTipRows(5).Label = 'Run ID'; + a.DataTipTemplate.DataTipRows(5).Value = filteredData.GroupedRunIDs; + a.DataTipTemplate.DataTipRows(5).Format = ['%f',' GBd']; + + + a.DataTipTemplate.FontSize = 9; + a.DataTipTemplate.FontName = 'arial'; + + end + end + + + + % Continue with the rest of your plot settings + title(sprintf('Lambda: %f',wlength)); + yline(2e-2, 'DisplayName', '20% O-FEC', 'LineStyle', '--', 'HandleVisibility', 'off'); + yline(3.8e-3, 'DisplayName', 'HD-FEC', 'LineStyle', '--', 'HandleVisibility', 'off'); + xlabel(groupVars{1},'Interpreter','none'); + ylabel('Bit Error Rate (BER)'); + %xlim([300, 480]) + ylim([8e-4,0.5]) + set(gca, 'yscale', 'log'); + set(gca, 'Box', 'on'); + grid on; + grid minor; + legend('Interpreter', 'none'); + + + + end +end + +% Custom function using rmoutliers to calculate mean after removing outliers +function meanWithoutOutliers = meanExcludingOutliers(x) +% Remove outliers using rmoutliers with default method (based on median) +xWithoutOutliers = rmoutliers(x); + +% Calculate the mean of the non-outliers +if isempty(xWithoutOutliers) + % Handle the case where all values are outliers + meanWithoutOutliers = NaN; +else + meanWithoutOutliers = mean(xWithoutOutliers); +end +end \ No newline at end of file diff --git a/projects/HighSpeedExperiment_2024/auswertung/buildDBfromMeasurements.m b/projects/HighSpeedExperiment_2024/auswertung/buildDBfromMeasurements.m new file mode 100644 index 0000000..152a37a --- /dev/null +++ b/projects/HighSpeedExperiment_2024/auswertung/buildDBfromMeasurements.m @@ -0,0 +1,554 @@ +% Connect to SQLite database +pathToDB = 'C:\Users\Silas\Documents\MATLAB\Datensätze\sioe_labor\silas_labor.db'; % Update the path as needed +db = DBHandler("pathToDB",pathToDB); + +% main file path +sioe_labor_path = 'C:\Users\Silas\Documents\MATLAB\Datensätze\sioe_labor'; + +% Get list of all folders (including subfolders) within sioe_labor_path +folderList = dir(fullfile(sioe_labor_path, '**', '*')); + +% Filter to include only directories and exclude '.' and '..' +folderNames = {folderList([folderList.isdir]).name}; +folderPaths = {folderList([folderList.isdir]).folder}; % Get the full paths +folderPaths = folderPaths(~ismember(folderNames, {'.', '..'})); +folderNames = folderNames(~ismember(folderNames, {'.', '..'})); + + +% Combine folder names with paths +fullFolderPaths = flip(fullfile(folderPaths, folderNames)); + +% process only MPI? +only_mpi=0; +if only_mpi + fullFolderPaths = fullFolderPaths(contains(fullFolderPaths,"mpi")); +end + +% Shorten folder paths to display only the folder name after the last filesep +displayFolderPaths = cellfun(@(x) x(find(x == filesep, 1, 'last') + 1 : end), fullFolderPaths, 'UniformOutput', false); + +% Create checkbox settings for each folder path +numFolders = numel(fullFolderPaths); +checkboxSettings = cell(1, 2 * numFolders); +for i = 1:numFolders + checkboxSettings{2*i-1} = {displayFolderPaths{i}; sprintf('Folder_%d', i)}; + checkboxSettings{2*i} = true; % Set false for unchecked by default +end + +% Create settings dialog using settingsdlg +[settings, button] = settingsdlg( ... + 'Description', 'Select Folders to Process:', ... + 'title', 'Folder Selection', ... + checkboxSettings{:}); + +% Check if the user pressed OK +if strcmp(button, 'OK') + % Get all the field names from settings + allFields = fieldnames(settings); + + % Determine which folders were selected + selectedFoldersIdx = cellfun(@(x) settings.(x), allFields); + + % Get the list of selected folders + selectedFolders = fullFolderPaths(selectedFoldersIdx==1); + + % Display the selected folders + fprintf('Selected Folders to Process:\n'); + disp(selectedFolders); +else + fprintf('No folders selected.\n'); +end + + +relativeFolderPaths = strrep(selectedFolders, sioe_labor_path, ''); + +disp(['Start to process ',num2str(numel(relativeFolderPaths)), ' folder in the directory']); + + +for f = 1:numel(selectedFolders) + folder = selectedFolders{n}; + relfolder = relativeFolderPaths{f}; + + + % Get list of all files in the specified folder and subfolders + fileList = dir(folder); + + if isempty(fileList(~[fileList.isdir])) + continue + end + + matches = regexp(folder, '\d+km', 'match'); + + % Check if a match was found + if ~isempty(matches) + + length_from_foldername_km = matches{1}; % Extract the first match + length_from_foldername_km = strrep(length_from_foldername_km,'km',''); + disp(['The length is: ', length_from_foldername_km]); + else + disp('No length information found in the folder name.'); + end + + % Loop through each file and rename if necessary + for i = 1:length(fileList) + oldName = fileList(i).name; + + % Use regex to find and remove any prefix before the date string + newName = regexprep(oldName, '^[^\d]*(\d{8}_\d{6}.*)', '$1'); + + % Insert an underscore before "PAM" if missing + newName = regexprep(newName, '(\d{8}_\d{6})(PAM)', '$1_PAM'); + + % Rename the file only if a change was made + if ~strcmp(oldName, newName) + movefile(fullfile(fileList(i).folder, oldName), fullfile(fileList(i).folder, newName)); + fprintf('Renamed: %s -> %s\n', oldName, newName); + end + + + end + + + % Get new list of all files in the specified folder and subfolders, we + % renamed files so we need to get the new filenames here to work on :-) + fileList = dir(folder); + + % Initialize lists to store DataStorage objects based on size + big_wh_list = {}; % For large DataStorage objects + big_wh_filename = {}; % Corresponding filenames for large objects + small_wh_list = {}; % For small DataStorage objects + small_wh_filename = {}; % Corresponding filenames for small objects + + % Loop through each file and categorize based on the presence of 'wh' in the filename + for i = 1:length(fileList) + fileName = fileList(i).name; + if contains(fileName, 'wh') + % Load DataStorage object from file + wh = load(fullfile(fileList(i).folder, fileName)); + wh = wh.obj; + + % Classify as big or small based on dimensions + if isa(wh, 'DataStorage') + if prod(wh.dim) > 2 + big_wh_list{end+1} = wh; + big_wh_filename{end+1} = fileName; + else + small_wh_list{end+1} = wh; + small_wh_filename{end+1} = fileName; + end + end + end + end + + % Aggregate unique parameters across all large DataStorage objects + params_merge = struct; + for c = 1:numel(big_wh_list) + fnames = fieldnames(big_wh_list{c}.parameter); + for fn = 1:numel(fnames) + % Initialize field if not already present + if ~isfield(params_merge, fnames{fn}) + params_merge.(fnames{fn}) = []; + end + + % Merge unique parameter values into params_merge + a = big_wh_list{c}.parameter.(fnames{fn}).values; + b = params_merge.(fnames{fn}); + vals_to_add = setdiff(a, b); % New values in a that aren't in b + b = sort([b, vals_to_add]); % Combine and sort values + params_merge.(fnames{fn}) = b; + end + end + + % Process each large DataStorage object + for w = 1:numel(big_wh_list) + wh = big_wh_list{w}; + % Extract date and time for filename generation + datebody = regexp(big_wh_filename{w}, '^\d{8}_\d{6}', 'match', 'once'); + + % Get the total number of linear indices + totalIndices = wh.getLastLinIndice; + + % Initialize the waitbar + h = waitbar(0, 'Processing DataStorage...'); + + % Loop over each linear index in DataStorage + for i = 1:wh.getLastLinIndice + % Update the waitbar with the current progress + waitbar(i / totalIndices, h, sprintf('Folder: %s...\n %d of %d', string(strrep(strrep(relfolder, '\', '/'),'_',' ')), i, totalIndices)); + + % Initialize record struct for each entry and flag for non-empty data + measurementStruct = struct(); + recordIsFilled = false; + + % Loop over each storage within DataStorage and gather data + storage_names = fieldnames(wh.sto); + for s = 1:length(storage_names) + % Retrieve physical values, parameter names, and stored value + [configStruct, stored_value] = wh.getPhysAndValueByLinIndex(storage_names{s}, i); + measurementStruct.(storage_names{s}) = stored_value; + if ~isempty(stored_value) + recordIsFilled = true; % Mark as filled if value is present + end + end + + [configStruct.precomp_amp_max,configStruct.v_bias_for_pam] = getBias(configStruct.duobinary,configStruct.M); + + isMPI = isfield(measurementStruct,'i_power'); + + % Process record if it contains *any* data + if recordIsFilled + + if ~isMPI + + % Generate filenames with conditionally formatted parameters + % Format the L parameter value (show decimal only if non-zero) + if configStruct.lambda == floor(configStruct.lambda) + L_str = sprintf('%.0f',configStruct.lambda); % No decimal part + else + L_str = sprintf('%.1f', configStruct.lambda); % Include one decimal place + end + + % Synthesize filename base with placeholders for storage types + fbody_tx = sprintf('%s_PAM_%d_L_%s_R_%d_DB_%d_ROP_%d', datebody, ... + configStruct.M, L_str, configStruct.bitrate, configStruct.duobinary, 0); + fbody_tx = strrep(fbody_tx, '.', '_'); % Replace decimal point with underscore + + if configStruct.rop_atten == round(configStruct.rop_atten) + fbody_rx = sprintf('%s_PAM_%d_L_%s_R_%d_DB_%d_ROP_%d', datebody, ... + configStruct.M, L_str, configStruct.bitrate, configStruct.duobinary, configStruct.rop_atten); + else + fbody_rx = sprintf('%s_PAM_%d_L_%s_R_%d_DB_%d_ROP_%.1f', datebody, ... + configStruct.M, L_str, configStruct.bitrate, configStruct.duobinary, configStruct.rop_atten); + end + fbody_rx = strrep(fbody_rx, '.', '_'); + + elseif isMPI + + fbody_tx = sprintf('%s_PAM_%d_R_%d_DB_%d_I_atten_%d', datebody, ... + configStruct.M, configStruct.bitrate, configStruct.duobinary, 0); + fbody_tx = strrep(fbody_tx, '.', '_'); % Replace decimal point with underscore + + if configStruct.interference_atten == round(configStruct.interference_atten) + fbody_rx = sprintf('%s_PAM_%d_R_%d_DB_%d_I_atten_%d', datebody, ... + configStruct.M, configStruct.bitrate, configStruct.duobinary, configStruct.interference_atten); + else + fbody_rx = sprintf('%s_PAM_%d_R_%d_DB_%d_I_atten_%.1f', datebody, ... + configStruct.M, configStruct.bitrate, configStruct.duobinary, configStruct.interference_atten); + end + fbody_rx = strrep(fbody_rx, '.', '_'); % Replace decimal point with underscore + + end + + % Check existence of different file types (bits, symbols, raw signal, rx signal) + % BIT SEQUENCE + fn_bits = [filesep, fbody_tx, '_bits.mat']; + fp_bits = fullfile([folder, fn_bits]); + if exist(fp_bits, "file") == 2 + fn_bits_rel = [relfolder, fn_bits]; + else + warning(['Bits not found at: ', fn_bits]); + end + + % SYMBOL SEQUENCE + fn_symbols = [filesep, fbody_tx, '_symbols.mat']; + fp_symbols = fullfile([folder, fn_symbols]); + if exist(fp_symbols, "file") == 2 + fn_symbols_rel = [relfolder, fn_symbols]; + else + warning(['Symbols not found at: ', fn_symbols]); + end + + % RAW RX SIGNAL + fn_rxraw = [filesep, fbody_rx, '_raw_signal.mat']; + fp_rxraw = fullfile([folder, fn_rxraw]); + missing_raw_flag = 1; % Initialize as missing + + if exist(fp_rxraw, "file") == 2 + fn_rxraw_rel = [relfolder, fn_rxraw]; + missing_raw_flag = 0; + end + + % SYNCHRONIZED RX SIGNAL + fn_rxtsynch = [filesep, fbody_rx, '_rx_signal.mat']; + fp_rxtsynch = fullfile([folder, fn_rxtsynch]); + fn_rxtsynch_rel = []; + if exist(fp_rxtsynch, "file") == 2 + fn_rxtsynch_rel = [relfolder, fn_rxtsynch]; + + matObj = matfile([folder, fn_rxtsynch]); + + % If RX signal actually contains raw signal, handle as necessary + if isprop(matObj, 'Scpe_sig_raw') + sig_rx = load([folder, fn_rxtsynch]); + if missing_raw_flag + % Save as raw signal if original raw signal is missing + Scpe_sig_raw = sig_rx.Scpe_sig_raw; + save([folder, fn_rxraw], "Scpe_sig_raw"); + delete([folder, fn_rxtsynch]); + else + % Check if raw and rx signal files are identical, then delete duplicate + sig_raw = load([folder, fn_rxraw]); + if isequal(sig_raw, sig_rx) + delete([folder, fn_rxtsynch]); + end + end + end + + elseif exist(fp_rxtsynch, "file") == 0 + + disp(['RX Signal not found at: ', fn_rxtsynch,' generate and save new one using symbols and raw signal']); + + Scpe_sig_raw = load(fp_rxraw); + Scpe_sig_raw = Scpe_sig_raw.Scpe_sig_raw; + + Symbols = load(fp_symbols); + Symbols = Symbols.Symbols; + %%%%%% Sample to 2x fsym %%%%%% + Scpe_sig_resampled = Scpe_sig_raw.resample("fs_in",Scpe_sig_raw.fs,"fs_out",2*Symbols.fs); + %%%%%% Sync Rx signal with reference (S is a cell array with all occurences) %%%%%% + [Scpe_sig_syncd,S,isFlipped] = Scpe_sig_resampled.tsynch("reference",Symbols,"fs_ref",Symbols.fs); + %%%%% Plot and Save Routines: SAVE RECEIVED SIGNALS %%%%%%%%%%%%%%%%%%%%%%%%% + save(fp_rxtsynch,"S"); + + if exist(fp_rxtsynch, "file") == 0 + warndlg('Something still wromg... No rx file here but we just generated it from raw signal'); + end + + fn_rxtsynch_rel = [relfolder, fn_rxtsynch]; + + elseif missing_raw_flag + warndlg('No RAW or RX signal found! This is bad!'); + % look at measurementStruct and configStruct + end + else + disp('Record not filled?') + % look at measurementStruct and configStruct + end + + % Call the duplicate check function + if ~isempty(fn_rxtsynch_rel) + exists = db.checkIfRunExists('Runs', 'rx_sync_path', fn_rxtsynch_rel); + end + + if ~exists + + % Table 1: Append to Runs + newRun = db.tables.Runs; % Get the existing table structure (an empty table) + newRun = struct(... + 'run_id', NaN, ... % Auto-increment, leave empty + 'date_of_run', datetime(datebody, 'InputFormat', 'yyyyMMdd_HHmmss'), ... + 'tx_bits_path', fn_bits_rel, ... + 'tx_symbols_path', fn_symbols_rel, ... + 'rx_sync_path', fn_rxtsynch_rel, ... + 'rx_raw_path', fn_rxraw_rel, ... + 'filename', fbody_rx ... + ); + + % Append the new row to the Runs table and get the generated run ID + run_id = db.appendToTable('Runs', newRun); + + if isMPI + + assert(configStruct.interference_atten==measurementStruct.voa.value(4),'MPI attuation differs between voa state and desired config from simulation loop.'); + interference_attenuation = configStruct.interference_atten; + interference_path_length = 2; + power_mpi_interference = measurementStruct.voa.power_state(4); + power_mpi_signal = measurementStruct.voa.power_state(3); + + rop_attenuation = 0; + wavelength = 1310; + fiber_length = 1; + + else + + interference_attenuation = NaN; + interference_path_length = NaN; + power_mpi_interference = NaN; + power_mpi_signal = NaN; + + rop_attenuation = configStruct.rop_atten; + wavelength = configStruct.lambda; + fiber_length = str2double(length_from_foldername_km); + + end + % Table 2: Append to Configurations + newConfig = db.tables.Configurations; % Get the existing table structure (an empty table) + newConfig = struct(... + 'configuration_id', NaN, ... % Auto-increment, leave empty + 'run_id', run_id, ... % Foreign key from Runs + 'unique_elab_id', "20241028-dea635ef776cd18270922ba0e52c65831ff7699f", ... % Set unique_elab_id as needed + 'bitrate', configStruct.bitrate, ... + 'symbolrate', floor(configStruct.bitrate * 1e-9 / log2(configStruct.M)) * 1e9, ... % Calculate symbolrate if available + 'pam_level', configStruct.M, ... + 'db_mode', configStruct.duobinary, ... % Assuming db_mode corresponds to duobinary mode + 'v_bias', configStruct.v_bias_for_pam, ... + 'v_awg', 2.7, ... + 'precomp_amp', configStruct.precomp_amp_max, ... + 'rop_attenuation', rop_attenuation, ... + 'wavelength', wavelength, ... + 'fiber_length', fiber_length, ... + 'is_mpi', isMPI, ... % Set false for no MPI, change as needed + 'interference_path_length', interference_path_length, ... % Set NaN if not applicable + 'interference_attenuation', interference_attenuation ... % Set NaN if not applicable + ); + + % Append the new row to the Configurations table + db.appendToTable('Configurations', newConfig); + + % Table 3: Append to Measurements + newMeas = db.tables.Measurements; % Get the existing table structure (an empty table) + newMeas = struct(... + 'measurement_id', NaN, ... % Auto-increment, leave empty + 'run_id', run_id, ... % Foreign key from Runs + 'power_laser', measurementStruct.exfo.cur_power, ... + 'power_rop', measurementStruct.rop, ... + 'power_pd_in', measurementStruct.pd_in, ... + 'power_mpi_interference', power_mpi_interference, ... + 'power_mpi_signal', power_mpi_signal, ... + 'voa_class', measurementStruct.voa, ... + 'pdfa_class', measurementStruct.pdfa, ... + 'laser_class', measurementStruct.exfo ... + ); + + % Append the new row to the Measurements table + db.appendToTable('Measurements', newMeas); + + % % Table 4: Append to Bers + % [ber, structure, settings] = getBers(configStruct,measurementStruct); + % for t = 1:numel(ber) + % + % if iscell(ber(t)) + % ber_ = ber(t); + % ber_ = ber_{1}; + % else + % ber_ = ber(t); + % end + % + % if ber_~=-1 + % + % newBer = struct(... + % 'ber_id', NaN,... + % 'run_id', run_id,... + % 'processing_structure', structure(t),... + % 'processing_settings', settings(t),... + % 'ber', jsonencode(ber_)... + % ); + % + % db.appendToTable('BERs', newBer); + % + % end + % + % end + + end + + + end + end +end + +function [ber, structure, settings] = getBers(configStruct,measurementStruct) + +if configStruct.duobinary == 0 + + structure(1) = "vnle"; + settings(1) = EQ("Ne",[50,7,7],"Nb",[0,0,0],"training_length",4096*2,"training_loops",5,"dd_loops",5,"K",2,"DCmu",0.0,"DDmu",[0.0004 0.0004 0.0004 0.0004 ],"DFEmu",0.005,"FFEmu",0,"plotfinal",0,"ideal_dfe",1); + ber(1) = measurementStruct.ber_vnle; + + structure(2) = "vnle -> remove DC from error ""Noi{s}.signal = Noi{s}.signal - mean(Noi{s}.signal);"" -> burg(error) -> pf -> mlse"; + settings(2) = EQ("Ne",[50,7,7],"Nb",[0,0,0],"training_length",4096*2,"training_loops",5,"dd_loops",5,"K",2,"DCmu",0.0,"DDmu",[0.0004 0.0004 0.0004 0.0004 ],"DFEmu",0.005,"FFEmu",0,"plotfinal",0,"ideal_dfe",1); + ber(2) = measurementStruct.ber_vnle_mlse; + +elseif configStruct.duobinary == 1 + + structure(1) = "tx: duobinary precode; rx: db target -> mlse -> modulo"; + settings(1) = EQ("Ne",[50,7,7],"Nb",[0,0,0],"training_length",4096*2,"training_loops",5,"dd_loops",5,"K",2,"DCmu",0.0,"DDmu",[0.0004 0.0004 0.0004 0.0004 ],"DFEmu",0.005,"FFEmu",0,"plotfinal",0,"ideal_dfe",1); + ber(1) = measurementStruct.ber_db; + +elseif configStruct.duobinary == 2 + + structure(1) = "tx: duobinary precode -> encode; rx: db target -> mlse as decoder -> modulo"; + settings(1) = EQ("Ne",[50,7,7],"Nb",[0,0,0],"training_length",4096*2,"training_loops",5,"dd_loops",5,"K",2,"DCmu",0.0,"DDmu",[0.0004 0.0004 0.0004 0.0004 ],"DFEmu",0.005,"FFEmu",0,"plotfinal",0,"ideal_dfe",1); + ber(1) = measurementStruct.ber_db; + +end + + +end + +function [precomp_amp_max,v_bias_for_pam] = getBias(db,M) + +if db == 1 + ffe_only = 0; + postfilter_approach = 0; + db_channel_approach = 1; + db_coding_approach = 0; + db_precode = db_coding_approach || db_channel_approach; + if M == 4 + pulsef=1; + precomp_amp_max = -50; + v_bias_for_pam = 2.3; + pulsef = 1; + elseif M == 6 + pulsef=0; + precomp_amp_max = -50; + v_bias_for_pam = 2.3; + pulsef = 1; + elseif M == 8 + pulsef=0; + precomp_amp_max = -50; + v_bias_for_pam=2.6; + pulsef = 0; + end + +elseif db == 2 + + ffe_only = 0; + postfilter_approach = 0; + db_channel_approach = 0; + db_coding_approach = 1; + db_precode = db_coding_approach || db_channel_approach; + if M == 4 + pulsef=1; + precomp_amp_max = -38; + v_bias_for_pam = 2.8; + pulsef = 1; + elseif M == 6 + pulsef=0; + precomp_amp_max = -38; + v_bias_for_pam = 2.8; + pulsef = 1; + elseif M == 8 + pulsef=0; + precomp_amp_max = -38; + v_bias_for_pam = 2.8; + pulsef = 1; + end + +elseif db == 0 + + ffe_only = 0; + postfilter_approach = 1; + db_channel_approach = 0; + db_coding_approach = 0; + db_precode = db_coding_approach || db_channel_approach; + if M == 4 + pulsef=1; + precomp_amp_max = -37; + v_bias_for_pam = 2.3; + pulsef = 1; + elseif M == 6 + pulsef=0; + precomp_amp_max = -34; + v_bias_for_pam = 2.3; + pulsef = 1; + elseif M == 8 + pulsef=0; + precomp_amp_max = -34; + v_bias_for_pam=2.6; + pulsef = 0; + end +end +end + + diff --git a/projects/HighSpeedExperiment_2024/auswertung/checkDB.m b/projects/HighSpeedExperiment_2024/auswertung/checkDB.m new file mode 100644 index 0000000..8acd53b --- /dev/null +++ b/projects/HighSpeedExperiment_2024/auswertung/checkDB.m @@ -0,0 +1,28 @@ +function checkDB(db_path) + + db = DBHandler("pathToDB",db_path); + + num_runs = db.fetch('SELECT COUNT(*) AS total_runs FROM Runs'); + + num_configs = db.fetch('SELECT COUNT(*) AS total_configurations FROM Configurations'); + + num_meas = db.fetch('SELECT COUNT(*) AS total_measurements FROM Measurements'); + + assert((num_runs{1,1}==num_configs{1,1})&&(num_configs{1,1}==num_meas{1,1}),'Different num of entries per table') + + % should not be possible, but check if anyconfig or meas is without + % parent Run entry + unmatchedConfigs = db.fetch('SELECT COUNT(*) AS unmatched_configs FROM Configurations WHERE run_id NOT IN (SELECT run_id FROM Runs)'); + unmatchedMeasurements = db.fetch('SELECT COUNT(*) AS unmatched_measurements FROM Measurements WHERE run_id NOT IN (SELECT run_id FROM Runs)'); + + if unmatchedConfigs{1,1}~=0 || unmatchedMeasurements{1,1}~=0 + fprintf('Unmatched Configurations: %d\n', unmatchedConfigs{1,1}); + fprintf('Unmatched Measurements: %d\n', unmatchedMeasurements{1,1}); + end + + %Check for any duplicate paths + db.fetch("SELECT rx_raw_path, COUNT(*) AS occurrences FROM Runs GROUP BY rx_raw_path HAVING COUNT(*) > 1"); + db.fetch("SELECT rx_sync_path, COUNT(*) AS occurrences FROM Runs GROUP BY rx_sync_path HAVING COUNT(*) > 1"); + db.fetch("SELECT filename, COUNT(*) AS occurrences FROM Runs GROUP BY filename HAVING COUNT(*) > 1"); + +end \ No newline at end of file diff --git a/projects/HighSpeedExperiment_2024/auswertung/checkDBpaths.m b/projects/HighSpeedExperiment_2024/auswertung/checkDBpaths.m new file mode 100644 index 0000000..7d3ba3d --- /dev/null +++ b/projects/HighSpeedExperiment_2024/auswertung/checkDBpaths.m @@ -0,0 +1,42 @@ +% Load the Runs table from the database +db = DBHandler("pathToDB", 'C:\Users\Silas\Documents\MATLAB\Datensätze\sioe_labor\silas_labor.db'); +runsTable = db.queryDB(db.tables, {'Runs.run_id', 'Runs.tx_bits_path', 'Runs.tx_symbols_path', 'Runs.rx_sync_path', 'Runs.rx_raw_path', 'Runs.filename'}); + +% Initialize an array to store the result of existence check +fileExistenceResults = false(height(runsTable), 4); % 4 columns for the paths: tx_bits, tx_symbols, rx_sync, rx_raw + +% Main file path +sioe_labor_path = 'C:\Users\Silas\Documents\MATLAB\Datensätze\sioe_labor'; + +% Loop through all rows in the table and check paths +for i = 1:height(runsTable) + fileExistenceResults(i, 1) = exist([sioe_labor_path, runsTable.tx_bits_path{i}], 'file') == 2; + fileExistenceResults(i, 2) = exist([sioe_labor_path, runsTable.tx_symbols_path{i}], 'file') == 2; + fileExistenceResults(i, 3) = exist([sioe_labor_path, runsTable.rx_sync_path{i}], 'file') == 2; + fileExistenceResults(i, 4) = exist([sioe_labor_path, runsTable.rx_raw_path{i}], 'file') == 2; +end + +% Identify corrupted run_ids (where any path does not exist) +corruptedRunIds = runsTable.run_id(~all(fileExistenceResults, 2)); + +% Delete entries in all tables related to corrupted run_ids +for i = 1:numel(corruptedRunIds) + run_id = corruptedRunIds(i); + + % Delete from BERs table + db.executeSQL(sprintf('DELETE FROM BERs WHERE run_id = %d;', run_id)); + + % Delete from Equalizer table (if applicable) + db.executeSQL(sprintf('DELETE FROM Equalizer WHERE eq_id IN (SELECT eq_id FROM BERs WHERE run_id = %d);', run_id)); + + % Delete from Measurements table + db.executeSQL(sprintf('DELETE FROM Measurements WHERE run_id = %d;', run_id)); + + % Delete from Configurations table + db.executeSQL(sprintf('DELETE FROM Configurations WHERE run_id = %d;', run_id)); + + % Delete from Runs table + db.executeSQL(sprintf('DELETE FROM Runs WHERE run_id = %d;', run_id)); +end +% +% disp('Entries for corrupted run_ids have been removed from the database.'); diff --git a/projects/HighSpeedExperiment_2024/auswertung/createConfigMenu.m b/projects/HighSpeedExperiment_2024/auswertung/createConfigMenu.m new file mode 100644 index 0000000..b413f34 --- /dev/null +++ b/projects/HighSpeedExperiment_2024/auswertung/createConfigMenu.m @@ -0,0 +1,52 @@ +function createConfigMenu(DBHandler) + % Create the main figure window + fig = uifigure('Name', 'Configuration Query', 'Position', [100, 100, 400, 300]); + + % Retrieve tables and table names using the DBHandler class + dbTables = DBHandler.getTables(); + tableNames = DBHandler.getTableNames(); + + % Assume that the DBHandler class provides methods to get the unique + % configuration options (e.g., PAM levels, bitrates, etc.) + uniqueBitrates = unique([dbTables.bitrate]); + uniquePAMLevels = unique([dbTables.pam_level]); + uniqueWavelengths = unique([dbTables.wavelength]); + uniqueDBModes = unique([dbTables.db_mode]); + + % Create dropdown menus for each configuration + lblBitrate = uilabel(fig, 'Text', 'Bitrate:', 'Position', [50, 240, 100, 20]); + dropdownBitrate = uidropdown(fig, 'Items', string(uniqueBitrates), 'Position', [150, 240, 200, 20]); + + lblPAM = uilabel(fig, 'Text', 'PAM Level:', 'Position', [50, 200, 100, 20]); + dropdownPAM = uidropdown(fig, 'Items', string(uniquePAMLevels), 'Position', [150, 200, 200, 20]); + + lblWavelength = uilabel(fig, 'Text', 'Wavelength:', 'Position', [50, 160, 100, 20]); + dropdownWavelength = uidropdown(fig, 'Items', string(uniqueWavelengths), 'Position', [150, 160, 200, 20]); + + lblDBMode = uilabel(fig, 'Text', 'DB Mode:', 'Position', [50, 120, 100, 20]); + dropdownDBMode = uidropdown(fig, 'Items', string(uniqueDBModes), 'Position', [150, 120, 200, 20]); + + % Create a button to query the configuration + btnQuery = uibutton(fig, 'Text', 'Query Configuration', 'Position', [150, 80, 200, 30], ... + 'ButtonPushedFcn', @(btn, event) queryConfiguration(DBHandler, ... + dropdownBitrate.Value, ... + dropdownPAM.Value, ... + dropdownWavelength.Value, ... + dropdownDBMode.Value)); + + % Function to handle querying the configuration + function queryConfiguration(DBHandler, bitrate, pamLevel, wavelength, dbMode) + % Convert dropdown values to numeric if necessary + bitrate = str2double(bitrate); + pamLevel = str2double(pamLevel); + wavelength = str2double(wavelength); + dbMode = str2double(dbMode); + + % Query the DBHandler class with the specified configuration + results = DBHandler.query(bitrate, pamLevel, wavelength, dbMode); + + % Display the results in the command window (or update the GUI) + disp('Query Results:'); + disp(results); + end +end diff --git a/projects/HighSpeedExperiment_2024/auswertung/getBerForRunId.m b/projects/HighSpeedExperiment_2024/auswertung/getBerForRunId.m new file mode 100644 index 0000000..054c904 --- /dev/null +++ b/projects/HighSpeedExperiment_2024/auswertung/getBerForRunId.m @@ -0,0 +1,32 @@ +function [berTable, foundBerFlag] = getBerForRunId(db, run_id) + % getBerForRunId Queries the BER data for the specified run_id. + % Inputs: + % db - The database handler object. + % run_id - The run ID for which to get the BER data. + % Outputs: + % berData - A table containing BER results for the given run ID. + + % Set up filter parameters to query the BER data for the specific run_id + filterParams = db.tables; + filterParams.Runs.run_id = run_id; % Filter by specific run_id + + % Define the fields to be retrieved from the database + selectedFields = {'Runs.run_id', 'BERs.ber_id', 'Equalizer.eq_id', 'Equalizer.eq_type', ... + 'BERs.ber', 'BERs.occurrence', 'Configurations.db_mode', ... + 'Configurations.pam_level', 'Configurations.bitrate', 'Configurations.symbolrate', ... + 'Configurations.fiber_length', 'Configurations.wavelength', ... + 'Configurations.precomp_amp', 'Measurements.power_rop', 'Measurements.power_laser', ... + 'Measurements.power_pd_in'}; + + % Query the database for the specified run_id + [berTable, ~] = db.queryDB(filterParams, selectedFields); + + if ~isnumeric(berTable.ber) + foundBerFlag = ~isnan(str2num(berTable.ber)); + else + foundBerFlag = 1; + end + + % Display information about the found BER entries + % fprintf('Found %d BER entries for run_id %d.\n', size(berTable, 1), run_id); +end diff --git a/projects/HighSpeedExperiment_2024/auswertung/only_show_precomp.m b/projects/HighSpeedExperiment_2024/auswertung/only_show_precomp.m new file mode 100644 index 0000000..9902b03 --- /dev/null +++ b/projects/HighSpeedExperiment_2024/auswertung/only_show_precomp.m @@ -0,0 +1,89 @@ + +precomp_path = "C:\Users\Silas\Documents\MATLAB\Datensätze\sioe_labor\precomp"; +precomp_fn = "lab_high_speed"; +precomp_mode = 2; %0=do nothing ; 1= measure; 2=precomp active +db_precode = 0; +db_coding_approach = 0; + +fsym = 224e9; +fdac = 256e9; +random_key = 0; +M = 4; + +if (db_precode==1)&&(db_coding_approach==0) + + if M == 4 + pulsef=1; + precomp_amp_max = -50; + elseif M == 6 + pulsef=0; + precomp_amp_max = -50; + elseif M == 8 + pulsef=0; + precomp_amp_max = -50; + end + +elseif (db_precode==1)&&(db_coding_approach==1) + + if M == 4 + pulsef=1; + precomp_amp_max = -38; + pulsef = 1; + elseif M == 6 + pulsef=0; + precomp_amp_max = -38; + pulsef = 1; + elseif M == 8 + pulsef=0; + precomp_amp_max = -38; + pulsef = 1; + end + +elseif (db_precode==0)&&(db_coding_approach==0) + + if M == 4 + pulsef=1; + precomp_amp_max = -37; + pulsef = 1; + elseif M == 6 + pulsef=0; + precomp_amp_max = -34; + pulsef = 1; + elseif M == 8 + pulsef=0; + precomp_amp_max = -34; + pulsef = 0; + end +end + + +rcalpha = 0.05; +Pform = Pulseformer("fsym",fsym,"fdac",4*fsym,"pulse","rrc","pulselength",16,"rrcalpha",rcalpha); + + +Pamsource = PAMsource(... + "fsym",fsym,"M",M,"order",19,"useprbs",1,... + "fs_out",fdac,... + "applyclipping",0,"clipfactor",1.2,... + "applypulseform",pulsef,"pulseformer",Pform,... + "randkey",random_key,... + "db_precode",db_precode,"db_encode",db_coding_approach,... + "mrds_code",0,"mrds_blocklength",512); + +[Digi_sig,Symbols,Bits] = Pamsource.process(); + +Digi_sig = Digi_sig.normalize("mode","rms"); + +Digi_sig.spectrum("displayname","No Precomp","fignum",2223,"normalizeToNyquist",0,"normalizeTo0dB",0); + +precomp_est = ChannelFreqResp("Nacq",2048,"Navg",100,"Ncp",63,'f_ref',Digi_sig.fs); + +Digi_sig = precomp_est.precomp(Digi_sig,'maxampdb',precomp_amp_max,'loadPath',precomp_path,'fileName',precomp_fn); + +Digi_sig = Digi_sig.normalize("mode","rms"); + +Digi_sig = Digi_sig.resample("fs_out",fdac); +Digi_sig= Digi_sig.normalize("mode","rms"); +Digi_sig.spectrum("displayname","Strong Precomp","fignum",2223,"normalizeToNyquist",0,"normalizeTo0dB",0); + + diff --git a/projects/HighSpeedExperiment_2024/auswertung/runDSP.m b/projects/HighSpeedExperiment_2024/auswertung/runDSP.m new file mode 100644 index 0000000..0d7fd55 --- /dev/null +++ b/projects/HighSpeedExperiment_2024/auswertung/runDSP.m @@ -0,0 +1,165 @@ +tic +basePath = 'C:\Users\Silas\Documents\MATLAB\Datensätze\sioe_labor\'; +useGui = 0; +db = DBHandler("pathToDB",[basePath,'silas_labor.db']); + +toc + +if useGui + filterParams = db.promptFilterParameters(); + selectedFields = db.promptSelectFields(); +else + filterParams = db.tables; + filterParams.Configurations = struct( ... + 'bitrate', 300e9, ... + 'db_mode', 0, ... + 'fiber_length', 1, ... + 'interference_attenuation', [], ... + 'interference_path_length', [], ... + 'is_mpi', 0, ... + 'pam_level', 4, ... + 'precomp_amp', [], ... + 'rop_attenuation', [], ... + 'symbolrate', [], ... + 'v_awg', [], ... + 'v_bias', [], ... + 'wavelength', 1310 ... + ); + % filterParams.Runs.run_id = 3303; + %filterParams.Equalizer.eq_id = equalizer_structure.vnle; + selectedFields = {'Runs.run_id','Runs.tx_bits_path', 'Runs.tx_symbols_path', 'Runs.rx_sync_path','Runs.rx_raw_path',... + 'Configurations.db_mode','Configurations.pam_level','Configurations.bitrate','Configurations.fiber_length','Configurations.wavelength','Configurations.precomp_amp','BERs.ber'}; +end + +toc + +[dataTable,sql_query] = db.queryDB(filterParams, selectedFields); +[~, uniqueIdx] = unique(dataTable.run_id); % Get unique run_id indices +dataTable = dataTable(uniqueIdx,:); % Extract unique configurations for each run_id +fprintf('Found %d entries for requested Configuration. IDs are: %s \n \n',size(dataTable,1),jsonencode(dataTable.run_id(1:min(size(dataTable,1),100)))); + +toc + +fprintf('Processing: %d%%', 0); +%2) Process Measurement Config +for i = 1:size(dataTable,1) + + fprintf('\b\b\b\b%4d', i); % Backspace 3 characters, then overwrite + + [~, foundBerFlag] = getBerForRunId(db, dataTable.run_id(i)); + if foundBerFlag + continue + end + + fprintf('\n%s T: %f CURRENT ID: %d == %d KM == %s PAM %d == %d Gbit/s == %d nm %s \n \n', repmat('=', 1, 10), toc/60, dataTable.run_id(i), dataTable.fiber_length(i) ,db_mode(dataTable.db_mode(i)), dataTable.pam_level(i) ,dataTable.bitrate(i).*1e-9,dataTable.wavelength(i), repmat('=', 1, 10)); % Print a blank line, then a thick line of 80 '=' characters, then another blank line + + % FROM NOW ON, ONE Run_id IS CHOSEN AND WILL BE DSP'd + + tx_bits = load([basePath, char(dataTable.tx_bits_path(i))]); + tx_bits = tx_bits.Bits; + tx_symbols = load([basePath, char(dataTable.tx_symbols_path(i))]); + tx_symbols = tx_symbols.Symbols; + rx_sync = load([basePath, char(dataTable.rx_sync_path(i))]); + rx_sync = rx_sync.S; + %rx_raw = load([basePath, char(result.rx_raw_path(i))]); + + ffe_order=[50,0,0]; + vnle_order=[50,7,7]; + dfe_order = [0 0 0]; + + len_tr = 4096*2; + mu_ffe = [0.0004 0.0004 0.0004]; + mu_dfe = 0.0004; + mu_dc = 0.05; + + dfe_ = sum(dfe_order)>0; + + %Loop through sliced oscilloscope measurement + parfor o = 1:numel(rx_sync) + rx_sig = rx_sync{o}; + + M = dataTable.pam_level(i); + + switch dataTable.db_mode(i) + + case db_mode.no_db + + %FFE + eq_ffe(o) = EQ("Ne",ffe_order,"Nb",dfe_order,"training_length",len_tr,"training_loops",5,"dd_loops",5,"K",2,"DCmu",0.05,"DDmu",[mu_ffe mu_dfe],"DFEmu",0.005,"FFEmu",0,"plotfinal",0,"ideal_dfe",1); + [eq_sig,eq_noise,ber_ffe(o),totalErrors] = vnle( eq_ffe(o),M,rx_sig,tx_symbols, tx_bits); + + %VNLE + eq_vnle(o) = EQ("Ne",vnle_order,"Nb",dfe_order,"training_length",len_tr,"training_loops",5,"dd_loops",5,"K",2,"DCmu",0.05,"DDmu",[mu_ffe mu_dfe],"DFEmu",0.005,"FFEmu",0,"plotfinal",0,"ideal_dfe",1); + [eq_sig,eq_noise,ber_vnle(o),totalErrors] = vnle(eq_vnle(o),M,rx_sig,tx_symbols, tx_bits); + + %VNLE + PF + MLSE + eq_mlse(o) = EQ("Ne",vnle_order,"Nb",dfe_order,"training_length",len_tr,"training_loops",5,"dd_loops",5,"K",2,"DCmu",0.05,"DDmu",[mu_ffe mu_dfe],"DFEmu",0.005,"FFEmu",0,"plotfinal",0,"ideal_dfe",1); + pf_(o) = Postfilter("ncoeff",2); + mlse_(o) = MLSE("DIR",[0,0],"duobinary_output",0,"M",[],"trellis_states",[]); + [eq_sig,eq_noise,ber_mlse(o),totalErrors] = vnle_postfilter_mlse(eq_mlse(o) , pf_(o), mlse_(o),M, rx_sig,tx_symbols, tx_bits); + + case db_mode.db_precoded + + %EQ targets DB => less precompensation; pre-coded + M = dataTable.pam_level(i); + mlse_db_pre(o) = MLSE("DIR",[1,1],"duobinary_output",1,"M",M,"trellis_states",PAMmapper(M,0).levels); + eq_db_pre(o) = EQ("Ne",vnle_order,"Nb",dfe_order,"training_length",len_tr,"training_loops",5,"dd_loops",5,"K",2,"DCmu",0.05,"DDmu",[mu_ffe mu_dfe],"DFEmu",0.005,"FFEmu",0,"plotfinal",0,"ideal_dfe",1); + [eq_sig,eq_noise,ber_db_pre(o),totalErrors] = duobinary_target(eq_db_pre(o), mlse_db_pre(o),M, rx_sig, tx_symbols, tx_bits); + %->append BER to DB + + case db_mode.db_encoded + + %db signaling => db encoded + M = dataTable.pam_level(i); + mlse_db_enc(o) = MLSE("DIR",[1,1],"duobinary_output",1,"M",M,"trellis_states",PAMmapper(M,0).levels); + eq_db_enc(o) = EQ("Ne",vnle_order,"Nb",dfe_order,"training_length",len_tr,"training_loops",5,"dd_loops",5,"K",2,"DCmu",0.05,"DDmu",[mu_ffe mu_dfe],"DFEmu",0.005,"FFEmu",0,"plotfinal",0,"ideal_dfe",1); + [eq_sig,eq_noise,ber_db_enc(o),totalErrors] = duobinary_signaling(eq_db_enc(o), mlse_db_enc(o),M, rx_sig, tx_symbols, tx_bits); + %->append BER to DB + end + + end + + for o = 1:numel(rx_sync) + switch dataTable.db_mode(i) + + case db_mode.no_db + + %FFE + eq_type = equalizer_structure.ffe; + db.addBEREntry(ber_ffe(o), o, dataTable.run_id(i), eq_ffe(o), dfe_, [], [], eq_type, ffe_order, dfe_order, len_tr, mu_ffe, mu_dfe, mu_dc, "FFE"); + showCurrentMeasurement('EQ', string(eq_type), 'BER',ber_ffe(o), 'Mode', string(db_mode(dataTable.db_mode(i))), 'Len', dataTable.fiber_length(i) ,'PAM' , dataTable.pam_level(i) , 'GBit/s' ,dataTable.bitrate(i).*1e-9, 'Lambda' ,dataTable.wavelength(i) ); + + %VNLE + eq_type = equalizer_structure.vnle; + db.addBEREntry(ber_vnle(o), o, dataTable.run_id(i), eq_vnle(o), dfe_, [], [], eq_type, vnle_order, dfe_order, len_tr, mu_ffe, mu_dfe, mu_dc, "VNLE"); + showCurrentMeasurement('EQ', string(eq_type), 'BER',ber_vnle(o), 'Mode', string(db_mode(dataTable.db_mode(i))), 'Len', dataTable.fiber_length(i) ,'PAM' , dataTable.pam_level(i) , 'GBit/s' ,dataTable.bitrate(i).*1e-9, 'Lambda' ,dataTable.wavelength(i) ); + + %MLSE + eq_type = equalizer_structure.vnle_pf_mlse; + db.addBEREntry(ber_mlse(o), o, dataTable.run_id(i), eq_mlse(o), dfe_, mlse_(o), pf_(o), eq_type, vnle_order, dfe_order, len_tr, mu_ffe, mu_dfe, mu_dc, "VNLE;PF;MLSE"); + showCurrentMeasurement('EQ', string(eq_type), 'BER',ber_mlse(o), 'Mode', string(db_mode(dataTable.db_mode(i))), 'Len', dataTable.fiber_length(i) ,'PAM' , dataTable.pam_level(i) , 'GBit/s' ,dataTable.bitrate(i).*1e-9, 'Lambda' ,dataTable.wavelength(i) ); + + case db_mode.db_precoded + + %db_precoded + eq_type = equalizer_structure.db_precoded; + db.addBEREntry(ber_db_pre(o), o, dataTable.run_id(i), eq_db_pre(o), dfe_, mlse_db_pre(o), [], eq_type, vnle_order, dfe_order, len_tr, mu_ffe, mu_dfe, mu_dc, "DB Precode;DB Target;MLSE DB Decode;Modulo"); + showCurrentMeasurement('EQ', string(eq_type), 'BER',ber_db_pre(o), 'Mode', string(db_mode(dataTable.db_mode(i))), 'Len', dataTable.fiber_length(i) ,'PAM' , dataTable.pam_level(i) , 'GBit/s' ,dataTable.bitrate(i).*1e-9, 'Lambda' ,dataTable.wavelength(i) ); + + case db_mode.db_encoded + + %db_encoded + eq_type = equalizer_structure.db_encoded; + db.addBEREntry(ber_db_enc(o), o, dataTable.run_id(i), eq_db_enc(o), dfe_, mlse_db_enc(o), [], eq_type, vnle_order, dfe_order, len_tr, mu_ffe, mu_dfe, mu_dc, "DB Precode;DB Encode;DB Target;MLSE DB Decode;Modulo"); + showCurrentMeasurement('EQ', string(eq_type), 'BER',ber_db_enc(o), 'Mode', string(db_mode(dataTable.db_mode(i))), 'Len', dataTable.fiber_length(i) ,'PAM' , dataTable.pam_level(i) , 'GBit/s' ,dataTable.bitrate(i).*1e-9, 'Lambda' ,dataTable.wavelength(i) ); + + end + + end +end + + +fprintf('\n%s SIMULATION COMPLETE AFTER %f MINUTES %s \n \n', repmat('=', 1, 35), toc/60 ,repmat('=', 1, 35)); % Print a blank line, then a thick line of 80 '=' characters, then another blank line + + + diff --git a/projects/HighSpeedExperiment_2024/master_auswertung_10km.m b/projects/HighSpeedExperiment_2024/master_auswertung_10km.m index 16b5039..b6724f9 100644 --- a/projects/HighSpeedExperiment_2024/master_auswertung_10km.m +++ b/projects/HighSpeedExperiment_2024/master_auswertung_10km.m @@ -1,5 +1,5 @@ -wh = load('C:\Users\sioe\Documents\High_Speed_Measurement_2024\10km_bitrate_complete\20241030_170224_wh.mat'); +wh = load('C:\Users\Silas\Documents\MATLAB\Datensätze\sioe_labor\highspeed_oct_2024\10km_bitrate_complete\20241030_170224_wh.mat'); wh = wh.obj; M_vals = wh.parameter.M.values; @@ -10,12 +10,17 @@ duobinary_vals = wh.parameter.duobinary.values; rop_atten_vals = wh.parameter.rop_atten.values; -figure(177) - +figure(18) +tiledlayout(3, 3, 'TileSpacing', 'compact', 'Padding', 'compact'); +%CHANGE PAM FORMAT HERE (use 4,6,8) for M_choose = [8] sgtitle(['PAM',num2str(M_choose)]) for l = 1:numel(lambda_vals) + ber_vnle = []; + ber_vnle_mlse= []; + ber_db= []; + ber_db_enc= []; for b = 1:numel(bitrate_vals) cel = wh.getStoValue('ber_vnle',M_choose(1),lambda_vals(l),bitrate_vals(b),duobinary_vals(1),rop_atten_vals(1)); @@ -36,8 +41,8 @@ for M_choose = [8] end cols = linspecer(4); - subplot(3,3,l) - + %subplot(3,3,l) +nexttile; if M_choose == 4 lst = '-'; mkr = 'o'; @@ -56,24 +61,24 @@ for M_choose = [8] fsym_vals = floor( bitrate_vals*1e-9./log2(M_choose) ); hold on - plot(bitrate_vals*1e-9,ber_db,'Color',cols(1,:),'Marker',mkr,'MarkerFaceColor','auto','DisplayName','DB pre','LineStyle',lst,'HandleVisibility',hv); - plot(bitrate_vals*1e-9,ber_db_enc,'Color',cols(2,:)','Marker',mkr,'MarkerFaceColor','auto','DisplayName','DB enc','LineStyle',lst,'HandleVisibility',hv); - plot(bitrate_vals*1e-9,ber_vnle,'Color',cols(3,:),'Marker',mkr,'MarkerFaceColor','auto','DisplayName','VNLE','LineStyle',lst,'HandleVisibility',hv); - plot(bitrate_vals*1e-9,ber_vnle_mlse,'Color',cols(4,:),'Marker',mkr,'MarkerFaceColor','auto','DisplayName','VNLE+PF+MLSE','LineStyle',lst,'HandleVisibility',hv); + plot(bitrate_vals*1e-9,ber_db,'Color',cols(1,:),'Marker',mkr,'MarkerFaceColor','auto','DisplayName','DB pre','LineStyle',lst,'HandleVisibility',hv,'LineWidth',1); + plot(bitrate_vals*1e-9,ber_db_enc,'Color',cols(2,:)','Marker',mkr,'MarkerFaceColor','auto','DisplayName','DB enc','LineStyle',lst,'HandleVisibility',hv,'LineWidth',1); + plot(bitrate_vals*1e-9,ber_vnle,'Color',cols(3,:),'Marker',mkr,'MarkerFaceColor','auto','DisplayName','VNLE','LineStyle',lst,'HandleVisibility',hv,'LineWidth',1); + plot(bitrate_vals*1e-9,ber_vnle_mlse,'Color',cols(4,:),'Marker',mkr,'MarkerFaceColor','auto','DisplayName','VNLE+PF+MLSE','LineStyle',lst,'HandleVisibility',hv,'LineWidth',1); % Continue with the rest of your plot settings yline(3.8e-3, 'DisplayName', 'HD-FEC', 'LineStyle', '--', 'HandleVisibility', 'off'); yline(2e-2, 'DisplayName', '20%', 'LineStyle', '--','LineWidth',1, 'HandleVisibility', 'off'); - xlabel('Bitrate'); - ylabel('Bit Error Rate (BER)'); + %xlabel('Bitrate'); + ylabel('BER'); title([num2str(lambda_vals(l)),' nm']); set(gca, 'yscale', 'log'); set(gca, 'Box', 'on'); grid on; grid minor; - legend('Interpreter', 'none','Location','southwest'); - ylim([1e-4,1e-1]); + % legend('Interpreter', 'none','Location','southwest','Visible','off','HandleVisibility','off'); + ylim([8e-4,1e-1]); xlim([bitrate_vals(1)*1e-9,bitrate_vals(end)*1e-9]) end diff --git a/projects/HighSpeedExperiment_2024/single_auswertung_10km.m b/projects/HighSpeedExperiment_2024/single_auswertung_10km.m new file mode 100644 index 0000000..830e60b --- /dev/null +++ b/projects/HighSpeedExperiment_2024/single_auswertung_10km.m @@ -0,0 +1,87 @@ + +wh = load('C:\Users\Silas\Documents\MATLAB\Datensätze\sioe_labor\highspeed_oct_2024\10km_bitrate_complete\20241030_170224_wh.mat'); +wh = wh.obj; + +M_vals = wh.parameter.M.values; +M_choose = M_vals(1); +lambda_vals = wh.parameter.lambda.values; +bitrate_vals = wh.parameter.bitrate.values; +duobinary_vals = wh.parameter.duobinary.values; +rop_atten_vals = wh.parameter.rop_atten.values; + + +figure(11) + +l = 6; +for m = 1:numel(M_vals) + sgtitle(['Lambda: ',num2str(lambda_vals(l)),' nm']) + %for l = 1:numel(lambda_vals) + ber_vnle = []; + ber_vnle_mlse= []; + ber_db= []; + ber_db_enc= []; + for b = 1:numel(bitrate_vals) + + M_choose = M_vals(m); + + + cel = wh.getStoValue('ber_vnle',M_choose(1),lambda_vals(l),bitrate_vals(b),duobinary_vals(1),rop_atten_vals(1)); + ber_vnle(b)=min(cel{1}); + + cel = wh.getStoValue('ber_vnle_mlse',M_choose(1),lambda_vals(l),bitrate_vals(b),duobinary_vals(1),rop_atten_vals(1)); + ber_vnle_mlse(b)=min(cel{1}); + + cel = wh.getStoValue('ber_db',M_choose(1),lambda_vals(l),bitrate_vals(b),duobinary_vals(2),rop_atten_vals(1)); + ber_db(b)=min(cel{1}); + + cel = wh.getStoValue('ber_db',M_choose(1),lambda_vals(l),bitrate_vals(b),duobinary_vals(3),rop_atten_vals(1)); + ber_db_enc(b)=min(cel{1}); + + dcs_ = wh.getStoValue('dcs',M_choose(1),lambda_vals(l),bitrate_vals(b),duobinary_vals(2),rop_atten_vals(1)); + + + end + + cols = linspecer(4); + subplot(1,3,m) + + if M_choose == 4 + lst = '-'; + mkr = 'o'; + hv = 'on'; + elseif M_choose == 6 + lst = '-'; + mkr = 'x'; + hv = 'on'; + elseif M_choose == 8 + lst = '-'; + mkr = 'diamond'; + hv = 'on'; + end + + + fsym_vals = floor( bitrate_vals*1e-9./log2(M_choose) ); + hold on + + plot(bitrate_vals*1e-9,ber_db,'Color',cols(1,:),'Marker',mkr,'MarkerFaceColor','auto','DisplayName','DB pre','LineStyle',lst,'HandleVisibility',hv,'LineWidth',1); + plot(bitrate_vals*1e-9,ber_db_enc,'Color',cols(2,:)','Marker',mkr,'MarkerFaceColor','auto','DisplayName','DB enc','LineStyle',lst,'HandleVisibility',hv,'LineWidth',1); + plot(bitrate_vals*1e-9,ber_vnle,'Color',cols(3,:),'Marker',mkr,'MarkerFaceColor','auto','DisplayName','VNLE','LineStyle',lst,'HandleVisibility',hv,'LineWidth',1); + plot(bitrate_vals*1e-9,ber_vnle_mlse,'Color',cols(4,:),'Marker',mkr,'MarkerFaceColor','auto','DisplayName','VNLE+PF+MLSE','LineStyle',lst,'HandleVisibility',hv,'LineWidth',1); + + % Continue with the rest of your plot settings + + yline(3.8e-3, 'DisplayName', 'HD-FEC', 'LineStyle', '--', 'HandleVisibility', 'off'); + yline(2e-2, 'DisplayName', '20%', 'LineStyle', '--','LineWidth',1, 'HandleVisibility', 'off'); + xlabel('Bitrate'); + ylabel('Bit Error Rate (BER)'); + title(['PAM ',num2str(M_choose),' ']); + set(gca, 'yscale', 'log'); + set(gca, 'Box', 'on'); + grid on; + grid minor; + legend('Interpreter', 'none','Location','southwest'); + ylim([1e-4,1e-1]); + xlim([bitrate_vals(1)*1e-9,bitrate_vals(end)*1e-9]) + + %end +end diff --git a/projects/IMDD_base_system/filter_debug.m b/projects/IMDD_base_system/filter_debug.m deleted file mode 100644 index ad0a4be..0000000 --- a/projects/IMDD_base_system/filter_debug.m +++ /dev/null @@ -1,70 +0,0 @@ - -clear -%% Set Simulation Variables - -O = 18; %order of prbs -N = 2^(O-1); %length of prbs -[~,seed] = prbs(O,1); %initialize first seed of prbs - -% Modulation -M = 4; %PAM-M -bitpattern = zeros(N,log2(M)); - -% Symbol Rate -fsym = 112e9; - -% DAC Rate -fdac = 120e9; - -% Simulation oversampling rate "k"; -kover = 16; - -% ADC Rate -fadc = 256e9; - -% Simulation frequency in "analog domain" -fsimu = kover * fdac ; - - - -%% CONSTRUCT ALL CLASSES - -digimod = PAMmapper(M,0); - -pulsef = Pulseformer("pulseform","rrc","fdac",fdac,"fsym",fsym,"pulselength",32,"rrcalpha",0.05); - -awg = AWG('preset','M8199B','fdac',fdac,'kover',kover,'lpf_active',1,'f_cutoff',56e9,'lpf_type',filtertypes.gaussian,'bit_resolution',5.5); - -lp_laser = Filter('filtdegree',1,"f_cutoff",30e9,"fsamp",fdac,"filterType",filtertypes.bessel_inp); - - - -%% PROCESS - -% PRBS Generation -for i = 1:log2(M) - [bitpattern(:,i),seed] = prbs(O,N,seed); -end - -% Build Inf. signal class -bits = Informationsignal(bitpattern); - -% Digi Mod -mod_out = digimod.map(bits); -% merken für EQ training -reference = mod_out; - -% shape shape -mod_out = pulsef.process(mod_out); -test = applyPulseShaping(reference.signal,fsym,fdac); - -% AWG -> ELECTRICAL DOMAIN -X = lp_laser.process(mod_out); -%X.spectrum(fsimu,"displayname",'AWG out','figurename','after AWG'); - - - - - - - diff --git a/projects/IMDD_base_system/imdd_example_live.mlx b/projects/IMDD_base_system/imdd_example_live.mlx new file mode 100644 index 0000000..bf780bb Binary files /dev/null and b/projects/IMDD_base_system/imdd_example_live.mlx differ diff --git a/projects/IMDD_base_system/imdd_it.m b/projects/IMDD_base_system/imdd_it.m new file mode 100644 index 0000000..d0f4084 --- /dev/null +++ b/projects/IMDD_base_system/imdd_it.m @@ -0,0 +1,367 @@ + +% basePath = 'C:\Users\Silas\Documents\MATLAB\Datensätze\sioe_labor\'; +% db = DBHandler("pathToDB",[basePath,'silas_labor.db']); +if 1 + uloops = struct; + uloops.precomp = [0,1]; + uloops.db_precode = [0,1]; + uloops.bitrate = [300,330,360,390,420,450,480].*1e9; %[300,330,360,390,420,450,480] + % uloops.bitrate = 390e9; + % uloops.laser_wavelength = [1293,1297.5,1302,1306.5,1310,1313.4,1318,1322.7,1327.4]; + uloops.laser_wavelength = [1293]; + uloops.M = [4,6,8]; + uloops.link_length = [2]; % 1,2,3,5,6,8,10 + wh = DataStorage(uloops); + wh.addStorage("ber"); + + wh = submit_simulations(wh,"parallel",0,"simulation_mode",1); +end + +wh_ana = wh; + +ber_mlse = {}; +ber_vnle = {}; +inf_rate_vnle ={}; + +ber_dbtgt ={}; + +ber_dbenc ={}; +alpha = {}; +ber_dfe = {}; +ngmi = []; + +wavelength=1293; +for m = [4,6,8] + %1302 + %VNLE + precomp = 1; + precode = 0; + a = wh_ana.getStoValue('ber',precomp, precode, uloops.bitrate , wavelength, m, uloops.link_length); + ber_vnle = cellfun(@(x) x.vnle_pf_package{1,1}.ber_vnle, a); + + %MLSE + precomp = 0; + precode = 1; + a = wh_ana.getStoValue('ber',precomp, precode, uloops.bitrate , wavelength, m, uloops.link_length); + ber_mlse = cellfun(@(x) x.vnle_pf_package{1,1}.ber_mlse, a); + + %DB + precomp = 0; + precode = 1; + a = wh_ana.getStoValue('ber',precomp, precode, uloops.bitrate , wavelength, m, uloops.link_length); + ber_dbtgt = cellfun(@(x) x.dbtgt_package{1,1}.ber, a); + + figure(m+20) + hold on + title(sprintf('%d km | %d nm | PAM %d',uloops.link_length,wavelength,m)); + + plot(uloops.bitrate,ber_vnle,'DisplayName',sprintf('VNLE'),'Color',cols(3,:),'LineStyle','-','HandleVisibility','on'); + + plot(uloops.bitrate,ber_dbtgt,'DisplayName',sprintf('DB tgt. + MLSE',uloops.link_length,uloops.M),'Color',cols(1,:),'LineStyle','-','HandleVisibility','on'); + + plot(uloops.bitrate,ber_mlse,'DisplayName',sprintf('VNLE + 1 tap post-filter + MLSE',uloops.link_length,uloops.M),'Color',cols(4,:),'LineStyle','-','HandleVisibility','on'); + + set(gca, 'YScale', 'log'); + ylim([5e-5 0.3]); + % xlim([min(uloops.bitrate.*1e-9), max(uloops.bitrate.*1e-9) ]); + yline([3.8e-3, 2e-2],'HandleVisibility','off'); + legend + beautifyBERplot() + xlabel('Bit Rate in Gbps'); + ylabel('BER'); +end + + +cols = linspecer(7);%cbrewer2('Set2',10); + + +for w = uloops.laser_wavelength + + figure(w) + figcnt = 0; + + for precode = uloops.db_precode + + for precomp = uloops.precomp + + for m = uloops.M + + a = wh_ana.getStoValue('ber',precomp, precode, uloops.bitrate , w, m, uloops.link_length); + ber_dbtgt = cellfun(@(x) x.dbtgt_package{1,1}.ber, a); + + ber_vnle = cellfun(@(x) x.vnle_pf_package{1,1}.ber_vnle, a); + + ber_mlse = cellfun(@(x) x.vnle_pf_package{1,1}.ber_mlse, a); + + figcnt = figcnt+1; + subplot(4,3,figcnt); + hold on + title(sprintf('precomp = %d | precode = %d | %d km | %d nm | PAM %d',precomp,precode,uloops.link_length,w,m)); + + plot(uloops.bitrate,ber_dbtgt,'DisplayName',sprintf('DB tgt. + MLSE',uloops.link_length,uloops.M),'Color',cols(1,:),'LineStyle','-','HandleVisibility','on'); + + plot(uloops.bitrate,ber_vnle,'DisplayName',sprintf('VNLE'),'Color',cols(3,:),'LineStyle','-','HandleVisibility','on'); + + plot(uloops.bitrate,ber_mlse,'DisplayName',sprintf('VNLE + 1 tap post-filter + MLSE',uloops.link_length,uloops.M),'Color',cols(4,:),'LineStyle','-','HandleVisibility','on'); + + % plot(uloops.bitrate,cellfun(@min, ber_dfe),'DisplayName',sprintf('VNLE + DFE',uloops.link_length,uloops.M),'Color',cols(2,:),'LineStyle','--'); + + % plot(uloops.bitrate,cellfun(@min, ber_dbenc),'DisplayName',sprintf('DB Encoded',uloops.link_length,uloops.M),'Color',cols(5,:),'LineStyle','-'); + + set(gca, 'YScale', 'log'); + ylim([5e-5 0.5]); + % xlim([min(uloops.bitrate.*1e-9), max(uloops.bitrate.*1e-9) ]); + yline([3.8e-3, 2e-2],'HandleVisibility','off'); + legend + beautifyBERplot() + xlabel('Bit Rate in Gbps'); + ylabel('Channel Wavelength (nm)'); + + end + end + end +end + +tp = TransmissionPerformance; +netRatesVNLE = tp.calculateNetRate(uloops.bitrate, 'NGMI', cellfun(@min, inf_rate_vnle)./log2(uloops.M), 'BER', cellfun(@min, ber_vnle)); + +pam8= [2.9515 2.9284 2.9203 2.9311 2.8473 2.7740 2.6253]; +pam6 = [2.5280 2.5452 2.5579 2.5549 2.5272 2.4243 2.2617]; +pam4 = [ 1.9982 1.9972 1.9690 1.7909 1.2493 0.8014 0.6385]; + +figure(6) +hold on +title(sprintf('Performance at 1310 for all lengths')); +% plot(uloops.bitrate.*1e-9,cellfun(@min, inf_rate_vnle),'DisplayName',sprintf('NGMI VNLE; %d km',uloops.link_length),'Color',cols(3,:),'LineStyle',':'); +plot(uloops.bitrate.*1e-9,pam4/2,'DisplayName',sprintf('GMI VNLE; PAM 4'),'Color',cols(1,:),'LineStyle',':'); +plot(uloops.bitrate.*1e-9,pam6/log2(6),'DisplayName',sprintf('GMI VNLE; PAM 6'),'Color',cols(2,:),'LineStyle',':'); +plot(uloops.bitrate.*1e-9,pam8/3,'DisplayName',sprintf('GMI VNLE; PAM 8'),'Color',cols(3,:),'LineStyle',':'); +xlabel('Gross Bitrate in Gbps'); +ylabel('NGMI') +beautifyBERplot() +ylim([0,1]); + +figure() +title(sprintf('%d km | 1310 nm | PAM %d | VNLE',uloops.link_length,uloops.M)); +hold on +line([min(uloops.bitrate.*1e-9) max(uloops.bitrate.*1e-9)],[min(uloops.bitrate.*1e-9) max(uloops.bitrate.*1e-9)],'Color',[.7,.7,.7],'Marker','none','Handlevisibility','off'); +plot(uloops.bitrate.*1e-9,cellfun(@min, inf_rate_vnle).*uloops.bitrate./log2(uloops.M).*1e-9,'DisplayName',sprintf('AIR'),'Color',cols(1,:),'LineStyle',':'); +plot(uloops.bitrate.*1e-9,netRatesVNLE.SDHD.NetRate.*1e-9,'DisplayName',sprintf('SD+HD'),'Color',cols(2,:),'LineStyle',':'); +plot(uloops.bitrate.*1e-9,netRatesVNLE.HD.NetRate.*1e-9,'DisplayName',sprintf('HD'),'Color',cols(3,:),'LineStyle',':'); +plot(uloops.bitrate.*1e-9,netRatesVNLE.KP4_hamming.NetRate.*1e-9,'DisplayName',sprintf('KP4+Hamming'),'Color',cols(4,:),'LineStyle',':'); +beautifyBERplot() +xlim([min(uloops.bitrate.*1e-9) max(uloops.bitrate.*1e-9)]) +xlabel('Gross Bitrate in Gbps'); +ylabel('Net Bitrate in Gbps'); +legend + + +% plot(uloops.bitrate.*1e-9,ber_vnle,'DisplayName',sprintf('NGMI MLSE; %d km',len),'Color',cols(1,:),'LineStyle','-'); +% plot(uloops.bitrate.*1e-9,ber_dfe,'DisplayName',sprintf('NGMI MLSE; %d km',len),'Color',cols(1,:),'LineStyle','-'); +% plot(uloops.bitrate.*1e-9,ber_mlse,'DisplayName',sprintf('NGMI MLSE; %d km',len),'Color',cols(1,:),'LineStyle','-'); +% plot(uloops.bitrate.*1e-9,ber_db,'DisplayName',sprintf('NGMI VNLE; %d km',len),'Color',cols(2,:),'LineStyle','-'); +% +% set(gca, 'YScale', 'log'); +% ylim([1e-5, 0.1]); +% yline([3.8e-3;1e-2],'LineWidth',1,'HandleVisibility','off'); + + + + + +% for alpha = uloops.alpha +% for precode = uloops.db_precode +% for precomp = uloops.precomp +% +% +% cols = linspecer(6);%cbrewer2('Set2',10); +% cnt = 1; +% a = wh.getStoValue('ber',alpha,uloops.vnle_order2,uloops.vnle_order3,precomp, precode, uloops.bitrate,uloops.M); +% +% +% for i = 1:numel(a) +% ber_db(i) = mean((a{i}.ber_db)); +% ber_vnle(i) = mean((a{i}.ber_vnle)); +% ber_vnle_dfe(i) = mean((a{i}.ber_vnle_dfe)); +% ber_mlse(i) = mean((a{i}.ber_mlse)); +% pf_taps(i) = a{i}.pf_taps{1}(2); +% vnle_taps(i,:) = a{i}.eq_vnle{1}.e; +% +% figure(222) +% +% +% subplot(7,3,3*(i-1)+1) +% ylim([-0.5 1]); +% title(sprintf('%d GBps',uloops.bitrate(i).*1e-9)); +% hold on +% stem(a{i}.eq_vnle{1}.e) +% +% subplot(7,3,3*(i-1)+2) +% ylim([-0.5 1]); +% title(sprintf('%d GBps',uloops.bitrate(i).*1e-9)); +% hold on +% stem(a{i}.eq_vnle{1}.e2) +% +% subplot(7,3,3*(i-1)+3) +% ylim([-0.5 1]); +% title(sprintf('%d GBps',uloops.bitrate(i).*1e-9)); +% hold on +% stem(a{i}.eq_vnle{1}.e3) +% +% showEQNoisePSD(a{i}.noise_vnle{1},"fignum",220,"displayname",sprintf('%d 2nd order taps; %d GBps',vnle_order2,uloops.bitrate(i).*1e-9),"postfilter_taps",a{i}.pf_taps{1}); +% +% eq_sig = a{i}.signal_vnle{1}; +% +% +% end +% +% figure() +% hold on +% +% if precomp +% lsty = '-'; +% else +% lsty = '-'; +% end +% +% if precode +% coloffset = 1; +% else +% coloffset=1; +% end +% +% % plot(uloops.bitrate,ber_mlse,'DisplayName',sprintf('Precomp: %d; Precode %d',precomp,precode),'Color',cols(cnt,:)); +% title(sprintf('Precomp: %d; Precode %d',precomp,precode)); +% plot(uloops.bitrate.*1e-9,ber_vnle,'DisplayName','VNLE','Color',cols(4,:),'LineStyle',lsty); +% plot(uloops.bitrate.*1e-9,ber_vnle_dfe,'DisplayName','VNLE+DFE','Color',cols(2,:),'LineStyle',lsty); +% plot(uloops.bitrate.*1e-9,ber_mlse,'DisplayName','VNLE+PF+MLSE','Color',cols(3,:),'LineStyle',lsty); +% plot(uloops.bitrate.*1e-9,ber_db,'DisplayName','DB tgt.','Color',cols(1,:),'LineStyle',lsty); +% +% cnt = cnt+1; +% yline([3.8e-3;1e-2],'LineWidth',1,'HandleVisibility','off'); +% beautifyBERplot() +% end +% end +% end +% +% +% +% for vnle_order3 = uloops.vnle_order3([1,3,5,7,9,10]) +% cnt = 0; +% for vnle_order2 = 3%= uloops.vnle_order2 +% for precode = uloops.db_precode +% for precomp = uloops.precomp +% +% +% cols = linspecer(10);%cbrewer2('Set2',10); +% cnt = cnt+1; +% a = wh.getStoValue('ber',vnle_order2,vnle_order3,precomp, precode, uloops.bitrate,uloops.M); +% +% +% ber_db(cnt) = mean((a{1}.ber_db)); +% ber_vnle(cnt) = mean((a{1}.ber_vnle)); +% ber_vnle_dfe(cnt) = mean((a{1}.ber_vnle_dfe)); +% ber_mlse(cnt) = mean((a{1}.ber_mlse)); +% pf_taps(cnt) = a{1}.pf_taps{1}(2); +% +% showEQNoisePSD(a{1}.noise_vnle{1},"fignum",220,"displayname",sprintf('%d 3rd order taps; %d GBps',vnle_order3,uloops.bitrate(i).*1e-9)); +% +% eq_sig = a{1}.signal_vnle{1}; +% +% +% end +% end +% end +% +% figure(180) +% hold on +% scatter(uloops.vnle_order2,ber_mlse,'MarkerEdgeColor',cols(vnle_order3,:),'LineWidth',1,'DisplayName',sprintf('%d 3rd order taps',vnle_order3)); +% ylim([1e-3 0.5]); +% +% end +% title(sprintf('%d GBps',uloops.bitrate(i).*1e-9)); +% ylabel('BER'); +% xlabel('VNLE 2nd order taps'); +% yline([3.8e-3;1e-2],'LineWidth',1,'HandleVisibility','off'); +% beautifyBERplot() + +% r = 1; +% for rate = uloops.bitrate +% +% i = 1; +% for alpha = uloops.alpha +% cols = linspecer(7);%cbrewer2('Set2',10); +% cnt = 1; +% a = wh.getStoValue('ber',alpha,uloops.vnle_order2,uloops.vnle_order3,precomp, precode, rate,uloops.M); +% ber_mlse(i) = mean((a{1}.ber_mlse)); +% pf_taps(i) = a{1}.pf_taps{1}(2); +% i = i+1; +% end +% +% figure(150) +% hold on +% scatter(pf_taps(1),ber_mlse(1),200,'DisplayName','Burg','MarkerEdgeColor',cols(r,:),'Marker','x','LineWidth',2,'HandleVisibility','off'); +% plot(uloops.alpha(2:end),ber_mlse(2:end),'DisplayName',sprintf('%d GBps',rate.*1e-9),'Color',cols(r,:),'LineStyle','-'); +% r=r+1; +% +% end +% +% +% % title(sprintf('%d GBps',uloops.bitrate.*1e-9)); +% ylabel('BER'); +% xlabel('Alpha'); +% yline([3.8e-3;1e-2],'LineWidth',1,'HandleVisibility','off'); +% beautifyBERplot() +% +% +% +% figure(2024) +% hold on +% for j = 1:numel(uloops.vnle_order3) +% all2nd = wh.getStoValue('ber',uloops.vnle_order3(j), uloops.vnle_order2, uloops.bitrate,uloops.M); +% for i = 1:numel(a) +% ber_mlse(i) = all2nd{i}.ber_mlse; +% ber_vnle(i) = all2nd{i}.ber_vnle; +% pf_taps(:,i) = all2nd{i}.pf_taps; +% +% end +% plot(uloops.vnle_order2,ber_mlse,'DisplayName',sprintf('%d 3rd order',uloops.vnle_order3(j))); +% end +% +% yline(3.8e-3,'LineWidth',2,'DisplayName','3.8e-3'); +% yline(2e-2,'LineWidth',2,'LineStyle','--','DisplayName','2e-2'); +% beautifyBERplot() +% legend +% +% figure(2025) +% clf; % Clear figure so we start fresh +% +% numJ = numel(uloops.vnle_order3); +% numI = numel(uloops.vnle_order2); +% ber_mlse_mat = zeros(numJ, numI); +% +% % Gather data into a 2D matrix +% for j = 1:numJ +% all2nd = wh.getStoValue('ber', uloops.vnle_order3(j), uloops.vnle_order2, uloops.bitrate, uloops.M); +% for i = 1:numI +% ber_mlse_mat(j,i) = all2nd{i}.ber_mlse; +% end +% end +% +% % Create a 2D plot +% % 'imagesc' displays the matrix as an image with a colorbar. +% imagesc(uloops.vnle_order2, uloops.vnle_order3, ber_mlse_mat); +% set(gca,'YDir','normal'); % Ensure that lower vnle_order3 is at the bottom +% colorbar; % Add a colorbar to show BER scale +% +% xlabel('VNLE Order 2'); +% ylabel('VNLE Order 3'); +% title('BER MLSE as a function of VNLE Orders'); +% +% % If you want to highlight certain BER levels, you can add contour lines: +% hold on; +% [C,h] = contour(uloops.vnle_order2, uloops.vnle_order3, ber_mlse_mat, [3.8e-3, 2e-2], 'LineWidth',2,'LineColor','k'); +% clabel(C,h,'Color','k','FontWeight','bold'); +% +% beautifyBERplot(); +% legend('BER contour lines'); \ No newline at end of file diff --git a/projects/IMDD_base_system/imdd_model.m b/projects/IMDD_base_system/imdd_model.m new file mode 100644 index 0000000..49e6723 --- /dev/null +++ b/projects/IMDD_base_system/imdd_model.m @@ -0,0 +1,346 @@ +function [output] = imdd_model(simulation_mode,varargin) + +%%% Change folder +curFolder = pwd; +funcFolder=fileparts(mfilename('fullpath')); +if ~isempty(funcFolder) + cd(funcFolder); +end + +%%% Run parameters +% TX +M = 4; +fsym = 180e9; + +apply_pulsef = 1; +fdac = 256e9; +fadc = 256e9; +random_key = 1; + +precomp = 0; +db_precode = 0; + +db_encode = 0; + +rcalpha = 0.05; +kover = 16; +vbias_rel = 0.5; +u_pi = 2.9; +vbias = -vbias_rel*u_pi; +laser_wavelength = 1293; +laser_linewidth = 0; +tx_bw_nyquist = 0.8; + +% Channel +link_length = 1; + +% RX +rop = -8; +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]; + + +alpha = 0; + +len_tr = 4096*2; + +mu_ffe1 = 0.0001; +mu_ffe2 = 0.0008; +mu_ffe3 = 0.001; +mu_dc = 0.005; + +mu_ffe = [mu_ffe1 mu_ffe3 mu_ffe3]; +mu_dfe = 0.0004; + + +dfe_ = sum(dfe_order)>0; + +doub_mode = db_mode.db_precoded; + +%%% change specific parameter if given in varargin +% Parse optional input arguments +if ~isempty(varargin) + var_s = varargin{1}; + if isstruct(var_s) + fields = fieldnames(var_s); + for i = 1:numel(fields) + if isnumeric(fields{i}) + eval([fields{i}, ' = ', num2str( var_s.(fields{i}) ), ';']); + fprintf("%s <-- %.2f \n", fields{i}, var_s.(fields{i})); + else + eval([fields{i}, ' = ', 'var_s.(fields{',num2str(i),'})' , ';']); + end + + end + else + error('Optional variables should be passed as a struct.'); + end +end + +if doub_mode ~= db_mode.db_encoded + if precomp == 0 && db_precode == 1 + doub_mode = db_mode.db_precoded; + + db_precode = 1; % preceded data (in my measurement set, this corresponds to low precomp too!) + discard_precode = 0; % + emulate_precode = 0; + legendentry = 'low precomp; precoded'; + disp('low precomp; precoded') + elseif precomp == 1 && db_precode == 1 + doub_mode = db_mode.db_emulate; + + db_precode = 0; % preceded data (in my measurement set, this corresponds to low precomp too!) + discard_precode = 0; % + emulate_precode = 1; + legendentry = 'high precomp; precoded'; + disp('high precomp; precoded') + elseif precomp == 0 && db_precode == 0 + doub_mode = db_mode.db_discard; + + db_precode = 1; % preceded data (in my measurement set, this corresponds to low precomp too!) + discard_precode = 1; % + emulate_precode = 0; + legendentry = 'no precomp; not precoded'; + disp('no precomp; not precoded') + elseif precomp == 1 && db_precode == 0 + doub_mode = db_mode.no_db; + + db_precode = 0; % preceded data (in my measurement set, this corresponds to low precomp too!) + discard_precode = 0; % + emulate_precode = 0; + legendentry = 'high precomp; not precoded'; + disp('high precomp; not precoded') + end +else + +end + +fsym_ = floor( bitrate*1e-9./log2(M) ).*1e9; + +if fsym_ ~= fsym + fsym = fsym_; + % fprintf('Adapted symbolrate to %d GBd, to match provided bitrate of %d GBit/s using PAM %d \n',fsym.*1e-9,bitrate.*1e-9, M); +end +f_nyquist = fsym/2; + +%%% run the simulation or measurement or ... +if simulation_mode + + Pform = Pulseformer("fsym",fsym,"fdac",4*fsym,"pulse","rrc","pulselength",16,"rrcalpha",rcalpha); + + [Digi_sig,Symbols,Tx_bits] = PAMsource(... + "fsym",fsym,"M",M,"order",17,"useprbs",1,... + "fs_out",fdac,... + "applyclipping",0,"clipfactor",1.5,... + "applypulseform",apply_pulsef,"pulseformer",Pform,... + "randkey",random_key,... + "db_precode",db_precode,"db_encode",db_encode,... + "mrds_code",0,"mrds_blocklength",512).process(); + + % Digi_sig.spectrum("displayname",'Digi Spectrum','fignum',10,'normalizeTo0dB',1); + + %%%%% 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',100,'normalizeTo0dB',0); + % El_sig = El_sig.setPower(0,"dBm"); + + %%%%% Low-pass el. components %%%%%% + tx_bwl = tx_bw_nyquist.*f_nyquist; + % tx_bwl = 80e9; + El_sig = Filter('filtdegree',4,"f_cutoff",tx_bwl,"fs",fdac*kover,"filterType",filtertypes.butterworth,"active",true).process(El_sig); + % El_sig.spectrum("displayname",'Digi Spectrum','fignum',100,'normalizeTo0dB',1); + + %%%%% 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"); + + %%%%% 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).process(El_sig); + + Opt_sig = Fiber("fsimu",Opt_sig.fs,"fiber_length",link_length/1000,"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 = rx_bw_nyquist.*f_nyquist; + % 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); + + % Rx_sig.spectrum("displayname",'Analog Rx Spectrum','fignum',100,'normalizeTo0dB',1); + + %%%%%% 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); + + Scpe_cell{1} = Scpe_sig; + +else + profile on + basePath = 'C:\Users\Silas\Documents\MATLAB\Datensätze\sioe_labor\'; + database = DBHandler("pathToDB",[basePath,'silas_labor.db']); + profile off + basePath = 'C:\Users\Silas\Documents\MATLAB\Datensätze\sioe_labor\'; + useGui = 0; + % db = DBHandler("pathToDB",[basePath,'silas_labor.db']); + filterParams = database.tables; + % filterParams.Runs.run_id = 2958; % no db + % filterParams.Runs.run_id = 2937; % no db + filterParams.Configurations = struct( ... + 'bitrate', bitrate, ... + 'db_mode', db_precode+db_encode, ... + 'fiber_length', link_length, ... + 'interference_attenuation', [], ... + 'interference_path_length', [], ... + 'is_mpi', 0, ... + 'pam_level', M, ... + 'precomp_amp', [], ... + 'rop_attenuation', 0, ... + 'symbolrate', [], ... + 'v_awg', [], ... + 'v_bias', [], ... + 'wavelength', laser_wavelength ... + ); + + selectedFields = {'Runs.run_id','Runs.tx_bits_path', 'Runs.tx_symbols_path', 'Runs.rx_sync_path','Runs.rx_raw_path',... + 'Configurations.db_mode','Configurations.pam_level','Configurations.bitrate','Configurations.symbolrate','Configurations.fiber_length','Configurations.wavelength','Configurations.precomp_amp','Measurements.power_rop','Configurations.v_bias'}; + + [dataTable,sql_query] = database.queryDB(filterParams, selectedFields); + [~, uniqueIdx] = unique(dataTable.run_id); % Get unique run_id indices + dataTable = dataTable(uniqueIdx,:); % Extract unique configurations for each run_id + fprintf('Found %d entries for requested Configuration. IDs are: %s \n \n',size(dataTable,1),jsonencode(dataTable.run_id(1:min(size(dataTable,1),100)))); + + Tx_bits = load([basePath, char(dataTable.tx_bits_path(end))]); + Tx_bits = Tx_bits.Bits; + + Symbols = load([basePath, char(dataTable.tx_symbols_path(end))]); + Symbols = Symbols.Symbols; + + Scpe_load = load([basePath, char(dataTable.rx_sync_path(end))]); + Scpe_cell = Scpe_load.S; + + + % Raw_signal = load([basePath, char(dataTable.rx_raw_path(1))]); + % Raw_signal = Raw_signal.Scpe_sig_raw; + % + % Raw_signal = Filter('filtdegree',4,"f_cutoff",Symbols.fs.*0.55,"fs",Raw_signal.fs,"filterType",filtertypes.gaussian,"active",true).process(Raw_signal); + % + % Scpe_cell{1}.eye(fsym,M,"displayname",'eye','fignum',227); + % + % Raw_signal.spectrum("normalizeTo0dB",0,"fignum",336,"fft_length",2^12); + % Raw_signal.move_it_spectrum("fignum",334); + + fsym = Symbols.fs; + +end + +if db_precode + Symbols_precoded = Symbols; +end + +output = struct(); +vnle_pf_package = {}; +vnle_dfe_package = {}; +dbtgt_package = {}; + + +proc_occ = min(8,length(Scpe_cell)); +for occ = 1:proc_occ + + Scpe_sig = Scpe_cell{occ}; + + %%%%%% Sample to 2x fsym %%%%%% + Scpe_sig = Scpe_sig.resample("fs_out",2*fsym); + + %%%%%% Sync Rx signal with reference %%%%%% + % [Scpe_sig,~] = Scpe_sig.tsynch("reference",Symbols,"fs_ref",fsym); + + 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); + + %%% EQUALIZING + + + % eq_mlse = FFE_DCremoval("epochs_tr",5,"epochs_dd",5,"len_tr",len_tr,"mu_dd",mu_ffe(1),"mu_tr",0,"order",ffe_order(1),"sps",2,"decide",0,"dc_buffer_len",1,"mu_dc",0.05); + % eq_mlse = FFE("epochs_tr",5,"epochs_dd",5,"len_tr",len_tr,"mu_dd",mu_ffe(1),"mu_tr",0,"order",ffe_order(1),"sps",2,"decide",0); + % eq_mlse = FFE_DCremoval("epochs_tr",5,"epochs_dd",5,"len_tr",len_tr,"mu_dd",mu_ffe(1),"mu_tr",0,"order",ffe_order(1),"sps",2,"decide",0,"dc_buffer_len",512,"mu_dc",0.05); + + mu_ffe = [mu_ffe1 mu_ffe2 mu_ffe3]; + + % %%%%% VNLE + DFE %%%% + if 0 + eq_vnle_dfe = EQ("Ne",vnle_order,"Nb",[0,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",1,"ideal_dfe",0); + + [result] = vnle(eq_vnle_dfe,M,Scpe_sig,Symbols,Tx_bits,"precode_mode",doub_mode,"showAnalysis",0); + vnle_dfe_package{occ} = result; + + + end + %%%%% VNLE + PF + MLSE %%%% + if 1 + + % len_tr = length(Symbols)-1000; + eq_vnle_ = EQ("Ne",vnle_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); + % eq_vnle_ = VNLE("epochs_tr",5,"epochs_dd",5,"len_tr",4096*2,"mu_dd",[0.0004 0.0005 0.0006],"mu_tr",0,"order",vnle_order,"sps",2,"decide",0); + pf_ = Postfilter("ncoeff",1,"useBurg",1); + mlse_ = MLSE_viterbi("duobinary_output",0,'M',M,'trellis_states',PAMmapper(M,0).levels); + + [result] = vnle_postfilter_mlse(eq_vnle_,pf_,mlse_,M,Scpe_sig,Symbols,Tx_bits,"precode_mode",doub_mode,'showAnalysis',1); + vnle_pf_package{occ} = result; + + end + + + %%%%% Duobinary Targeting %%%% + if 1 + + mlse_db = MLSE_viterbi("DIR",[1,1],"duobinary_output",0,"M",M,"trellis_states",PAMmapper(M,0).levels); + eq_db = EQ("Ne",vnle_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); + + [result] = duobinary_target(eq_db, mlse_db, M, Scpe_sig, Symbols, Tx_bits, "precode_mode", doub_mode,'showAnalysis',1); + dbtgt_package{occ} = result; + + + end + + %%%%%% %db signaling => db encoded %%%%% + if 0 + mlse_db_enc = MLSE_viterbi("DIR",[1,1],"duobinary_output",0,"M",M,"trellis_states",PAMmapper(M,0).levels); + eq_db_enc = EQ("Ne",vnle_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); + [result] = duobinary_signaling(eq_db_enc, mlse_db_enc,M, Scpe_sig ,Symbols, Tx_bits); + dbenc_package{occ} = result; + end + + + % autoArrangeFigures; + disp('- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ') + fprintf('\n') + + +end + +output.vnle_dfe_package = vnle_dfe_package; +output.vnle_pf_package = vnle_pf_package; +output.dbtgt_package = dbtgt_package; + +if ~isempty(curFolder) + cd(curFolder); +end + +end \ No newline at end of file diff --git a/projects/IMDD_base_system/imddmodel.m b/projects/IMDD_base_system/imddmodel.m deleted file mode 100644 index b3879bf..0000000 --- a/projects/IMDD_base_system/imddmodel.m +++ /dev/null @@ -1,227 +0,0 @@ -function output = imddmodel(sir,dcmode) - -for realiz = 1:3 - - rng(realiz); - - %% Set Simulation Variables - delay = 0;10+(10*realiz); %mpi delay in meter - - fiblen = 0; %main link in km - - laser_linewidth =0e6; - - O = 18; %order of prbs - N = 2^(O-1); %length of prbs - [~,seed] = prbs(O,1); %initialize first seed of prbs - - % Modulation - M = 4; %PAM-M - bitpattern = zeros(N,log2(M)); - - % Symbol Rate - fsym = 112e9; - - % DAC Rate - fdac = 120e9; - - % Simulation oversampling rate "k"; - kover = 16; - - % ADC Rate - fadc = 256e9; - - % Simulation frequency in "analog domain" - fsimu = kover * fdac ; - - - - %% B) CONSTRUCT ALL CLASSES %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - - digimod = PAMmapper(M,0); - - pulseform = Pulseformer("pulseform","rrc","fdac",fdac,"fsym",fsym,"pulselength",32,"rrcalpha",0.027); - - awg = AWG('fdac',fdac,'kover',kover,'lpf_active',1,'f_cutoff',56e9,'lpf_type',filtertypes.gaussian,'bit_resolution',5.5); - - lp_laser = Filter('filtdegree',1,"f_cutoff",50e9,"fsamp",fdac*kover,"filterType",filtertypes.bessel_inp); - - u_pi = 3.5; - vbias = (0.5*u_pi)-u_pi; - extmodlaser = EML("mode",eml_mode.im_cosinus,"power",5,"fsimu",fsimu,"lambda",1550,"bias",vbias,"u_pi",u_pi,"linewidth",laser_linewidth); - - fib = Fiber("fsimu",fdac*kover,"fiber_length",fiblen,"alpha",0.2,"D",16,"lambda0",thz2nm(193.1),"gamma",0); - - reflectionpoint = Amplifier("amp_mode","ideal_no_noise","gain_mode","gain","amplification_db",sir); - reflectionprop = Fiber("fsimu",fdac*kover,"fiber_length",delay/1000,"alpha",0.2,"D",16,"lambda0",1550,"gamma",0); - - opticatten = Amplifier("amp_mode","ideal_no_noise","gain_mode","output_power","amplification_db",-8); - - phdiode = Photodiode("fsimu",fdac*kover,"dark_current",2e-08,"responsivity",1,"temperature",20); - - lp_diode = Filter('filtdegree',1,"f_cutoff",50e9,"fsamp",fdac*kover,"filterType",filtertypes.bessel_inp); - - scp = Scope("fsimu",fdac*kover,"fadc",fadc,... - "delay",0,"fixed_delay",0,"lpf_bw",113e9,"filtertype",filtertypes.butterworth,... - "samplingdelay",0,"rand_samplingdelay",0,"freq_offset",0,"samp_jitter",0,... - "adcresolution",6,"quantbuffer",0.1,'block_dc',1); - - eq = EQ("K",2,"plottrain",0,"plotfinal",0,... - "training_length",4096,"training_loops",2,... - "Ne",[50,5,3],"Nb",[3,2,2],... - "DCmu",0.05,"DDmu",[0.0004 0.0005 0.0006 0.0007 ],"DFEmu",0.005,"FFEmu",0.005,... - "dd_loops",2,"epsilon",[10 100 1000 ],"M",2,... - "thres",[0.005 0.004 0.0005 ],"l1act",0,"delay",0,"rho",0.0005,"ideal_dfe",0,"DB_aim",0); - - eq2 = EQ_silas("Ne",[20,0,0],"Nb",[3,0,0],"trainlength",4096,"mu_dc_dd",0.005,"mu_dc_train",0.05,... - "mu_ffe_train",0.005,"mu_combined_dd",[0.0004 0.0006 0.0003 0.005],"ddloops",3,"dcmode",dcmode); - - - %% C) PROCESS TX %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - - % 1) PRBS Generation - for i = 1:log2(M) - [bitpattern(:,i),seed] = prbs(O,N,seed); - end - - % 2 ) Build Inf. signal class - bits = Informationsignal(bitpattern); - - % 3) Digi modulation -> PAM-M signal - digimod_out = digimod.map(bits); - - % 4) Pulse shaping -> racos - X = pulseform.process(digimod_out); - - % 5) AWG (lowpass, quantization, sample and hold) - X = awg.process(X); - - % 6) Lowpass behavior of laser and hf-cable? why twice? - X = lp_laser.process(X); - X = lp_laser.process(X); - - % 7) Normalize signal - X = X.normalize("mode","oneone"); - X.signal = X.signal .* 1.3800; - - - - %% D) PROCESS OPTICAL CHANNEL %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - - % 1) Laser; Modulation -> OPTICAL DOMAIN - [X,extmodlaser] = extmodlaser.process(X); - - % 2) Main fiber propagation - X = fib.process(X); - - if delay ~= 0 - - % 3) Reflection - % Reflection is just an attenuation - R = reflectionpoint.process(X); - - % Propagate back and forth (actual fiber propagation) - R = reflectionprop.process(R); - - % Delay the reflected signal - [R,n] = R.delay("delay_meter",delay); - - % Add together - X.signal = X.signal(n:end); - R.signal = R.signal(n:end); - - %disp(['SIR ',num2str(10*log10(X.power/R.power))]); - - X = X+R; - - % 4) Equalize - % cut reference signal to correct length (nessecary due to MPI delay) - digimod_out.signal = digimod_out.signal(round(n * fsym/fsimu) : end,:); - bitpattern = bitpattern(round(n * fsym/fsimu):end,:); - end - - % 4) Attenuation - X = opticatten.process(X); - % X = edfaamp.process(X); - - % 5) Photo Diode -> ELECTRICAL DOMAIN - X = phdiode.process(X); - X = lp_diode.process(X); - - - %% E) PROCESS RX %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - - % 1) Oscilloscope (Sampling to f_adc; Quantization; Bandwidth Limitation) - X = scp.process(X); - - % 2) Resample to 2x symbol rate - X = X.resample("fs_out",2*fsym,"fs_in",fadc); - - % 3) Normalize - Eq_in = X.normalize("mode","rms"); - - - - % MPI reduction DC removal BEFORE EQ - wl = 3000; % symbols - Eq_in.signal = Eq_in.signal - 1/wl .* movsum( Eq_in.signal,[wl/2,wl/2]); - - % Equalize Signal - [Eq_out] = eq2.process(Eq_in,digimod_out); - - - - - %% A1: MPI reduction DC removal - wl = 1000; % symbols - yk_dcsm = Eq_out; - yk_dcsm.signal = Eq_out.signal - 1/wl .* movsum( Eq_out.signal,[wl/2,wl/2]); - - %% A2: MPI reduction Level wise error removal - yk_lvsm = Eq_out; - yk_lvlp = Eq_out; - pre_decision_level_uni = digimod.decide_pamlevel(Eq_out); - pre_decision_level_bi = ( pre_decision_level_uni*2-3 ) .* 1/sqrt(5); - - e = Eq_out.signal - pre_decision_level_bi; - - lp_mpi = Filter('filtdegree',1,"f_cutoff",2e6,"fsamp",fsym,"filterType",filtertypes.bessel_inp); - - filtered = lp_mpi.process(e); - - wl = 30; % symbols - smoothed = ( 1/wl .* movsum(e,[wl/2,wl/2]) ); - - % remove interference - for level = 0:3 - yk_lvsm.signal(pre_decision_level_uni==level) = yk_lvsm.signal(pre_decision_level_uni==level) - smoothed(pre_decision_level_uni==level); - yk_lvlp.signal(pre_decision_level_uni==level) = yk_lvlp.signal(pre_decision_level_uni==level) - filtered(pre_decision_level_uni==level); - end - - %% PROCESS RX %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - - % 1) Digi Demod - d_bm = digimod.demap(Eq_out); - d_dcsm = digimod.demap(yk_dcsm); - d_lvsm = digimod.demap(yk_lvsm); - d_lvlp = digimod.demap(yk_lvlp); - - % 2) BER - - dbit = length(d_bm.signal)-length(bitpattern); - - [~,errors_bm,ber_bm(realiz),loc] = calc_ber(d_bm.signal(1:end-dbit,:) ,bitpattern(1:end,:),"skip",0,"returnErrorLocation",1); - [~,errors_dcsm,ber_dcsm(realiz)] = calc_ber(d_dcsm.signal(1:end-dbit,:) ,bitpattern(1:end,:),"skip",0,"returnErrorLocation",0); - [~,errors_lvsm,ber_lvsm(realiz)] = calc_ber(d_lvsm.signal(1:end-dbit,:) ,bitpattern(1:end,:),"skip",0,"returnErrorLocation",0); - [~,errors_lvlp,ber_lvlp(realiz)] = calc_ber(d_lvlp.signal(1:end-dbit,:) ,bitpattern(1:end,:),"skip",0,"returnErrorLocation",0); - - -end - -output.ber_bm = mean(ber_bm); -output.ber_dcsm = mean(ber_dcsm); -output.ber_lvsm = mean(ber_lvsm); -output.ber_lvlp = mean(ber_lvlp); - - -end \ No newline at end of file diff --git a/projects/IMDD_base_system/parameters.m b/projects/IMDD_base_system/parameters.m new file mode 100644 index 0000000..e329a37 --- /dev/null +++ b/projects/IMDD_base_system/parameters.m @@ -0,0 +1,46 @@ +% TX + M = 4; + fsym = 180e9; + f_nyquist = fsym/2; + apply_pulsef = 0; + fdac = 2*fsym;%256e9; + fadc = 2*fsym;%256e9; + fdac = 256e9; + fadc = 256e9; + random_key = 1; + db_precode = 0; + emulate_precode = 0; + discard_precode = 0; + db_encode = 0; + % duob_mode = db_mode.db_emulate; + emulate_db = 1; + rcalpha = 0.05; + kover = 16; + vbias_rel = 0.5; + u_pi = 2.9; + vbias = -vbias_rel*u_pi; + laser_wavelength = 1310; + laser_linewidth = 0; + tx_bw_nyquist = 1.5; + +% Channel + link_length = 1; + +% RX + rop = -8; + rx_bw_nyquist = 0.7; + +% EQ + eq_mode = equalizer_structure.vnle_pf_mlse; + ffe_order=[50,0,0]; + vnle_order=[50,7,7]; + dfe_order = [2 0 0]; + + len_tr = 4096*2; + mu_ffe = [0.0004 0.0004 0.0004]; + mu_dfe = 0.0004; + mu_dc = 0.00; + + dfe_ = sum(dfe_order)>0; + + \ No newline at end of file diff --git a/projects/IMDD_base_system/run_loop.m b/projects/IMDD_base_system/run_loop.m deleted file mode 100644 index 2041d50..0000000 --- a/projects/IMDD_base_system/run_loop.m +++ /dev/null @@ -1,208 +0,0 @@ - -clear - -sir_loop = [-25:2:-13]; -sir_loop = 0; -lw_loop = [1,2,3]; - -data = cell(length(sir_loop),length(lw_loop)); - -iterations=size(data); - -parfor ix = 1:numel(data) - - [u1,u2] = ind2sub(iterations,ix); - - output = imddmodel(sir_loop(u1),lw_loop(u2)); - - data{ix} = output; - -end - -for sir = 1:size(data,1) - for lw = 1:size(data,2) - ber_bm(sir,lw) = data{sir,lw}.ber_bm; - ber_dcsm(sir,lw) = data{sir,lw}.ber_dcsm; - ber_lvsm(sir,lw) = data{sir,lw}.ber_lvsm; - ber_lvlp(sir,lw) = data{sir,lw}.ber_lvlp; - end -end - -col = [ 0.6510 0.8078 0.8902 - 0.6980 0.8745 0.5412 - 0.9922 0.7490 0.4353]; -figure(22) -for l = 1:numel(lw_loop) - hold on - plot(sir_loop,ber_bm(:,l),'DisplayName',['DC mode:', num2str(lw_loop(l)),', Linewidth= 50 MHz'],'Marker','o','MarkerFaceColor',col(l,:),'Color',col(l,:),'LineWidth',2,'LineStyle','--'); -end -set(gca,'yscale','log'); -yline(3.8e-3,'LineWidth',2,'LineStyle','--','HandleVisibility','off'); -set(gca,'xdir','reverse'); - - - -%% Plot -col = linspecer(8); -figure(1) -hold on -m = ["x","o","pentagram","hexagram","*","+"]; -cnt = 1; -for d = 1%:size(data,2) - for dc = 1:size(data,1) - for lw = 1:size(data,3) - ber_bm(dc,d,lw) = (data{dc,d,lw}.ber_bm); - ber_dcsm(dc,d,lw) = data{dc,d,lw}.ber_dcsm; - ber_lvsm(dc,d,lw) = data{dc,d,lw}.ber_lvsm; - ber_lvlp(dc,d,lw) = (data{dc,d,lw}.ber_lvlp); - end - end - i = 1; - comm_dn = [];% ['EQ DC Tap: ',num2str(dc_tap_loop(d)),' m']; - title("Dependency on Laser Linewidth; B2B; Delay : 2*50m") - plot(lw_loop*1e-6,mean(squeeze(ber_bm(1:end,d,:)),1),"LineWidth",1.2,"Marker",m(1),"MarkerSize",5,'Color',col(cnt,:),'DisplayName',[' ',comm_dn]); - plot(lw_loop*1e-6,mean(squeeze(ber_dcsm(1:end,d,:)),1),"LineWidth",1,"Marker",m(1+4),"MarkerSize",5,'LineStyle','--','Color',col(cnt,:),'DisplayName',['DC smoothing ',comm_dn],'HandleVisibility','on'); - plot(lw_loop*1e-6,mean(squeeze(ber_lvsm(1:end,d,:)),1),"LineWidth",1.2,"Marker",m(1+1),"MarkerSize",5,'LineStyle',':','Color',col(cnt,:),'DisplayName',['Lvl Smoothing ',comm_dn],'HandleVisibility','on'); - plot(lw_loop*1e-6,mean(squeeze(ber_lvlp(1:end,d,:)),1),"LineWidth",1,"Marker",m(1+3),"MarkerSize",5,'LineStyle','-.','Color',col(cnt,:),'DisplayName',['Lvl Lowpass ',comm_dn],'HandleVisibility','on'); - set(gca,'yscale','log'); - set(gca,'xscale','log'); - %xticklabels([10 100 1000 10000]); - grid minor - yline(3.8e-3,'LineWidth',2,'LineStyle','--','HandleVisibility','off'); - ylim([1e-3 4e-2]); - ylabel("BER"); - xlabel("Linewidth in MHz") - legend - cnt = cnt+1; -end - - -figure(1) -contour(lw_loop,sir_loop,thres_a0,16:0.4:21,'LineWidth',2,'FaceAlpha',0.3,'ShowText','on',"LabelFormat","%0.1f dB"); -clim([16 21]); -ylabel("Bandwidth in Multiples of Linewidth"); -xlabel("Linewidth in MHz"); -% set(gca,'yscale','log'); -grid minor -title("MPI removal - Optimization of Lowpass Filter Bandwidth") - -figure(2) -contour(lw_loop,sir_loop([1:10,12:end]),thres_a0([1:10,12:end],:),16:0.3:21,'LineWidth',2,'FaceAlpha',0.3,'ShowText','on',"LabelFormat","%0.1f dB"); -clim([16 21]); -ylabel("Window Length"); -xlabel("Linewidth in MHz"); -set(gca,'yscale','log'); -grid minor -title("MPI removal - Optimization of Averaging Window Length") - - - -%% Plot Winlen Contour -hdfec = 3.8e-3.*ones(size(sir_loop)); - -for dc = 1:size(data,2) - for lw = 1:size(data,3) - for s = 1:size(data,1) - ber_lvlp(s,dc,lw) = data{s,dc,lw}.ber_dcsm; - % ber_dcsm(wl,lw,s) = data{wl,s,lw}.ber_dcsm; - end - - a_bm = InterX([sir_loop;squeeze(ber_lvlp(:,dc,lw))'],[sir_loop;hdfec]); - % a_dcsm = InterX([sirloop;squeeze(ber_dcsm(wl,lw,:))'],[sirloop;hdfec]); - try - thres_a0(dc,lw) = -a_bm(1); - %thres_a1(wl,lw) = -a_dcsm(1); - catch - thres_a0(dc,lw) = NaN; - %thres_a1(wl,lw) = NaN; - end - - end -end - -figure(1) -contour(lw_loop,bw_loop,thres_a0,14:0.2:21,'LineWidth',1.5,'FaceAlpha',0.3,'ShowText','on',"LabelFormat","%0.1f dB"); -a = flip(cbrewer2('seq','Spectral',32)); -a = [a(1:12,:); a(22:end,:)]; -colormap(a); -clim([16 21]); -ylabel("Window Length"); -xlabel("Linewidth in MHz"); -yticks(bw_loop); -yticklabels(bw_loop); -set(gca,'yscale','log'); -set(gca,'xscale','log'); -grid minor - - - - -%% Plot DC Tap Contour -hdfec = 3.8e-3.*ones(size(bw_loop)); -thres_a0 = zeros(size(ber,1),size(ber,3)); -thres_a1 = zeros(size(ber,1),size(ber,3)); -for dc = 1:size(ber,1) - for lw = 1:size(ber,3) - a_lvsm = InterX([bw_loop;ber(dc,:,lw)],[bw_loop;hdfec]); - thres_a0(dc,lw) = -a_lvsm(1); - - a1 = InterX([bw_loop;ber_a1(dc,:,lw)],[bw_loop;hdfec]); - thres_a1(dc,lw) = -a1(1); - end -end - -figure(1) -subplot(2,1,1) -contour(lw_loop,sir_loop,thres_a0,16:0.5:21,'LineWidth',3,'FaceAlpha',0.3,'ShowText','on',"LabelFormat","%0.1f dB"); -clim([16 21]); -ylabel("DC Tap"); -xlabel("Linewidth in MHz"); -set(gca,'yscale','log'); -grid minor -subplot(2,1,2) -contour(lw_loop,sir_loop,thres_a1,16:0.5:21,'LineWidth',3,'FaceAlpha',0.3,'ShowText','on',"LabelFormat","%0.1f dB"); -clim([16 21]); -ylabel("DC Tap"); -xlabel("Linewidth in MHz"); -set(gca,'yscale','log'); -grid minor - -%% Plot Curves of required SIR to see the minimum a bit better -col = flip(cbrewer2('seq','Spectral',16)); -col = col([1:4, 10:end],:); -figure(2) -hold on -for lw = [size(ber,3):-2:2 2 1] - plot(sir_loop,thres_a0(:,lw),'DisplayName',[' Linewidth: ',num2str(lw_loop(lw)*1e-6), ' MHz'],'Color',col(lw,:),'Marker','o','MarkerFaceColor',col(lw,:),'LineWidth',2); - set(gca,'xscale','log'); -end -xlabel("DC Tap Value"); -ylabel("Required SIR to rech FEC in dB"); - -%% -col = linspecer(7); -figure(3) -cnt=1; -for lw = [1,2,11] - - for i = 1:length(sir_loop)-1 - - subplot(1,3,cnt) - hold on - plot(-1.*bw_loop,ber(i,:,lw),"LineWidth",2,"Marker","o","MarkerSize",5,'Color',col(i,:),'DisplayName',['DC tap ',num2str(sir_loop(i))]); - plot(-1.*bw_loop,ber_a1(i,:,lw),"LineWidth",2,"Marker","x","MarkerSize",5,'LineStyle','--','Color',col(i,:),'DisplayName',['A1. DC tap ',num2str(sir_loop(i))]); - yline(3.8e-3,'LineWidth',2,'LineStyle','--','HandleVisibility','off'); - set(gca,'yscale','log'); - grid minor - - xlim([15,30]); - ylim([1e-4,1e-2]); - xlabel("SIR in dB"); - ylabel("BER"); - title(['BER for different SIR;',' Linewidth: ',num2str(lw_loop(lw)*1e-6), ' MHz']) - text(25,4.2e-3,"FEC $3.8 e^{-3}$"); - end - cnt = cnt+1; -end -legend - diff --git a/projects/IMDD_base_system/rx_simulation.m b/projects/IMDD_base_system/rx_simulation.m new file mode 100644 index 0000000..f105bf4 --- /dev/null +++ b/projects/IMDD_base_system/rx_simulation.m @@ -0,0 +1,24 @@ + + + %%%%%% 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_sig = Filter('filtdegree',4,"f_cutoff",rx_bw_nyquist.*f_nyquist,"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); + + % Rx_sig.spectrum("displayname",'Analog Rx Spectrum','fignum',100,'normalizeTo0dB',1); + + %%%%%% 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); + diff --git a/projects/IMDD_base_system/setup_simulation.m b/projects/IMDD_base_system/setup_simulation.m deleted file mode 100644 index 324a409..0000000 --- a/projects/IMDD_base_system/setup_simulation.m +++ /dev/null @@ -1,399 +0,0 @@ - - -lw = [0.1e6 1e6 10e6]; - -for lp = 1 - - rng(9); - - %% A) Set Simulation Variables - - sir = -18; - delay = 50; %mpi delay in meter - - fiblen = 0; %main link in km - - laser_linewidth =5e6; - - O = 19; %order of prbs - N = 2^(O-1); %length of prbs - [~,seed] = prbs(O,1); %initialize first seed of prbs - - % Modulation - M = 4; %PAM-M - bitpattern = zeros(N,log2(M)); - - % Symbol Rate - fsym = 112e9; - - % DAC Rate - fdac = 120e9; - - % Simulation oversampling rate "k"; - kover = 16; - - % ADC Rate - fadc = 256e9; - - % Simulation frequency in "analog domain" - fsimu = kover * fdac ; - - - - %% B) CONSTRUCT ALL CLASSES %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - - digimod = PAMmapper(M,0); - - pulseform = Pulseformer("pulseform","rrc","fdac",fdac,"fsym",fsym,"pulselength",32,"rrcalpha",0.027); - - awg = AWG('fdac',fdac,'kover',kover,'lpf_active',1,'f_cutoff',56e9,'lpf_type',filtertypes.gaussian,'bit_resolution',5.5); - - lp_laser = Filter('filtdegree',1,"f_cutoff",50e9,"fsamp",fdac*kover,"filterType",filtertypes.bessel_inp); - - u_pi = 3.5; - vbias = (0.5*u_pi)-u_pi; - extmodlaser = EML("mode",eml_mode.im_cosinus,"power",5,"fsimu",fsimu,"lambda",1310,"bias",vbias,"u_pi",u_pi,"linewidth",laser_linewidth); - - fib = Fiber("fsimu",fdac*kover,"fiber_length",fiblen,"alpha",0.2,"D",16,"lambda0",thz2nm(193.1),"gamma",0); - - reflectionpoint = Amplifier("amp_mode","ideal_no_noise","gain_mode","gain","amplification_db",sir); - reflectionprop = Fiber("fsimu",fdac*kover,"fiber_length",delay/1000,"alpha",0.2,"D",16,"lambda0",1550,"gamma",0); - - opticatten = Amplifier("amp_mode","ideal_no_noise","gain_mode","output_power","amplification_db",-8); - - phdiode = Photodiode("fsimu",fdac*kover,"dark_current",2e-08,"responsivity",1,"temperature",20); - - lp_diode = Filter('filtdegree',1,"f_cutoff",50e9,"fsamp",fdac*kover,"filterType",filtertypes.bessel_inp); - - scp = Scope("fsimu",fdac*kover,"fadc",fadc,... - "delay",0,"fixed_delay",0,"lpf_bw",113e9,"filtertype",filtertypes.butterworth,... - "samplingdelay",0,"rand_samplingdelay",0,"freq_offset",0,"samp_jitter",0,... - "adcresolution",6,"quantbuffer",0.1,'block_dc',1); - - eq = EQ("K",2,"plottrain",0,"plotfinal",0,... - "training_length",4096,"training_loops",2,... - "Ne",[50,5,3],"Nb",[3,0,0],... - "DCmu",0.05,"DDmu",[0.0004 0.0005 0.0006 0.0007 ],"DFEmu",0.005,"FFEmu",0.00,... - "dd_loops",2,"epsilon",[10 100 1000 ],"M",2,... - "thres",[0.005 0.004 0.0005 ],"l1act",0,"delay",0,"rho",0.0005,"ideal_dfe",0,"DB_aim",0); - - eq = EQ_silas("Ne",[50,5,3],"Nb",[2,0,0],"trainlength",4096,... - "sps",2,... - "mu_dc_dd",0.05,... - "mu_dc_train",0.05,... - "mu_ffe_train",0,... - "mu_dfe_train",0.005,... - "mu_ffe_dd",[0.0004 0.0004 0.0004],... - "mu_dfe_dd",0.005,... - "ddloops",3,... - "trainloops",4,... - "dcmode",1); - - - %% C) PROCESS TX %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - - % 1) PRBS Generation - for i = 1:log2(M) - [bitpattern(:,i),seed] = prbs(O,N,seed); - end - - % 2 ) Build Inf. signal class - bits = Informationsignal(bitpattern); - - % 3) Digi modulation -> PAM-M signal - digimod_out = digimod.map(bits); - - % 4) Pulse shaping -> racos - X = pulseform.process(digimod_out); - - % 5) AWG (lowpass, quantization, sample and hold) - X = awg.process(X); - - % 6) Lowpass behavior of laser and hf-cable? why twice? - X = lp_laser.process(X); - % X = lp_laser.process(X); - - % 7) Normalize signal - X = X.normalize("mode","oneone"); - X.signal = X.signal .* 1.3800; - - - %% D) PROCESS OPTICAL CHANNEL %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - - % 1) Laser; Modulation -> OPTICAL DOMAIN - [X,extmodlaser] = extmodlaser.process(X); - - % 2) Main fiber propagation - X = fib.process(X); - - if delay ~= 0 - % 3) Reflection - % Reflection is just an attenuation - R = reflectionpoint.process(X); - - % Propagate back and forth (actual fiber propagation) - R = reflectionprop.process(R); - - % Delay the reflected signal - [R,n] = R.delay("delay_meter",delay); - - % Add together - col = cbrewer2('qual','Paired',8); - - xax = (1:X.length);% / fsimu * (physconst("LightSpeed")/1.4677); - xax_sec = (1:X.length) / fsimu .* 1e6;%* (physconst("LightSpeed")/1.4677); - xax_sec = xax_sec(n:end).'; - thresh = pi/4; - phaseX = phase(X.signal(n:end)); - phaseR = phase(R.signal(n:end)); - phasediff = wrapToPi(phaseX-phaseR); - [pos_high] = find(abs(phasediff)>thresh); - [pos_low] = find(abs(phasediff)<=thresh); - - - figure(6);hold on;histogram(phaseX-phaseR,500,'EdgeAlpha',0) - - figure() - subplot(3,1,1) - scatter(xax_sec.',wrapToPi(phaseX),4,'.','MarkerEdgeColor',col(2,:),'DisplayName','Desired Signal') - hold on - scatter(xax_sec,wrapToPi(phaseR),4,'.','MarkerEdgeColor',col(1,:),'DisplayName','Reflected Signal') - hold on - lg = legend; - lg.Location = "southwest"; - xlim([xax_sec(1) xax_sec(end)]); - xlabel('time in $\mu$s') - ylim([-pi pi]); - yticks([-pi 0 pi]) - yticklabels({'$-\pi$',0, '$\pi$'}) - ylabel('$\phi$') - - subplot(3,1,2) - scatter(xax_sec(pos_low),phasediff(pos_low),4,'.','MarkerEdgeColor',col(5,:),'DisplayName','Phase Difference') - hold on - scatter(xax_sec(pos_high),phasediff(pos_high),4,'.','MarkerEdgeColor',col(2,:),'HandleVisibility','off') -% yline(thresh,'LineWidth',2,'LineStyle','-','HandleVisibility','off') -% yline(-thresh,'LineWidth',2,'LineStyle','-','HandleVisibility','off') - lg = legend; - lg.Location = "southwest"; - xlabel('time in $\mu$s') - xlim([xax_sec(1) xax_sec(end)]); - ylim([-pi pi]); - yticks([-pi 0 pi]) - yticklabels({'$-\pi$',0, '$\pi$'}) - ylabel('$\Delta \phi$') - - - X.signal = X.signal(n:end); - R.signal = R.signal(n:end); - X1 = X; - X = X+R; - - subplot(3,1,3) - scatter(xax_sec(pos_low),abs(X.signal(pos_low).^2)*1000,4,'.','MarkerEdgeColor',col(5,:),'DisplayName','Constructive Interference'); - hold on - scatter(xax_sec(pos_high),abs(X.signal(pos_high).^2)*1000,4,'.','MarkerEdgeColor',col(2,:),'DisplayName','Destructive Interference'); - %scatter(xax_sec(pos_high),abs(X1.signal(pos_high).^2)*1000,4,'.','MarkerEdgeColor',col(1,:),'MarkerFaceAlpha',0.3,'DisplayName','Destructive Interference'); - xlim([xax_sec(1) xax_sec(end)]); - xlabel('time in $\mu$s') - lg = legend; - lg.Location = "southwest"; - ylabel('Optical power in mW'); - - - - - disp(['SIR ',num2str(10*log10(X.power/R.power))]); - - % cut reference signal to correct length (nessecary due to MPI delay) - digimod_out.signal = digimod_out.signal(round(n * fsym/fsimu) : end,:); - - bitpattern = bitpattern(round(n * fsym/fsimu):end,:); - - end - - -% plot(angle(R.signal)) - - % 4) Attenuation - X = opticatten.process(X); - - - % 5) Photo Diode -> ELECTRICAL DOMAIN - X = phdiode.process(X); - X = lp_diode.process(X); - - - %% E) PROCESS RX %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - - % 1) Oscilloscope (Sampling to f_adc; Quantization; Bandwidth Limitation) - X = scp.process(X); - - % 2) Resample to 2x symbol rate - X = X.resample("fs_out",2*fsym,"fs_in",fadc); - - % 3) Normalize - Eq_in = X.normalize("mode","rms"); - - % 4) Equalize - - % MPI reduction DC removal BEFORE EQ - wl = 3000; % symbols - Eq_in.signal = Eq_in.signal - 1/wl .* movsum( Eq_in.signal,[wl/2,wl/2]); - - % Equalize Signal - [Eq_out] = eq.process(Eq_in,digimod_out); - - - - %% A1: MPI reduction DC removal - wl = 1000; % symbols - yk_dcsm = Eq_out; - yk_dcsm.signal = Eq_out.signal - 1/wl .* movsum( Eq_out.signal,[wl/2,wl/2]); - - %% A2: MPI reduction Level wise error removal - yk_lvsm = Eq_out; - yk_lvlp = Eq_out; - pre_decision_level_uni = digimod.decide_pamlevel(Eq_out); - pre_decision_level_bi = ( pre_decision_level_uni*2-3 ) .* 1/sqrt(5); - - e = Eq_out.signal - pre_decision_level_bi; - - lp_mpi = Filter('filtdegree',1,"f_cutoff",2e6,"fsamp",fsym,"filterType",filtertypes.bessel_inp); - - filtered = lp_mpi.process(e); - - wl = 30; % symbols - smoothed = ( 1/wl .* movsum(e,[wl/2,wl/2]) ); - - % remove interference - for level = 0:3 - yk_lvsm.signal(pre_decision_level_uni==level) = yk_lvsm.signal(pre_decision_level_uni==level) - smoothed(pre_decision_level_uni==level); - yk_lvlp.signal(pre_decision_level_uni==level) = yk_lvlp.signal(pre_decision_level_uni==level) - filtered(pre_decision_level_uni==level); - end - - % Calc EVM - - evm_bm = calc_evm(Eq_out.signal, pre_decision_level_bi); - evm_dcsm = calc_evm(yk_dcsm.signal, pre_decision_level_bi); - evm_lsm = calc_evm(yk_lvsm.signal, pre_decision_level_bi); - evm_llp = calc_evm(yk_lvlp.signal, pre_decision_level_bi); - - % figure(1);bar([evm_bm' evm_dcsm' evm_llp' evm_lsm']);ylim([0.01 0.1]);set(gca,'yscale','log'); - - %% PROCESS RX %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - - % 1) Digi Demod - d_bm = digimod.demap(Eq_out); - d_dcsm = digimod.demap(yk_dcsm); - d_lvsm = digimod.demap(yk_lvsm); - d_lvlp = digimod.demap(yk_lvlp); - - % 2) BER - dbit = length(d_bm.signal)-length(bitpattern); - - [~,errors_bm,ber_bm,loc] = calc_ber(d_bm.signal(1:end-dbit,:) ,bitpattern(1:end,:),"skip",0,"returnErrorLocation",1); - [~,errors_dcsm,ber_dcsm] = calc_ber(d_dcsm.signal(1:end-dbit,:) ,bitpattern(1:end,:),"skip",0,"returnErrorLocation",0); - [~,errors_lvsm,ber_lvsm] = calc_ber(d_lvsm.signal(1:end-dbit,:) ,bitpattern(1:end,:),"skip",0,"returnErrorLocation",0); - [~,errors_lvlp,ber_lvlp] = calc_ber(d_lvlp.signal(1:end-dbit,:) ,bitpattern(1:end,:),"skip",0,"returnErrorLocation",0); - - % Display BER - disp(['BER benchmark: ', sprintf('%2E',ber_bm), ' ERRORS: ' ,num2str(sum(errors_bm))]); - disp(['BER dc smooth (A1): ', sprintf('%2E',ber_dcsm), ' ERRORS: ' ,num2str(sum(errors_dcsm))]); - disp(['BER lv smooth (A2): ', sprintf('%2E',ber_lvsm), ' ERRORS: ' ,num2str(sum(errors_lvsm))]); - disp(['BER lv lowpas: ', sprintf('%2E',ber_lvlp), ' ERRORS: ' ,num2str(sum(errors_lvlp))]); - - - %% Generate some Plots - - if 1 - - % SCATTER - col = cbrewer2('Paired',8); - - xax = 1:Eq_out.length; - - figure(3) - sgtitle('') - - subplot(1,3,1) - hold on - eq_decision = digimod.decide_pamlevel(Eq_out); - true_symbols = digimod.decide_pamlevel(digimod_out); - - xindices = 1:Eq_in.length; - errorpos = find(loc~=0)*2; - errorpos(errorpos>length(Eq_in.signal)) = length(Eq_in.signal); - correct = find(loc==0)*2; - correct(correct>length(Eq_in.signal)) = length(Eq_in.signal); - scatter(xindices(correct),Eq_in.signal(correct),4,'.','MarkerEdgeColor',col(4,:),'DisplayName','After EQ'); - hold on - scatter(xindices(errorpos),Eq_in.signal(errorpos),6,'x','MarkerEdgeColor',col(6,:),'DisplayName','Wrong Decision'); - hold off - - xlim([1, xindices(end)]); - ylim([-3 3]); - xlabel('Sampling Index') - ylabel('Amplitude') - a = legend; - a.Location = "best"; - - subplot(1,3,2) - xindices = 1:Eq_out.length; - xax_sec = (1:Eq_out.length) / fsym .* 1e6; - scatter(xax_sec(loc==0),Eq_out.signal(loc==0),4,'.','MarkerEdgeColor',col(4,:),'DisplayName','After EQ'); - hold on - scatter(xindices(loc~=0),Eq_out.signal(loc~=0),8,'x','MarkerEdgeColor',col(6,:),'DisplayName','Wrong Decision'); - hold off - xlim([1, xax(end)]); - ylim([-2 2]); - xlabel('Sampling Index') - ylabel('Amplitude') - legend - a = legend; - a.Location = "best"; - hold off - - subplot(1,3,3) - xindices = 1:yk_lvsm.length; - scatter(xindices(loc==0),yk_lvsm.signal(loc==0),4,'.','MarkerEdgeColor',col(4,:),'DisplayName','After A2'); - hold on - scatter(xindices(loc~=0),yk_lvsm.signal(loc~=0),8,'x','MarkerEdgeColor',col(6,:),'DisplayName','Wrong Decision'); - hold off - xlim([1, xax(end)]); - ylim([-2 2]); - xlabel('Sampling Index') - ylabel('Amplitude') - legend - a = legend; - a.Location = "best"; - hold off - - - end - - if 0 - col = cbrewer2('Paired',8); - - figure(11) - clf - - subplot(2,1,1) - hold on - plot(digimod_out.signal(4150:4175),'DisplayName','Tx','Color',col(1,:),'LineWidth',3); - plot(Eq_out.signal(4150:4175),'DisplayName','Rx after EQ','Color',col(6,:),'LineWidth',1); - title('Modulated Sequence Zoom'); - legend - hold off - subplot(2,1,2) - hold on - stem(d_bm.signal(4150:4175,1),'DisplayName','Tx','Color',col(1,:),'LineStyle','-','LineWidth',5) - stem(bitpattern(4150:4175,1)','DisplayName','Rx','Color',col(6,:),'LineStyle','--','LineWidth',2) - title('Bitpattern Tx - Rx'); - legend - hold off - - end - -end - diff --git a/projects/IMDD_base_system/submit_simulations.m b/projects/IMDD_base_system/submit_simulations.m new file mode 100644 index 0000000..d8e1d24 --- /dev/null +++ b/projects/IMDD_base_system/submit_simulations.m @@ -0,0 +1,83 @@ +function wh = submit_simulations(wh,options) + +arguments + wh + options.parallel = 1; + options.simulation_mode = 1; +end + +%%% 2) SUBMIT SIMULATION +% Initialize job results +if options.parallel + curpool = gcp('nocreate'); + if isempty(curpool) + parpool; + else + % stop all forgotten or unfetched jobs from queue + if ~isempty(curpool.FevalQueue.QueuedFutures) || ~isempty(curpool.FevalQueue.RunningFutures) + oldq = length(curpool.FevalQueue.QueuedFutures) +length(curpool.FevalQueue.RunningFutures); + curpool.FevalQueue.cancelAll + fprintf('Canceled %d unfetched jobs from old queue.',oldq); + end + + end + results = parallel.FevalFuture.empty(); +else + results = []; +end + +fprintf('Requested %d loops',wh.getLastLinIndice); + +lin_idx = 1; +for lin_idx = 1:wh.getLastLinIndice + optionalVars = struct(); + if ~isempty(wh.getDimension) + % Build the optionalVars struct + [parametervalues,parameternames]=wh.getPhysIndicesByLinIndex(lin_idx); + for pidx = 1:numel(parameternames) + optionalVars.(parameternames{pidx}) = parametervalues{pidx}; + end + end + + %%% SIMULATION HERE + if options.parallel + + numOutputs = 1; + results(lin_idx) = parfeval(@imdd_model, numOutputs, options.simulation_mode, optionalVars); + + else + + finalresults{lin_idx} = imdd_model(options.simulation_mode,optionalVars); + wh.addValueToStorageByLinIdx(finalresults{lin_idx}, 'ber', lin_idx); + + end +end + + + +if options.parallel + + %%% 4) Setup waitbar + h = waitbar(0, 'Processing Simulations...'); + % Helper function to compute progress + updateWaitbar = @(~) waitbar(mean(arrayfun(@(f) strcmp(f.State, 'finished'), results)), h); + + fprintf('Fetching results... \n'); + + % Update the waitbar after each simulation + updateWaitbarFutures = afterEach(results, updateWaitbar, 0); + + % Close the waitbar after all simulations complete + afterAll(updateWaitbarFutures, @(~) delete(h), 0); + + %%% 7) Fetch final results after all computations + fetchOutputs(results); + + for ridx = 1:length(results) + wh.addValueToStorageByLinIdx(results(ridx).OutputArguments{1}, 'ber', ridx); + end + +end + + +end \ No newline at end of file diff --git a/projects/IMDD_base_system/tx_simulation.m b/projects/IMDD_base_system/tx_simulation.m new file mode 100644 index 0000000..77a1679 --- /dev/null +++ b/projects/IMDD_base_system/tx_simulation.m @@ -0,0 +1,31 @@ + + + Pform = Pulseformer("fsym",fsym,"fdac",4*fsym,"pulse","rrc","pulselength",16,"rrcalpha",rcalpha); + + [Digi_sig,Symbols,Tx_bits] = PAMsource(... + "fsym",fsym,"M",M,"order",19,"useprbs",1,... + "fs_out",fdac,... + "applyclipping",0,"clipfactor",1.5,... + "applypulseform",apply_pulsef,"pulseformer",Pform,... + "randkey",random_key,... + "db_precode",db_precode,"db_encode",db_encode,... + "mrds_code",0,"mrds_blocklength",512).process(); + + % Digi_sig.spectrum("displayname",'Digi Spectrum','fignum',10,'normalizeTo0dB',1); + + %%%%% 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',100,'normalizeTo0dB',0); + % El_sig = El_sig.setPower(0,"dBm"); + + %%%%% Low-pass el. components %%%%%% + El_sig = Filter('filtdegree',4,"f_cutoff",tx_bw_nyquist.*f_nyquist,"fs",fdac*kover,"filterType",filtertypes.butterworth,"active",true).process(El_sig); + + %%%%% 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"); + + %%%%% 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).process(El_sig); + diff --git a/projects/Lab_2024/bias_sweep_evaluation.m b/projects/Lab_2024/bias_sweep_evaluation.m index b465e05..8ad9625 100644 --- a/projects/Lab_2024/bias_sweep_evaluation.m +++ b/projects/Lab_2024/bias_sweep_evaluation.m @@ -1,29 +1,22 @@ - -filename = "C:\Users\sioe\Documents\High_Speed_Measurement_2024\bias_testing\PAM4_b2b_bias_sweep_20241023_130342_wh.mat"; - +filename = "/Users/silasoettinghaus/Documents/MATLAB/PAM4_b2b_bias_sweep_20241023_145739_wh.mat"; a = load(filename); wh2 = a.obj; -m = wh2.getStoValue('m',wh2.parameter.vbias.values(1),wh2.parameter.awg_vpp.values(1)); +precomp_max = 5; +m = wh2.getStoValue('m',wh2.parameter.vbias.values(1),wh2.parameter.awg_vpp.values(1),precomp_max); v_bias_vals = wh2.parameter.vbias.values; awg_vpp_vals = wh2.parameter.awg_vpp.values; -ber_ffe= []; -ber_mlse= []; -rop_measured= []; -pd_in_measured= []; - +bers = []; rop_measured = []; cnt = 0; for awg_vpp_cur = awg_vpp_vals cnt = cnt+1; - ber_ffe(cnt,:) = wh2.getStoValue('ber_ffe',v_bias_vals,awg_vpp_cur)'; - ber_mlse(cnt,:) = wh2.getStoValue('ber_mlse',v_bias_vals,awg_vpp_cur); - rop_measured(cnt,:) = wh2.getStoValue('rop',v_bias_vals,awg_vpp_cur); - pd_in_measured(cnt,:) = wh2.getStoValue('pd_in',v_bias_vals,awg_vpp_cur); + bers(cnt,:) = wh2.getStoValue('ber_mlse',v_bias_vals,awg_vpp_cur,precomp_max); + rop_measured(cnt,:) = wh2.getStoValue('rop',v_bias_vals,awg_vpp_cur,precomp_max); end [bestber,bestindex] = min(bers,[],'all'); @@ -34,14 +27,27 @@ bestvbias=v_bias_vals(v_bias_pos); disp(['Best Vpp: ',num2str(bestvbias),' V; Best Vpp AWG: ',num2str(bestawgvpp),' V' ]) -figure(100) + +figure() hold on -plot(v_bias_vals,ber_ffe,'DisplayName',['FFE only']); -plot(v_bias_vals,ber_mlse,'DisplayName',['MLSE']); +for i = 1:numel(awg_vpp_vals) + va=awg_vpp_vals(i); + a=scatter(rop_measured(i,:),bers(i,:),'DisplayName',['FFE AWG:',num2str(va)],'LineWidth',1); + + a.DataTipTemplate.DataTipRows(1).Label = 'P out'; + + a.DataTipTemplate.DataTipRows(2).Label = 'BER'; + + a.DataTipTemplate.DataTipRows(3).Label = 'Vbias'; + a.DataTipTemplate.DataTipRows(3).Value = v_bias_vals; + a.DataTipTemplate.DataTipRows(3).Format = 'auto'; +end + +% Continue with the rest of your plot settings yline(3.8e-3, 'DisplayName', 'HD-FEC', 'LineStyle', '--', 'HandleVisibility', 'off'); -xlabel('V bias'); +xlabel('ROP'); ylabel('Bit Error Rate (BER)'); -title('Bit Error Rate vs. V bias'); +title('Bit Error Rate vs. ROP'); set(gca, 'yscale', 'log'); set(gca, 'Box', 'on'); grid on; @@ -49,7 +55,6 @@ grid minor; legend('Interpreter', 'none'); - figure(); sgtitle(['PAM ', num2str(m)]) subplot1 = subplot(1,2,1); diff --git a/projects/Lab_2024/offline_dsp_analysis/load_n_dsp.m b/projects/Lab_2024/offline_dsp_analysis/load_n_dsp.m index fe8434f..784127b 100644 --- a/projects/Lab_2024/offline_dsp_analysis/load_n_dsp.m +++ b/projects/Lab_2024/offline_dsp_analysis/load_n_dsp.m @@ -1,13 +1,14 @@ % load data points if 0 - foldername = '/Users/silasoettinghaus/Nextcloud/Dokumente/02_Ablage_Office/Lab_Data_24/sir_sweep_sd40/'; + foldername = 'C:\Users\Silas\Nextcloud4\Dokumente\02_Ablage_Office\Lab_Data_24\sir_sweep_sd40'; filename = 'PAM4_56_'; filename = 'PAM4_56_v2'; else - foldername = '/Users/silasoettinghaus/Nextcloud/Dokumente/02_Ablage_Office/Lab_Data_24/sir_sweep_sd40/DB_coded'; + foldername = 'C:\Users\Silas\Nextcloud4\Dokumente\02_Ablage_Office\Lab_Data_24\sir_sweep_sd40\DB_coded'; filename = 'PAM4_68_v2'; end + stuff = load([foldername,filesep,filename,'wh']); %stuff = load([foldername,filesep,'PAM4_v2_10km_wh']); wh = stuff.obj; diff --git a/projects/Lab_2024/offline_dsp_analysis/load_n_plot_transfer_characteristic.m b/projects/Lab_2024/offline_dsp_analysis/load_n_plot_transfer_characteristic.m new file mode 100644 index 0000000..a23d25a --- /dev/null +++ b/projects/Lab_2024/offline_dsp_analysis/load_n_plot_transfer_characteristic.m @@ -0,0 +1,8 @@ + + +precomp_path = "C:\Users\Silas\Documents\MATLAB\imdd_simulation\projects\standard_system"; +precomp_filename = "lab_mpi_setup_2"; + +freqresp = ChannelFreqResp("Nacq",1024,"Navg",64,"Ncp",63,'f_ref',92e9); +freqresp.load('loadPath',precomp_path,'fileName',precomp_filename); +freqresp.plot(); diff --git a/projects/MPI_August/auswertung/M_4_datarate_224_sir_35_laser_linewidth_1000000_pn_key_1_rop_0.mat b/projects/MPI_August/auswertung/M_4_datarate_224_sir_35_laser_linewidth_1000000_pn_key_1_rop_0.mat new file mode 100644 index 0000000..bf2c100 Binary files /dev/null and b/projects/MPI_August/auswertung/M_4_datarate_224_sir_35_laser_linewidth_1000000_pn_key_1_rop_0.mat differ diff --git a/python_version/amp_mode.py b/python_version/amp_mode.py deleted file mode 100644 index 65da429..0000000 --- a/python_version/amp_mode.py +++ /dev/null @@ -1,7 +0,0 @@ -from enum import IntEnum - -class amp_mode(IntEnum): - ideal_no_noise = 1 - edfa_increase_nase = 2 - edfa_replace_nase = 3 - # edfa_set_osnr = 4 TODO: implement mode to achieve desired OSNR \ No newline at end of file diff --git a/python_version/ampclass.py b/python_version/ampclass.py deleted file mode 100644 index 6d1789b..0000000 --- a/python_version/ampclass.py +++ /dev/null @@ -1,86 +0,0 @@ -import numpy as np -import scipy.constants as Constant -import amp_mode -import gain_mode -import nase_mode - -class Amplifier: - def __init__(self, options=None): - self.amp_mode = options.amp_mode if options and hasattr(options, 'amp_mode') else amp_mode.ideal_no_noise - self.gain_mode = options.gain_mode if options and hasattr(options, 'gain_mode') else gain_mode.output_power - self.nase_mode = options.nase_mode if options and hasattr(options, 'nase_mode') else nase_mode.pass_ase - self.amplification_db = options.amplification_db if options and hasattr(options, 'amplification_db') else 0 - self.noifig = options.noifig if options and hasattr(options, 'noifig') else 0 - self.fsimu = options.fsimu if options and hasattr(options, 'fsimu') else None - - def process(self, signalclass_in): - signalclass_in = self.process_(signalclass_in) - lbdesc = 'Amp ' - signalclass_in = signalclass_in.logbookentry(lbdesc) - signalclass_out = signalclass_in - return signalclass_out - - def process_(self, X_in): - a_lin = self.calculateGain(X_in.signal) - X_in.signal = a_lin * X_in.signal - - if isinstance(X_in, Opticalsignal): - if self.amp_mode == amp_mode.ideal_no_noise: - X_in.nase = self.onlyAmplifyAse(X_in.nase, a_lin) - elif self.amp_mode == amp_mode.edfa_increase_nase: - X_in.nase = self.increaseAse(X_in.nase, a_lin, self.noifig, X_in.lambda_) - elif self.amp_mode == amp_mode.edfa_replace_nase: - X_in.nase = self.replaceAse(X_in.nase, a_lin, self.noifig, X_in.lambda_) - - if self.nase_mode == nase_mode.generate_ase: - nase = X_in.nase - fs = X_in.fs - dimension = X_in.signal.shape - nase_numeric = self.generateAseNoise(nase, fs, dimension) - X_in.signal, osnr = self.applyAseToSignal(X_in.signal, nase_numeric) - X_in.nase = 0 - elif self.nase_mode == nase_mode.pass_ase: - X_in.nase = X_in.nase - - X_out = X_in - return X_out - - def calculateGain(self, xin): - if self.gain_mode == gain_mode.output_power: - pow_in = np.mean(np.abs(xin) ** 2) - pow_out = 10 ** (self.amplification_db / 10 - 3) - a_lin = np.sqrt(pow_out / pow_in) - elif self.gain_mode == gain_mode.gain: - a_lin = 10 ** (self.amplification_db / 20) - return a_lin - - def onlyAmplifyAse(self, nase_old, a_lin): - nase_amped = a_lin ** 2 * nase_old - return nase_amped - - def calculateAseFromThisAmp(self, a_lin, noisefig, lambda_): - h = Constant.Planck - c = Constant.speed_of_light - nase_new = 0.5 * 10 ** (noisefig / 10) * h * c / lambda_ * (a_lin ** 2 - 1) - return nase_new - - def increaseAse(self, nase_old, a_lin, noisefig, lambda_): - nase_fromThisAmp = self.calculateAseFromThisAmp(a_lin, noisefig, lambda_) - nase_old = a_lin ** 2 * nase_old - ase_increased = nase_old + nase_fromThisAmp - return ase_increased - - def replaceAse(self, nase_old, a_lin, noisefig, lambda_): - nase_fromThisAmp = self.calculateAseFromThisAmp(a_lin, noisefig, lambda_) - nase_new = nase_fromThisAmp - return nase_new - - def generateAseNoise(self, nase, fs, dimension): - nase_numeric = (np.random.randn(*dimension) + 1j * np.random.randn(*dimension)) * np.sqrt(nase / 2 * fs) - return nase_numeric - - def applyAseToSignal(self, opticalsignal, nase_numeric): - noisy_sig = opticalsignal + nase_numeric - osnr = pow(10 * np.log10(np.mean(np.abs(opticalsignal) ** 2) / np.mean(np.abs(nase_numeric) ** 2))) - print(osnr) - return noisy_sig, osnr diff --git a/python_version/gain_mode.py b/python_version/gain_mode.py deleted file mode 100644 index 6fa928d..0000000 --- a/python_version/gain_mode.py +++ /dev/null @@ -1,5 +0,0 @@ -from enum import IntEnum - -class gain_mode(IntEnum): - gain = 1 - output_power = 2 \ No newline at end of file diff --git a/python_version/nase_mode.py b/python_version/nase_mode.py deleted file mode 100644 index f88e2f7..0000000 --- a/python_version/nase_mode.py +++ /dev/null @@ -1,5 +0,0 @@ -from enum import IntEnum - -class nase_mode(IntEnum): - generate_ase = 1 - pass_ase = 2 \ No newline at end of file diff --git a/python_version/python_trial.py b/python_version/python_trial.py deleted file mode 100644 index 26a5866..0000000 --- a/python_version/python_trial.py +++ /dev/null @@ -1,3 +0,0 @@ -from ampclass import Amplifier - -a = Amplifier() diff --git a/test/duobinary_emulation_minimal_example.m b/test/duobinary_emulation_minimal_example.m new file mode 100644 index 0000000..3f808b3 --- /dev/null +++ b/test/duobinary_emulation_minimal_example.m @@ -0,0 +1,76 @@ +useprbs = 1; +M = 6; +randkey = 1; +datarate = 224e9; +fsym = round(datarate / log2(M)) ; + +db_pre = 1; + +Pform = Pulseformer("fsym",fsym,"fdac",4*fsym,"pulse","rrc","pulselength",16,"rrcalpha",0.05); + +[d,Symbols,Bits] = PAMsource(... + "fsym",fsym,"M",M,"order",17,"useprbs",1,... + "fs_out",fsym,... + "applyclipping",0,"clipfactor",1.5,... + "applypulseform",0,"pulseformer",Pform,... + "randkey",1,... + "db_precode",db_pre,"db_encode",0,... + "mrds_code",0,"mrds_blocklength",512).process(); + +%%%CHANNEL + +% s = RandStream('twister','Seed',2); +% start = 10000; +% burstwidth = 100; +% d_burst = d; +% for pos = start:start+burstwidth +% lvls = 1.5 .* PAMmapper(M,0).levels / rms(PAMmapper(M,0).levels); +% d_burst.signal(pos) = d.signal(pos)+randn(s,1,1); +% end + +d_resample = d.resample("fs_out",2.*fsym); + +eq_ffe = FFE("epochs_tr",5,"epochs_dd",5,"len_tr",1024,"mu_dd",0.0004,"mu_tr",0,"order",25,"sps",2,"decide",1); +d_eq = eq_ffe.process(d_resample,Symbols); + +% s = RandStream('twister','Seed',2); +% start = 10000; +% burstwidth = 100; +% d_burst = d_eq; +% for pos = start:start+burstwidth +% lvls = 1.5 .* PAMmapper(M,0).levels / rms(PAMmapper(M,0).levels); +% d_burst.signal(pos) = d_eq.signal(pos)+randn(s,1,1); +% end +% +% d_burst = PAMmapper(M,0).decide_pamlevel(d_burst); + +if db_pre + % Entschiedene Symbole codieren: d_DB(n) = d(n) + d(n-1) (im Fall von PAM4 7 level [0 1 2 3 4 5 6]) + d_db = Duobinary().encode(d); + + % Entschiedene codierte Symbole decodieren: d_dec(n) = d_DB(n) mod4 + d_dec = Duobinary().decode(d_db); +else + d_dec = d_burst; +end + +% Vergleichen von b(n) und d_dec(n) +Rx_bits = PAMmapper(M,0).demap(d_dec); + +Tx_bits = Bits; + +[~,error_num,ber,error_pos] = calc_ber(Tx_bits.signal,Rx_bits.signal,"skip_front",0,"skip_end",0,"returnErrorLocation",1); + +disp(['BER: ',sprintf('%.1E',ber),' - - PAM-',num2str(M)]); + + +figure(200) +clf +hold on +idxs = start-10:start+burstwidth+10; +scatter(idxs,d.signal(idxs),'DisplayName',['Orig Signal'],'Marker','o'); +scatter(idxs,d_burst.signal(idxs),'DisplayName',['Error Signal'],'Marker','x'); +scatter(idxs,d_dec.signal(idxs),'DisplayName',['EQ Signal'],'Marker','x'); +yline(PAMmapper(M,0).thresholds,'HandleVisibility','off'); +legend +ylim([-2 2]) \ No newline at end of file diff --git a/test/duobinary_minimal_example.m b/test/duobinary_minimal_example.m index bcd2de7..f817713 100644 --- a/test/duobinary_minimal_example.m +++ b/test/duobinary_minimal_example.m @@ -5,39 +5,65 @@ datarate = 448e9; fsym = round(datarate / log2(M)) ; %%%%% PRBS Generation in correct shape for Modulation Format %%%%%% -O = 17; %order of prbs +O = 15; %O of prbs N = 2^(O); %length of prbs [~,seed] = prbs(O,1); %initialize first seed of prbs bitpattern=[]; -if useprbs - for i = 1:log2(M) - [bitpattern(:,i),seed] = prbs(O,N,seed); - end -else - s = RandStream('twister','Seed',randkey); - for i = 1:log2(M) - bitpattern(:,i) = randi(s,[0 1], N, 1); - end -end +state = struct(); + +para = struct(); if M == 6 - bitpattern = reshape(bitpattern,[],1); + para.bl = 2^(O-2); + para.dimension = 5; +else + para.bl = 2^(O-1); + para.dimension = log2(M); %2.5bits/sym -> 2 bit/sym +end + +para.rand = 0; + +para.order = floor(O / log2(M)); +para.skip =0; +para.bruijn = 0; +para.reset_prms = 0; +para.method = 1; + +data_in = []; +global loop; +loop = 0; +[data_out,state_] = prms(data_in, state, para); +loop = 1; +[data_out,state_out] = prms(data_in, state_, para); +bitpattern = data_out'; + +if M == 6 + bitpattern = reshape(bitpattern',[],1); bitpattern = bitpattern(1:end-mod(length(bitpattern),5)); end Tx_bits = Informationsignal(bitpattern); +%%%%% Duobinary %%%%%% + +close all Symbols_tx = PAMmapper(M,0).map(Tx_bits); Symbols_tx.fs = fsym; -Symbols = Duobinary().precode(Symbols_tx); +Symbols1 = Duobinary().precode(Symbols_tx); +figure;histogram(Symbols1.signal); -Symbols = Duobinary().encode(Symbols); +Symbols2 = Duobinary().encode(Symbols1); +figure;histogram(Symbols2.signal); -Symbols = Duobinary().decode(Symbols); +Symbols3 = Duobinary().decode(Symbols2); +figure;histogram(Symbols3.signal); +autoArrangeFigures; -Rx_bits = PAMmapper(M,0).demap(Symbols); +Rx_bits = PAMmapper(M,0).demap(Symbols3); + +%%%%% Check BER of Bit Sequence %%%%%% [~,error_num,ber,error_pos] = calc_ber(Tx_bits.signal,Rx_bits.signal,"skip_front",0,"skip_end",0,"returnErrorLocation",1); diff --git a/test/exampleFunction.m b/test/exampleFunction.m new file mode 100644 index 0000000..4830167 --- /dev/null +++ b/test/exampleFunction.m @@ -0,0 +1,32 @@ +function output = exampleFunction(varargin) + + % Default values for optional variables + var_1 = 1; + var_2 = 2; + var_4 = 10; % Default value for var4 + var_5 = 20; % Default value for var5 + var_6 = 30; % Default value for var6 + var_7 = 40; % Default value for var7 + var_8 = 50; % Default value for var8 + var_9 = 60; % Default value for var9 + var_10 = 70; % Default value for var10 + + % Parse optional input arguments + if ~isempty(varargin) + var_s = varargin{1}; + if isstruct(var_s) + fields = fieldnames(var_s); + for i = 1:numel(fields) + eval([fields{i}, ' = ', num2str( var_s.(fields{i}) ), ';']); + fprintf("%s <-- %.2f \n",fields{i},var_s.(fields{i})) + end + else + error('Optional variables should be passed as a struct.'); + end + end + + output = var_4+var_10+var_9+var_8+var_1+var_2; + + +end + diff --git a/test/mapping_minimal_example.m b/test/mapping_minimal_example.m index fdc86ac..08e1b3a 100644 --- a/test/mapping_minimal_example.m +++ b/test/mapping_minimal_example.m @@ -7,6 +7,55 @@ randkey = 1; fsym = 112e9; viewresults = 0; +%%%%% Mapping %%%%% +M = 8; +data = 0:M-1; +bitpersymbol = log2(M); + +%Bits +bits = int2bit(data,bitpersymbol, true); + +%Integers +ints = bit2int(bits,bitpersymbol, true); + +Tx_bits = Informationsignal(bits'); +Digi_Mod = PAMmapper(M,0); +Symbols = Digi_Mod.map(Tx_bits); +moveitgray = Symbols.signal; + +%Gray Symbol Mapping +matlabgray = pammod(ints,M,0,'gray'); +scaling_factor = rms(unique(matlabgray)); +matlabgray = matlabgray ./ scaling_factor; + + +%Demod +moveitgray = moveitgray.* scaling_factor; +matlabgray = matlabgray .* scaling_factor; +ints_demap = pamdemod(matlabgray,M,0,'gray'); + +bits_demap = int2bit(ints_demap,bitpersymbol, true); + +% for i = 1:M +% fprintf('%d , %d , %d --> %d \n',bits(1,i),bits(2,i),bits(3,i),matlabgray(i)); +% end +% +% for i = 1:M +% fprintf('%d , %d , %d --> %d \n',bits(1,i),bits(2,i),bits(3,i),moveitgray(i)); +% end + +scatterplot(matlabgray,1,0,'b*'); +for k = 1:M + text(real(matlabgray(k)),imag(matlabgray(k))+0.6,num2str(ints_demap(k)),"Color",[1 1 1]); + + text(real(matlabgray(k)),imag(matlabgray(k))-1.6,num2str(bits(:,k)),"Color",'blue'); + text(real(moveitgray(k)),imag(moveitgray(k))-3,num2str(bits(:,k)),"Color",'green'); +end +axis([-M M -3 2]) + + +symbols = bit2int(bitGroups',bitpersymbol, true); + %%%%% PRBS Generation in correct shape for Modulation Format %%%%%% O = 10; %order of prbs @@ -34,6 +83,9 @@ Tx_bits = Informationsignal(bitpattern); Digi_Mod = PAMmapper(M,0); +symbols = bitMapper(bitpattern, M, 'PAM'); + + Symbols = Digi_Mod.map(Tx_bits); Rx_bits = PAMmapper(M,0).demap(Symbols); diff --git a/test/run_examplefcn.m b/test/run_examplefcn.m new file mode 100644 index 0000000..f00cbcd --- /dev/null +++ b/test/run_examplefcn.m @@ -0,0 +1,100 @@ +% Define ranges for variables to iterate over +var1_range = [1, 2, 3, 4, 6]; +var2_range = [10, 20]; +var3_range = [100, 200]; + +% Prepare the parallel pool +if isempty(gcp('nocreate')) + parpool; % Start a parallel pool if not already running +end + +% Array to hold measurement futures +measurements = parallel.FevalFuture.empty(); + +% Array to hold DSP results +dsp_results = parallel.Future.empty(); + +% Nested for loops for all parameter combinations +lin_idx = 1; +for v1 = var1_range + for v2 = var2_range + for v3 = var3_range + % Construct the struct of optional variables for this iteration + optionalVars = struct('var_4', v1, 'var_5', v2, 'var_6', v3); + + % Submit the measurement function to the parallel pool + measurements(lin_idx) = parfeval(@measurement, 1, optionalVars); + + % Link DSP function to run after measurement completes + dsp_results(lin_idx) = afterEach(measurements(lin_idx), @(output) rundsp(output, optionalVars), 1); + + lin_idx = lin_idx + 1; % Increment linear index + end + end +end + +% Fetch and display DSP results +final_results = cell(numel(dsp_results), 1); +for i = 1:numel(dsp_results) + fprintf('Fetching DSP result for job %d...\n', i); + final_results{i} = fetchOutputs(dsp_results(i)); % Fetch each DSP result individually +end + +fprintf('All DSP evaluations completed.\n'); +disp('Final Results:'); +disp(final_results); + +% --- Measurement Function --- +function output = measurement(varargin) + + % Default values for optional variables + var_1 = 1; + var_2 = 2; + var_4 = 10; % Default value for var4 + var_5 = 20; % Default value for var5 + var_6 = 30; % Default value for var6 + var_7 = 40; % Default value for var7 + var_8 = 50; % Default value for var8 + var_9 = 60; % Default value for var9 + var_10 = 70; % Default value for var10 + + % Parse optional input arguments + if ~isempty(varargin) + var_s = varargin{1}; + if isstruct(var_s) + fields = fieldnames(var_s); + for i = 1:numel(fields) + eval([fields{i}, ' = ', num2str( var_s.(fields{i}) ), ';']); + fprintf("%s <-- %.2f \n", fields{i}, var_s.(fields{i})); + end + else + error('Optional variables should be passed as a struct.'); + end + end + + % Simulate output with a random delay + output = randi(5); % Random result + pause(output); % Simulate processing time +end + +% --- DSP Function --- +function output = rundsp(measurement_output, varargin) + + % Parse optional input arguments + if ~isempty(varargin) + var_s = varargin{1}; + if isstruct(var_s) + fields = fieldnames(var_s); + for i = 1:numel(fields) + eval([fields{i}, ' = ', num2str( var_s.(fields{i}) ), ';']); + fprintf("%s <-- %.2f \n", fields{i}, var_s.(fields{i})); + end + else + error('Optional variables should be passed as a struct.'); + end + end + + % Simulate DSP processing based on measurement output + output = measurement_output + 10; % Add 10 to measurement output + pause(measurement_output); % Simulate DSP processing time +end