diff --git a/Classes/00_signals/Signal.m b/Classes/00_signals/Signal.m index 872b9d3..f212a02 100644 --- a/Classes/00_signals/Signal.m +++ b/Classes/00_signals/Signal.m @@ -172,9 +172,9 @@ classdef Signal hold on; if isempty(options.color) - plot(t, sig(1:length(t)), 'DisplayName', dn, 'LineWidth', 0.1, 'Marker', '.', 'LineStyle','none', 'MarkerSize', 0.1); + plot(t* 1e6, 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); + plot(t* 1e6, 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) @@ -187,10 +187,7 @@ classdef Signal ylabel('Amplitude'); end - % Convert time axis to milliseconds for readability - xticks = get(gca, 'XTick'); - set(gca, 'XTick', xticks, 'XTickLabel', xticks * 1e6); - + % Add legend if not already present if isempty(get(gca, 'Legend')) legend; @@ -656,7 +653,7 @@ classdef Signal end %% - function [obj,S,isFlipped,sequenceFound] = tsynch(obj,options) + function [obj,S,inverted,sequenceFound,sequenceStarts] = tsynch(obj,options) % time sync and cut arguments obj Signal @@ -668,9 +665,9 @@ classdef Signal S = {}; - isFlipped=0; + inverted = -1; sequenceFound = 0; - + sequenceStarts = []; %normalize the signal @@ -696,8 +693,10 @@ classdef Signal return end - if mean(w) > 10 || mean(p) > 10 + if mean(w) > 10 + warning('No sync possible, check code of findpeaks! Look at correlation') return + else sequenceFound = 1; end @@ -711,19 +710,19 @@ classdef Signal shifts = lags(pkpos); - + sequenceStarts = shifts; % shifts = shifts(shifts>=0); if numel(shifts) > 0 %Cut occurences of ref signal from signal (only positive shifts) - if all(sign(co(pkpos))) - isFlipped = 1; + if all(sign(co(pkpos))==-1) + inverted = 1; end for c = shifts sig = obj.delay(-c,'mode','samples'); - sig.signal = sig.signal(1:length(b)).*-isFlipped; + sig.signal = sig.signal(1:length(b)) .* -inverted; S{end+1,1} = sig; end diff --git a/Classes/05_Lab/OptLaserN7714A.m b/Classes/05_Lab/OptLaserN7714A.m new file mode 100644 index 0000000..b6a5372 --- /dev/null +++ b/Classes/05_Lab/OptLaserN7714A.m @@ -0,0 +1,146 @@ +classdef OptLaserN7714A < handle + % Minimal controller for Keysight N7714A tunable laser over VISA-LAN + % Methods: getLaserInfo, setPower, setWavelength + % + % Examples: + % L = OptLaserN7714A('TCPIP::192.168.0.50::INSTR'); + % L.setWavelength(1550); % nm + % L.setPower(-3.0, true); % dBm, also turns output ON + % info = L.getLaserInfo(); + + properties (Access=private) + v % visadev handle + resource char % VISA resource string, e.g. 'TCPIP::...::INSTR' + end + + methods + function obj = OptLaserN7714A(resource) + arguments + resource (1,:) char + end + obj.resource = resource; + + % Robust connect with small retry loop + maxRetries = 3; pauseTime = 1.0; lastErr = []; + for k = 1:maxRetries + try + obj.v = visadev(obj.resource); + % Identify instrument (SCPI *IDN?) + writeline(obj.v, '*IDN?'); % SCPI common, identification + idn = strtrim(readline(obj.v)); %#ok + break + catch ME + lastErr = ME; + pause(pauseTime); + end + end + if isempty(obj.v) || ~isvalid(obj.v) + error('OptLaserN7714A:ConnectFailed', ... + 'Could not connect to %s. Last error: %s', obj.resource, lastErr.message); + end + + % Set power unit to dBm for SOURce tree to be explicit (optional) + % [:SOUR]:POWer:UNIT dBm (laser power unit) + % Ref: SOURce:POWer:UNIT. :contentReference[oaicite:0]{index=0} + try + writeline(obj.v, 'SOUR:POW:UNIT DBM'); + catch + % non-fatal + end + end + + function delete(obj) + if ~isempty(obj.v) && isvalid(obj.v); delete(obj.v); end + end + + function setPower(obj, power_dBm, outputOn, channel) + arguments + obj + power_dBm (1,1) double + outputOn (1,1) logical = true + channel (1,1) double {mustBeMember(channel,0:4)} = 1 + end + + v = obj.v; + cmd = sprintf('SOUR%d:POW:LEV:IMM:AMPL %g DBM', channel, power_dBm); + writeline(v, cmd); + + if outputOn + writeline(v, sprintf('SOUR%d:POW:STAT 1', channel)); %SOUR1:POW:STAT 0 + else + writeline(v, sprintf('SOUR%d:POW:STAT 0', channel)); + end + + writeline(v, '*OPC?'); + a=readline(v); + end + + function setWavelength(obj, wavelength_nm, channel) + arguments + obj + wavelength_nm (1,1) double {mustBePositive} + channel (1,1) double {mustBeMember(channel,0:4)} = 1 + end + v = obj.v; + cmd = sprintf('SOUR%d:WAV %gNM', channel, wavelength_nm); + writeline(v, cmd); + writeline(v, '*OPC?'); readline(v); + end + + function setDither(obj, enable, port) + % Enable or disable laser frequency dither (stabilization). + % enable = false → no dither (FIX), true → stabilization (STAB). + % port = 1..4 (default 1). + if nargin < 3 + port = 1; + end + + v = obj.v; + if enable + writeline(v, sprintf('SOUR%d:CONTrol:FCDither ON', port)); %[:SOURce[n]][:CHANnel[m]]:CONTrol:FCDither + else + writeline(v, sprintf('SOUR%d:CONTrol:FCDither OFF', port)); + end + + % optional confirmation + writeline(v, sprintf('SOUR%d:CONTrol:FCDither?', port)); + modeStr = strtrim(readline(v)); + fprintf('Port %d dither mode set to %s\n', port, modeStr); + end + + + + function info = getLaserInfo(obj, port) + % Returns struct with IDN, output state, wavelength (nm), power (dBm) + % port = 1..4 (for N7714A with 4 outputs). Default = 1. + if nargin < 2 + port = 1; + end + + v = obj.v; + + % *IDN? + writeline(v, '*IDN?'); + idn = strtrim(readline(v)); + + % Output state: :SOURn:POW:STAT? + writeline(v, sprintf('SOUR%d:POW:STAT?', port)); + out_state = str2double(readline(v)) ~= 0; + + % Wavelength query (returns meters → convert to nm) + writeline(v, sprintf('SOUR%d:WAV?', port)); + wav_m = str2double(readline(v)); + wav_nm = wav_m * 1e9; + + % Power (set level) query (dBm) + writeline(v, sprintf('SOUR%d:POW:LEV:IMM:AMPL?', port)); + p_dBm = str2double(readline(v)); + + info = struct('idn', idn, ... + 'output_on', out_state, ... + 'wavelength_nm', wav_nm, ... + 'power_dBm', p_dBm); + end + + end +end diff --git a/Functions/EQ_structures/duobinary_signaling.m b/Functions/EQ_structures/duobinary_signaling.m index 69c0449..0d69311 100644 --- a/Functions/EQ_structures/duobinary_signaling.m +++ b/Functions/EQ_structures/duobinary_signaling.m @@ -17,6 +17,7 @@ if ~isempty(options.postFFE) [eq_signal,eq_noise] = options.postFFE.process(eq_signal,tx_symbols); end +eq_signal.eye(eq_signal.fs,M,"fignum",340); eq_signal = mlse_.process(eq_signal); @@ -62,7 +63,7 @@ equalizerConfigDBsignaling = struct( ... 'target_constellation', jsonencode(round(unique(tx_symbols.signal),5)), ... % Beispielhafter Target-String 'db_target', 1, ... % 0 oder 1 'diff_precode', 1, ... % 0 oder 1 - 'postFFE', ~isempty(options.postFFE), ... % Beispielwert + 'postFFE', double(~isempty(options.postFFE)), ... % Beispielwert 'NpostFFE', npostFFE, ... % Beispielwert 'Ne1', eq_.Ne(1), ... % Feedforward Koeffizienten 1. Ordnung 'Ne2', eq_.Ne(2), ... % Feedforward Koeffizienten 2. Ordnung diff --git a/Functions/EQ_structures/vnle_postfilter_mlse.m b/Functions/EQ_structures/vnle_postfilter_mlse.m index 70c95af..07ad822 100644 --- a/Functions/EQ_structures/vnle_postfilter_mlse.m +++ b/Functions/EQ_structures/vnle_postfilter_mlse.m @@ -99,6 +99,8 @@ end [gmi_vnle] = calc_air(eq_signal_sd,tx_symbols,"skip_front",10000,"skip_end",10000); air_vnle = tx_symbols.fs .* floor(log2(double(M))*10)/10 .* gmi_vnle ./ log2(double(M)); [evm_vnle_total,evm_vnle_lvl] = calc_evm(eq_signal_sd,tx_symbols); +[std_vnle_total,std_vnle_lvl] = calc_std(eq_signal_sd,tx_symbols); +[std_rxraw_total,std_rxraw_lvl] = calc_std(rx_signal.resample("fs_out",tx_symbols.fs),tx_symbols); % METRICS OF MLSE (HD-VITERBI) pf_.ncoeff = 1; @@ -127,6 +129,10 @@ resultsVNLE = struct( ... 'numBitErr_precoded', errors_vnle_diff_precoded, ... % Beispiel: 120 Bitfehler 'SNR', snr_vnle, ... % Beispielhafte SNR 'SNR_level', jsonencode(snr_vnle_lvl), ... % SNR-Level als JSON-codiertes Array + 'STD', std_vnle_total, ... + 'STD_level', jsonencode(std_vnle_lvl),... + 'STDrx' , std_rxraw_total, ... + 'STDrx_level', jsonencode(std_rxraw_lvl),... 'GMI', gmi_vnle, ... % Beispielhafter GMI-Wert 'AIR', air_vnle, ... % Beispielhafter AIR-Wert 'EVM', evm_vnle_total, ... % Beispielhafte EVM @@ -147,7 +153,7 @@ equalizerConfigVNLE = struct( ... 'target_constellation', jsonencode(round(unique(tx_symbols.signal),5)), ... % Beispielhafter Target-String 'db_target', 0, ... % 0 oder 1 'diff_precode', int32(options.precode_mode), ... % 0 oder 1 - 'postFFE', ~isempty(options.postFFE), ... % Beispielwert + 'postFFE', double(~isempty(options.postFFE)), ... % Beispielwert 'NpostFFE', npostFFE, ... % Beispielwert 'Ne1', eq_.Ne(1), ... % Feedforward Koeffizienten 1. Ordnung 'Ne2', eq_.Ne(2), ... % Feedforward Koeffizienten 2. Ordnung @@ -202,7 +208,7 @@ equalizerConfigMLSE = struct( ... 'target_constellation', jsonencode(round(unique(tx_symbols.signal),5)), ... % Beispielhafter Target-String 'db_target', 0, ... % 0 oder 1 'diff_precode', int32(options.precode_mode), ... % 0 oder 1 - 'postFFE', ~isempty(options.postFFE), ... % Beispielwert + 'postFFE', double(~isempty(options.postFFE)), ... % Beispielwert 'NpostFFE', npostFFE, ... % Beispielwert 'Ne1', eq_.Ne(1), ... % Feedforward Koeffizienten 1. Ordnung 'Ne2', eq_.Ne(2), ... % Feedforward Koeffizienten 2. Ordnung @@ -234,9 +240,12 @@ eq_package.resultsMLSE = resultsMLSE; eq_package.equalizerConfigVNLE = equalizerConfigVNLE; eq_package.equalizerConfigMLSE = equalizerConfigMLSE; + + % eq_package.vnle_out = eq_signal_sd; if options.showAnalysis + % fprintf(['VNLE EVM lvl: ',repmat('%.3f ',1,numel(evm_lvl)),' \n'],evm_lvl); % fprintf('VNLE BER: %.2e \n',ber_vnle); @@ -264,6 +273,10 @@ if options.showAnalysis figure(341);clf; showLevelHistogram(eq_signal_sd,tx_symbols,"fignum",341); + showLevelScatter(eq_signal_sd,tx_symbols,"fignum",400); + + showLevelScatter(rx_signal.resample("fs_out",tx_symbols.fs),tx_symbols,"fignum",401); + % autoArrangeFigures(3,3,2) diff --git a/Functions/EQ_visuals/showLevelScatter.m b/Functions/EQ_visuals/showLevelScatter.m new file mode 100644 index 0000000..2d5def9 --- /dev/null +++ b/Functions/EQ_visuals/showLevelScatter.m @@ -0,0 +1,129 @@ +function showLevelScatter(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.f_sym = []; +end + +if isa(eq_signal,'Signal') + options.f_sym = eq_signal.fs; + 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 + clf; +end + +assert(~isempty(options.f_sym),'No fsym given'); + +rx_symbols = eq_signal ./ rms(eq_signal); +correct_symbols = ref_symbols; +f_sym = options.f_sym; + +col = cbrewer2('Paired',numel(unique(correct_symbols))*2); +ccnt = -1; + +levels = unique(correct_symbols); + +start = 1; +ende = length(correct_symbols); + +% start = 30000; +% ende = 40000; + +for l = 1:numel(levels) + ccnt = ccnt+2; + + level_amplitude = levels(l); + + symbols_for_lvl = NaN(1,length(correct_symbols)); + symbols_for_lvl(correct_symbols==level_amplitude) = rx_symbols(correct_symbols==level_amplitude); + std_lvl(l) = std(symbols_for_lvl,'omitnan'); + xax_in_sec = ((1:length(correct_symbols)) / f_sym) * 1e6; + % xax_in_sec = 1:length(correct_symbols); + + scatter(xax_in_sec(start:ende),symbols_for_lvl(start:ende),10,'.','MarkerFaceAlpha',0.5,'MarkerEdgeAlpha',0.5,'MarkerEdgeColor',col(ccnt,:)); + hold on; +end + +std_lvl = round(std_lvl,2); + +ccnt = 0; + +% Add the windowed/ smoothed curves +for l = 1:numel(levels) + ccnt = ccnt+2; + level_amplitude = levels(l); + + symbols_for_lvl = NaN(1,length(correct_symbols)); + + movmean = 1/250 .* movsum(rx_symbols(correct_symbols==level_amplitude),[250/2,250/2]); + + symbols_for_lvl(correct_symbols==level_amplitude) = movmean; + + nanx = isnan(symbols_for_lvl); + t = 1:numel(symbols_for_lvl); + symbols_for_lvl(nanx) = interp1(t(~nanx), symbols_for_lvl(~nanx), t(nanx)); + + xax_in_sec = ((1:length(correct_symbols)) / f_sym) * 1e6; + % xax_in_sec = 1:length(correct_symbols); + + plot(xax_in_sec(start:ende),symbols_for_lvl(start:ende),'Color',col(ccnt,:)); + hold on +end + +%yline(max(rx_symbols(correct_symbols==levels(2)))) +yline(levels); + +if 0 + annotation(fig,'textbox',... + [0.660523809523809 0.844444444444448 0.133523809523809 0.0603174603174607],... + 'String',['\sigma = ',num2str(std_lvl(4))],... + 'LineWidth',1.8,... + 'LineStyle','none',... + 'FontSize',12,... + 'FitBoxToText','off'); + + % Create textbox + annotation(fig,'textbox',... + [0.667666666666665 0.642857142857147 0.133523809523809 0.0603174603174607],... + 'String',['\sigma = ',num2str(std_lvl(3))],... + 'LineWidth',1.8,... + 'LineStyle','none',... + 'FontSize',12,... + 'FitBoxToText','off'); + + % Create textbox + annotation(fig,'textbox',... + [0.671238095238093 0.442857142857148 0.133523809523809 0.0603174603174608],... + 'String',['\sigma = ',num2str(std_lvl(2))],... + 'LineWidth',1.8,... + 'LineStyle','none',... + 'FontSize',12,... + 'FitBoxToText','off'); + + % Create textbox + annotation(fig,'textbox',... + [0.670047619047616 0.265079365079371 0.133523809523809 0.0603174603174608],... + 'String',['\sigma = ',num2str(std_lvl(1))],... + 'LineWidth',1.8,... + 'LineStyle','none',... + 'FontSize',12,... + 'FitBoxToText','off'); +end + +% xlim([0, 2.6]) +% ylim([-2 2]) +xlabel('Time in $\mu$s'); +ylabel('Normalized Amplitude'); + +end diff --git a/Functions/Metrics/calc_std.m b/Functions/Metrics/calc_std.m new file mode 100644 index 0000000..5f3a2e5 --- /dev/null +++ b/Functions/Metrics/calc_std.m @@ -0,0 +1,68 @@ +function [std_total,std_lvl] = calc_std(test_signal,reference_signal,options) + +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) -24 || voa.power_state(1)+ voa.atten_state(4) > -38 + if voa.power_state(3) > -24 || voa.power_state(1)+ voa.atten_state(4) > -37 holdAndShowValue end - + % PDFA if ~exist('pdfa','var') pdfa = Thor_PDFA("safety_mode",0,"serialport_number",'COM15'); end - % Construct AWG and Scope Modules %%%%%% - fdac = 224e9; - fadc = 160e9; - Scp = ScopeKeysight("model","DSAZ634A",'autoscale',0,"fadc","GSa_160","channel",[0,0,1,0],"recordLen",recordlen,"removeDC",1,"extRef",1); - Awg = AwgKeysight("model","M8199A_ILV","fdac",fdac,"scaletodac",[1,1],"skews",[0,0],"voltages",[0,conf.v_awg]); - A2S = Awg2Scope(Awg,Scp,[0,0,3,0],"waitUntilClick",0); - end +% if conf.symbolrate == 72e9 +% if conf.pam_level == 2 +% conf.v_awg = 0.55; +% conf.pulsef_alpha = 0.6; +% elseif conf.pam_level == 4 +% conf.v_awg = 0.55; +% conf.pulsef_alpha =0.6; +% elseif conf.pam_level == 6 +% conf.v_awg = 0.55; +% conf.pulsef_alpha = 0.6; +% elseif conf.pam_level == 8 +% conf.v_awg = 0.55; +% conf.pulsef_alpha = 0.6; +% end +% elseif conf.symbolrate == 96e9 +% if conf.pam_level == 2 +% conf.v_awg = 0.8; +% conf.pulsef_alpha = 0.2; +% elseif conf.pam_level == 4 +% conf.v_awg = 0.8; +% conf.pulsef_alpha = 0.2; +% elseif conf.pam_level == 6 +% conf.v_awg = 0.8; +% conf.pulsef_alpha = 0.2; +% elseif conf.pam_level == 8 +% conf.v_awg = 0.8; +% conf.pulsef_alpha = 0.2; +% end +% elseif conf.symbolrate == 112e9 +% if conf.pam_level == 2 +% conf.v_awg = 0.85; +% conf.pulsef_alpha = 0.2; +% elseif conf.pam_level == 4 +% conf.v_awg = 0.85; +% conf.pulsef_alpha = 0.2; +% elseif conf.pam_level == 6 +% conf.v_awg = 0.85; +% conf.pulsef_alpha = 0.2; +% elseif conf.pam_level == 8 +% conf.v_awg = 0.85; +% conf.pulsef_alpha = 0.2; +% end +% end + +awg_upload_required = 1; +if any(confPrev.pam_level == conf.pam_level) && any(confPrev.symbolrate == conf.symbolrate) + awg_upload_required = 0; +end %% Signal generation and transmission if awg_upload_required || isempty(loop_id) @@ -69,6 +110,13 @@ if awg_upload_required || isempty(loop_id) sequence_order = min(18,sequence_order); end + % Construct AWG and Scope Modules %%%%%% + fdac = 224e9; + fadc = 160e9; + Scp = ScopeKeysight("model","DSAZ634A",'autoscale',0,"fadc","GSa_160","channel",[0,0,1,0],"recordLen",recordlen,"removeDC",1,"extRef",1); + Awg = AwgKeysight("model","M8199A_ILV","fdac",fdac,"scaletodac",[1,1],"skews",[0,0],"voltages",[0,conf.v_awg]); + A2S = Awg2Scope(Awg,Scp,[0,0,3,0],"waitUntilClick",0); + Pamsource = PAMsource(... "fsym",conf.symbolrate,"M",conf.pam_level,"order",sequence_order,"useprbs",1,... "fs_out",fdac,... @@ -79,11 +127,11 @@ if awg_upload_required || isempty(loop_id) "randkey",1,... "duobinary_mode", conf.db_mode); - conf.pam_source = Pamsource; - confPrev = conf; - [Digi_sig,Symbols,Bits] = Pamsource.process(); + figure(10);clf; + Digi_sig.spectrum("displayname",'Tx Pulse Shaped','fignum',10,'normalizeTo0dB',1); + %%%%% Precompensation Routine %%%%%% if precomp_mode == 1 % measure channel @@ -94,11 +142,13 @@ if awg_upload_required || isempty(loop_id) Digi_sig = precomp_est.precomp(Digi_sig,'maxampdb',conf.precomp_amp,'loadPath',precomp_path,'fileName',precomp_fn); end - % Digi_sig.spectrum("displayname",'Tx Spectrum','fignum',10,'normalizeTo0dB',0); + Digi_sig.spectrum("displayname",'Tx Pre-Emphasized','fignum',10,'normalizeTo0dB',1); %%%%% Resample to DAC rate %%%%%% Digi_sig = Digi_sig.resample("fs_out",Awg.fdac); + Digi_sig.spectrum("displayname",'Tx Resampled','fignum',10,'normalizeTo0dB',1); + % [~,~,Scpe_sig_raw,~] = A2S.process("signal2",Digi_sig); Awg.upload("signal2",Digi_sig); @@ -113,6 +163,8 @@ if precomp_mode == 1 return; % End routine if precomp mode is active end +confPrev = conf; + %% Save static TX data (only once) currentTime = datetime('now', 'Format', 'yyyyMMdd_HHmmss'); timeStr = char(currentTime); @@ -142,7 +194,7 @@ for recIdx = 1:n_recording end % Plot spectrum and time domain (optional) - % Scpe_sig_raw.spectrum("displayname", 'Rx Spectrum', 'fignum', 10, 'normalizeTo0dB', 0); + Scpe_sig_raw.spectrum("displayname", 'Rx Spectrum', 'fignum', 10, 'normalizeTo0dB', 0); Scpe_sig_raw.plot("clear", 1, "displayname", 'Rx Signal', 'fignum', 11); %% Save Routine @@ -153,7 +205,6 @@ for recIdx = 1:n_recording rx_raw_path = [filesep, current_folder, filesep, filename, '_rx_signal_raw']; save([savePath, rx_raw_path], "Scpe_sig_raw"); - % Check if loop_id is already created if isempty(loop_id) newLoop = db.tables.LoopControl; @@ -165,7 +216,6 @@ for recIdx = 1:n_recording fprintf('LoopControl entry created: loop_id = %d\n', loop_id); end - %% Append to Runs Table newRun = db.tables.Runs; newRun.run_id = NaN; @@ -183,6 +233,8 @@ for recIdx = 1:n_recording %% Append to Configurations Table conf.configuration_id = NaN; conf.run_id = run_id; + conf.bitrate = conf.symbolrate .* floor(log2(6)*10)/10; + conf.pam_source = Pamsource; db.appendToTable('Configurations', conf); %% Append to Measurements Table @@ -210,6 +262,11 @@ for recIdx = 1:n_recording [out, a] = submit_dsp(run_id, databasePath, database_name, savePath, ... "parallel", parallel_dsp, "max_occurences", max_occurences); end + if awg_upload_required + [out, a] = submit_dsp(run_id, databasePath, database_name, savePath, ... + "parallel", 0, "max_occurences", 1); + end end + end diff --git a/projects/ECOC_2025/plots_from_database/bias_vs_ber.m b/projects/ECOC_2025/plots_from_database/bias_vs_ber.m index 60977a2..b92698e 100644 --- a/projects/ECOC_2025/plots_from_database/bias_vs_ber.m +++ b/projects/ECOC_2025/plots_from_database/bias_vs_ber.m @@ -2,7 +2,7 @@ basePath = 'C:\Users\sioe\Documents\MATLAB\imdd_simulation\projects\ECOC_2025\'; database_name = 'ecoc2025.db'; -database = DBHandler("pathToDB", [basePath, database_name]); +database = DBHandler("pathToDB", [basePath, database_name],"type",'mysql'); filterParams = database.tables; filterParams.Configurations = struct( ... diff --git a/projects/ECOC_2025/precomp_1km.mat b/projects/ECOC_2025/precomp_1km.mat new file mode 100644 index 0000000..5c4c625 Binary files /dev/null and b/projects/ECOC_2025/precomp_1km.mat differ diff --git a/projects/ECOC_2025/precomp_1km_1mm_cable.mat b/projects/ECOC_2025/precomp_1km_1mm_cable.mat new file mode 100644 index 0000000..43937a4 Binary files /dev/null and b/projects/ECOC_2025/precomp_1km_1mm_cable.mat differ diff --git a/projects/ECOC_2025/precomp_1km_1mm_cable_100ghz_pd.mat b/projects/ECOC_2025/precomp_1km_1mm_cable_100ghz_pd.mat new file mode 100644 index 0000000..ed37b29 Binary files /dev/null and b/projects/ECOC_2025/precomp_1km_1mm_cable_100ghz_pd.mat differ diff --git a/projects/ECOC_2025/precomp_1km_1mm_cable_70ghz_pd.mat b/projects/ECOC_2025/precomp_1km_1mm_cable_70ghz_pd.mat new file mode 100644 index 0000000..9560ab1 Binary files /dev/null and b/projects/ECOC_2025/precomp_1km_1mm_cable_70ghz_pd.mat differ diff --git a/projects/ECOC_2025/precomp_1km_1mm_cable_70ghz_pd_shf_t850_2p8_bias.mat b/projects/ECOC_2025/precomp_1km_1mm_cable_70ghz_pd_shf_t850_2p8_bias.mat new file mode 100644 index 0000000..5befc3c Binary files /dev/null and b/projects/ECOC_2025/precomp_1km_1mm_cable_70ghz_pd_shf_t850_2p8_bias.mat differ diff --git a/projects/ECOC_2025/precomp_1km_1mm_cable_70ghz_pd_shf_t850_2p8_bias_shot2.mat b/projects/ECOC_2025/precomp_1km_1mm_cable_70ghz_pd_shf_t850_2p8_bias_shot2.mat new file mode 100644 index 0000000..918b1fb Binary files /dev/null and b/projects/ECOC_2025/precomp_1km_1mm_cable_70ghz_pd_shf_t850_2p8_bias_shot2.mat differ diff --git a/projects/ECOC_2025/precomp_1km_1mm_cable_70ghz_pd_shot2.mat b/projects/ECOC_2025/precomp_1km_1mm_cable_70ghz_pd_shot2.mat new file mode 100644 index 0000000..37932d1 Binary files /dev/null and b/projects/ECOC_2025/precomp_1km_1mm_cable_70ghz_pd_shot2.mat differ diff --git a/projects/Lab_base_system/exfo_control_app.mlapp b/projects/Lab_base_system/exfo_control_app.mlapp new file mode 100644 index 0000000..cbd306d Binary files /dev/null and b/projects/Lab_base_system/exfo_control_app.mlapp differ diff --git a/projects/Lab_base_system/exfo_laser_example.m b/projects/Lab_base_system/exfo_laser_example.m new file mode 100644 index 0000000..e059344 --- /dev/null +++ b/projects/Lab_base_system/exfo_laser_example.m @@ -0,0 +1,15 @@ +%% Laser +start_wavelength = 1550; +laser = Exfo_laser("mainframe_channel",3,"safety_mode",0,"connection_id",'10','lab_interface','gpib'); +laser.getLaserInfo(); + +laser.setWavelength(start_wavelength) +laser.setPower(0); + +laser.enableLaser(); +for l = 1550:1560 + laser.setWavelength(l); +end + +laser.disableLaser(); + diff --git a/projects/Lab_base_system/olaf_control.m b/projects/Lab_base_system/olaf_control.m new file mode 100644 index 0000000..d9c72de --- /dev/null +++ b/projects/Lab_base_system/olaf_control.m @@ -0,0 +1,74 @@ + +clear all + +visastring = "GPIB0::22::INSTR"; +v_pwrmtr = visadev(visastring); +writeline(v_pwrmtr, "*IDN?"); +answ = readline(v_pwrmtr); +disp(['Yay! We can talk to Instrument: ',char(answ)]); + +% laser = Exfo_laser("mainframe_channel",3,"safety_mode",0,"connection_id",'15','lab_interface','gpib'); +% laser.getLaserInfo(); + +L = OptLaserN7714A("GPIB0::20::INSTR"); + +% visastring = 'GPIB0::10::INSTR'; +% v_lsr = visadev(visastring); +% writeline(v_lsr, "*IDN?"); +% answ = readline(v_lsr); +% disp(['Yay! We can talk to Instrument: ',char(answ)]); + +steps = 100; +wavelength_sweep = linspace(1554,1556,steps); +start_wavelength = wavelength_sweep(1); + +% laser.setWavelength(start_wavelength); +L.setWavelength(start_wavelength,0); +% laser.setPower(0); +% laser.enableLaser(); +L.setPower(0, true,0); + + +pwr_save = NaN(size(wavelength_sweep)); +for l = 1:numel(wavelength_sweep) + + % 1) + % laser.setWavelength(wavelength_sweep(l)); + L.setWavelength(wavelength_sweep(l),0); + %writeline(v_lsr, ['L=' num2str(wavelength_sweep(l))]); + + % 2) Set Wavelength of Power Meter + t = string(['SENS2:POW:WAVE ',num2str(wavelength_sweep(l)),'NM']); + writeline(v_pwrmtr, t); + % writeline(v, "SENS:POW:WAVE?"); + % wavel = readline(v); + + % 3) Read Power of + writeline(v_pwrmtr, "READ2:POW?"); + pwr = readline(v_pwrmtr); + pwr_save(l) = str2num(pwr); + + figure(2025);clf + plot(wavelength_sweep,pwr_save,'Marker','*'); + xlabel('Wavelength [nm]'); + ylabel('Insertion Loss [dB]'); + ylim([min(pwr_save)-1, min(pwr_save)+1]); + xlim([wavelength_sweep(1) wavelength_sweep(end)]) + grid minor + +end + +% laser.disableLaser(); +L.setPower(0, false,0); +L.delete(); + +%writeline(v_lsr, 'DISABLE'); + +path= "Z:\2025\NFT WDM DFG Olaf\lambda_vs_power"; + +dt = datetime('now','Format','yyyyMMdd_HHmmss'); +filename = fullfile(path, "loop_5_7_"+num2str(wavelength_sweep(1)) +"nm_to_"+ num2str(wavelength_sweep(end))+ "nm_" + string(dt) + ".mat"); + +save(filename, "pwr_save","wavelength_sweep"); + +disp("Saved to: " + filename); diff --git a/projects/Lab_base_system/olaf_laser_att_control_lambda_sweep.m b/projects/Lab_base_system/olaf_laser_att_control_lambda_sweep.m new file mode 100644 index 0000000..91fe52e --- /dev/null +++ b/projects/Lab_base_system/olaf_laser_att_control_lambda_sweep.m @@ -0,0 +1,61 @@ + +clear all + +%%%%%%%%%%%%%%%%%%%%% + +start_wavelength = 1554.2; %nm +stop_wavelength = 1555.7; %nm +steps = 100; +power = 0; %dBm +name = "south_board_total_loss_ports_21_20"; + +%%%%%%%%%%%%%%%%%%%%% + +wavelength_sweep = linspace(start_wavelength,stop_wavelength,steps); +wavelength_1 = wavelength_sweep(1); + +visastring = "GPIB0::22::INSTR"; +v_pwrmtr = visadev(visastring); +%writeline(v_pwrmtr, "*IDN?"); +%answ = readline(v_pwrmtr); +%disp(['Yay! We can talk to Instrument: ',char(answ)]); + +L = OptLaserN7714A("GPIB0::20::INSTR"); +L.setWavelength(wavelength_1,0); +L.setPower(power, true,0); + +pwr_save = NaN(size(wavelength_sweep)); +for l = 1:numel(wavelength_sweep) + + % 1) + L.setWavelength(wavelength_sweep(l),0); + + % 2) Set Wavelength of Power Meter + t = string(['SENS1:POW:WAVE ',num2str(wavelength_sweep(l)),'NM']); + writeline(v_pwrmtr, t); + + % 3) Read Power of + writeline(v_pwrmtr, "READ1:POW?"); + pwr = readline(v_pwrmtr); + pwr_save(l) = str2num(pwr); + + figure(2026);clf + plot(wavelength_sweep,pwr_save,'Marker','*'); + xlabel('Wavelength [nm]'); + ylabel('Insertion Loss [dB]'); + ylim([min(pwr_save)-1, max(pwr_save)+1]); + xlim([wavelength_sweep(1) wavelength_sweep(eind)]) + grid minor +end + +L.setPower(0, false,0); +L.delete(); + +path= "Z:\2025\NFT WDM DFG Olaf\lambda_vs_power"; + +dt = datetime('now','Format','yyyyMMdd_HHmmss'); +filename = fullfile(path, name+"_"+replace(num2str(wavelength_sweep(1)),".","_") +"nm_to_"+ replace(num2str(wavelength_sweep(end)),".","_")+ "nm_" + string(dt) + ".mat"); + +save(filename, "pwr_save","wavelength_sweep"); + +disp("Saved to: " + filename); diff --git a/projects/Lab_base_system/olaf_laser_control.m b/projects/Lab_base_system/olaf_laser_control.m new file mode 100644 index 0000000..cdde961 --- /dev/null +++ b/projects/Lab_base_system/olaf_laser_control.m @@ -0,0 +1,21 @@ +clear all + +% L = OptLaserN7714A("TCPIP0::134.245.243.209::inst0::INSTR"); +% L.setWavelength(1551,1); % nm +% L.setPower(5.8, true,1); % dBm, also turns output ON +% L.setDither(0,1); +% % L.setPower(5.9, false,1); +% info = L.getLaserInfo(); +% +% L.delete(); + + +clear all + +L = OptLaserN7714A("GPIB0::20::INSTR"); +L.setWavelength(1550,0); % nm +L.setPower(0, true,0); % dBm, also turns output ON +L.setPower(0, false,0); +info = L.getLaserInfo(); + +L.delete(); \ No newline at end of file diff --git a/projects/Lab_base_system/olaf_laser_control_minimal.m b/projects/Lab_base_system/olaf_laser_control_minimal.m new file mode 100644 index 0000000..cbe68d1 --- /dev/null +++ b/projects/Lab_base_system/olaf_laser_control_minimal.m @@ -0,0 +1,29 @@ +% --- Minimal N7714A example (MATLAB) --- +visa_addr = "TCPIP0::134.245.243.209::inst0::INSTR"; % <-- change to your laser's IP +port = 1; % 1..4 selects the N7714A output port + +% v = visadev(visa_addr); + +% Identify instrument +writeline(v,'*IDN?'); disp(strtrim(readline(v))); + +% Make sure wavelength is settable (Auto mode) +writeline(v, sprintf('SOUR%d:WAV:AUTO 1', port)); % Auto Mode ON (wavelength set allowed). + +% Set wavelength and power (units explicit) +writeline(v, sprintf('SOUR%d:WAV 1560NM', port)); % set 1550 nm. :contentReference[oaicite:3]{index=3} +writeline(v, sprintf('SOUR%d:POW:UNIT DBM', port)); % power unit = dBm. :contentReference[oaicite:4]{index=4} +writeline(v, sprintf('SOUR%d:POW:LEV:IMM:AMPL 6 DBM', port)); % set -3 dBm. :contentReference[oaicite:5]{index=5} + +% Enable output (either OUTP or SOUR:POW:STAT works) +writeline(v, sprintf('OUTP%d:STAT ON', port)); % laser ON. :contentReference[oaicite:6]{index=6} +writeline(v, 'OUTP1 ON'); + +% ---- Read back to verify ---- +writeline(v, sprintf('SOUR%d:WAV?', port)); wav_m = str2double(readline(v)); +writeline(v, sprintf('SOUR%d:POW:LEV:IMM:AMPL?', port)); pow = str2double(readline(v)); +writeline(v, sprintf('OUTP%d:ON?', port)); onoff = str2double(readline(v)); + +fprintf('Port %d -> %.2f nm, %.2f dBm, Output=%d\n', port, 1e9*wav_m, pow, onoff); + +delete(v); \ No newline at end of file diff --git a/projects/Lab_base_system/olaf_laser_control_single_wavelength_OFF.m b/projects/Lab_base_system/olaf_laser_control_single_wavelength_OFF.m new file mode 100644 index 0000000..1119c82 --- /dev/null +++ b/projects/Lab_base_system/olaf_laser_control_single_wavelength_OFF.m @@ -0,0 +1,2 @@ +L.setPower(power, false,0); +L.delete(); diff --git a/projects/Lab_base_system/olaf_laser_control_single_wavelength_ON.m b/projects/Lab_base_system/olaf_laser_control_single_wavelength_ON.m new file mode 100644 index 0000000..3b00905 --- /dev/null +++ b/projects/Lab_base_system/olaf_laser_control_single_wavelength_ON.m @@ -0,0 +1,19 @@ +clear all + +% 1554.7097 +% 1554.9032 +% 1555.0968 +% 1555.2904 + + +%%%%%%%%%%%%%%%%%%%%% + +wavelength = 1555.0968; %nm +power = 6; %dBm + +%%%%%%%%%%%%%%%%%%%%% + +L = OptLaserN7714A("GPIB0::20::INSTR"); + +L.setWavelength(wavelength,0); +L.setPower(power, true,0); diff --git a/projects/run_loop.m b/projects/run_loop.m index 4248623..537a34e 100644 --- a/projects/run_loop.m +++ b/projects/run_loop.m @@ -13,42 +13,45 @@ end database_name = 'ecoc2025_loops.db'; -if ~exist('db','var') - db = DBHandler("pathToDB", [databasePath, database_name]); -end +db = DBHandler("pathToDB", [databasePath, database_name]); conf = db.tables.Configurations; +% conf = db.tables.Configurations; if ~exist('confPrev','var') - confPrev = db.tables.Configurations; + confPrev = conf; end awg_upload_required = 1; %still uploads every first round subimt_DSP = 1; -recordlen = 5000000; -sequence_order = 19; -n_recording = 2; % Or any number you want +recordlen = 1000000; +sequence_order = 17; +n_recording = 1; % Or any number you want + +conf=rmfield(conf,"interference_attenuation"); +conf=rmfield(conf,"symbolrate"); +conf=rmfield(conf,"pam_level"); % Define vector parameters directly in conf: conf.unique_elab_id = "20250408-842b0a3078172b48dd032795226fbe683190afc4"; conf.db_mode = db_mode.no_db; conf.pulsef_alpha = 0.2; conf.v_bias = 2.65; -conf.v_awg = 0.9; +conf.v_awg = 0.85; conf.precomp_amp = -64; %-64 conf.wavelength = 1310; conf.laser_power = 11; conf.fiber_length = 0; conf.pd_in_desired = 9; -conf.is_mpi = 1; +conf.is_mpi = true; conf.signal_attenuation = 0; -conf.interference_path_length = 300; %m -conf.interference_attenuation = [0:2:30,40]; -conf.pam_level = [4,6,8]; -conf.symbolrate = [56,72,96,112].*1e9; -conf.bitrate = conf.symbolrate .* floor(log2(6)*10)/10; +conf.interference_path_length = 20; %m +conf.interference_attenuation = 10;%[0:2:30,40]; +conf.pam_level = 4;%[2,4,6,8]; +conf.symbolrate = [112].*1e9; + conf.pam_source = []; if conf.is_mpi - current_folder = ['mpi_',num2str(conf.interference_path_length),'m_pam',num2str(conf.pam_level)]; + current_folder = ['test_mpi_opti_',num2str(conf.interference_path_length),'m_pam',num2str(conf.pam_level)]; else current_folder = 'testing'; end @@ -106,10 +109,23 @@ else end end - fprintf('Running measurement: %s\n', strjoin(paramDisplayCell, ', ')); + fprintf('Running measurement: %s ---> %d of %d done \n ', strjoin(paramDisplayCell, ', '),runIdx, totalRuns); + + if confRequest.pam_level == 2 + confRequest.symbolrate = 112e9; + elseif confRequest.pam_level == 4 + confRequest.symbolrate = 112e9; + elseif confRequest.pam_level == 6 + confRequest.symbolrate = 96e9; + elseif confRequest.pam_level == 8 + confRequest.symbolrate = 72e9; + end + confRequest.bitrate = confRequest.symbolrate * floor(log2(confRequest.pam_level) * 10) / 10; % measure_run("config",confRun,"parallel",parallel_dsp,"max_occurences",max_occurences); - measure_run_script; + + measure_run_script; + end end