diff --git a/Classes/05_Lab/AwgKeysight.m b/Classes/05_Lab/AwgKeysight.m index ec82430..68e34f0 100644 --- a/Classes/05_Lab/AwgKeysight.m +++ b/Classes/05_Lab/AwgKeysight.m @@ -226,7 +226,7 @@ classdef AwgKeysight case awg_model.M8199A v = visadev('TCPIP0::Zizou::hislip2::INSTR'); case awg_model.M8199A_ILV - v = visadev('TCPIP0::Zizou::hislip2::INSTR'); + v = visadev('TCPIP0::Zizou::hislip0::INSTR'); end debug = 0; diff --git a/Functions/Lab_helper/holdAndShowValue.m b/Functions/Lab_helper/holdAndShowValue.m index 1740aaa..5efe6ae 100644 --- a/Functions/Lab_helper/holdAndShowValue.m +++ b/Functions/Lab_helper/holdAndShowValue.m @@ -15,7 +15,7 @@ function holdAndShowValue() 'ButtonPushedFcn', @(src, event) closeWindow()); % Initialize the timer - updateTimer = timer('ExecutionMode', 'fixedRate', 'Period', 0.1, ... + updateTimer = timer('ExecutionMode', 'fixedRate', 'Period', 0.5, ... 'TimerFcn', @(src, event) updatePowerValues()); % Start the timer diff --git a/projects/ECOC_2025/measure_run_script.m b/projects/ECOC_2025/measure_run_script.m index 15405f8..4abd8eb 100644 --- a/projects/ECOC_2025/measure_run_script.m +++ b/projects/ECOC_2025/measure_run_script.m @@ -1,7 +1,5 @@ -savePath = 'Z:\2025\ECOC Silas\ecoc_2025\'; - fullFolderPath = fullfile(savePath, current_folder); if ~exist(fullFolderPath, 'dir') mkdir(fullFolderPath); @@ -19,19 +17,19 @@ referenceFields = fieldnames(db.tables.Configurations); assert(isequal(fieldnames(conf), referenceFields), 'Fieldnames do not match the reference structure!'); - %% Lab Automation if run_lab_automation % DC Source - if confPrev.v_bias ~= conf.v_bias + if (any(confPrev.v_bias ~= conf.v_bias)) || (~exist('dcs','var')) || (isempty(confPrev.v_bias)) dcs = DC_supply("active",[1,1],"voltage",[conf.v_bias, 5]); dcs.set("voltage",[conf.v_bias, 5]); [v_bias_meas,i_bias_meas]=dcs.readVals(); end % Laser - if confPrev.laser_power ~= conf.laser_power + + if (any(confPrev.laser_power ~= conf.laser_power)) || (~exist('laser','var')) || (isempty(confPrev.laser_power)) laser = Exfo_laser("mainframe_channel",1,"safety_mode",0,"connection_id",'10','lab_interface','gpib'); laser.setWavelength(conf.wavelength); laser.setPower(conf.laser_power); @@ -39,16 +37,24 @@ if run_lab_automation end % Optical Attenuator - voa = OptAtten("active",[0,2,1,1],"value",[0,conf.pd_in_desired,conf.signal_attenuation,conf.interference_attenuation],"wavelength",[conf.wavelength,conf.wavelength,conf.wavelength,conf.wavelength]); + if ~exist('voa','var') + voa = OptAtten("active",[1,2,1,1],"value",[0,conf.pd_in_desired,conf.signal_attenuation,conf.interference_attenuation],"wavelength",[conf.wavelength,conf.wavelength,conf.wavelength,conf.wavelength]); + end voa.set('value',[0,conf.pd_in_desired,conf.signal_attenuation,conf.interference_attenuation]); + if voa.power_state(3) > -24 || voa.power_state(1)+ voa.atten_state(4) > -38 + holdAndShowValue + end + % PDFA - pdfa = Thor_PDFA("safety_mode",0,"serialport_number",'COM15'); + 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',1,"fadc","GSa_160","channel",[0,0,1,0],"recordLen",5000000,"removeDC",1,"extRef",1); + 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); @@ -56,12 +62,16 @@ end %% Signal generation and transmission -if 0% awg_upload_required || isempty(loop_id) +if awg_upload_required || isempty(loop_id) %%%%% Symbol Generation %%%%%% Pform = Pulseformer("fsym",conf.symbolrate,"fdac",8*conf.symbolrate,"pulse","rc","pulselength",16,"alpha",conf.pulsef_alpha); - + + if conf.symbolrate < 64e9 + sequence_order = min(18,sequence_order); + end + Pamsource = PAMsource(... - "fsym",conf.symbolrate,"M",conf.pam_level,"order",19,"useprbs",1,... + "fsym",conf.symbolrate,"M",conf.pam_level,"order",sequence_order,"useprbs",1,... "fs_out",fdac,... "applyclipping",0,... "clipfactor",4,... @@ -69,13 +79,13 @@ if 0% awg_upload_required || isempty(loop_id) "pulseformer",Pform,... "randkey",1,... "duobinary_mode", conf.db_mode); - + conf.pam_source = Pamsource; confPrev = conf; - + [Digi_sig,Symbols,Bits] = Pamsource.process(); - - + + %%%%% Precompensation Routine %%%%%% if precomp_mode == 1 % measure channel precomp_est = ChannelFreqResp("Nacq",2048,"Navg",100,"Ncp",63,'f_ref',fdac); @@ -84,12 +94,12 @@ if 0% awg_upload_required || isempty(loop_id) precomp_est = ChannelFreqResp("Nacq",2048,"Navg",100,"Ncp",63,'f_ref',Digi_sig.fs); 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); - + %%%%% Resample to DAC rate %%%%%% Digi_sig = Digi_sig.resample("fs_out",Awg.fdac); - + % [~,~,Scpe_sig_raw,~] = A2S.process("signal2",Digi_sig); Awg.upload("signal2",Digi_sig); @@ -104,7 +114,6 @@ if precomp_mode == 1 return; % End routine if precomp mode is active end - %% Save static TX data (only once) currentTime = datetime('now', 'Format', 'yyyyMMdd_HHmmss'); timeStr = char(currentTime); @@ -119,8 +128,6 @@ save([savePath, tx_symbols_path], "Symbols"); tx_signal_path = [filesep, current_folder, filesep, base_filename, '_signal']; save([savePath, tx_signal_path], "Digi_sig"); -n_recording = 2; % Or any number you want - for recIdx = 1:n_recording fprintf('Recording %d / %d\n', recIdx, n_recording); @@ -167,7 +174,7 @@ for recIdx = 1:n_recording newRun.date_of_run = datetime(currentTime, 'InputFormat', 'yyyyMMdd_HHmmss'); newRun.tx_bits_path = tx_bits_path; newRun.tx_symbols_path = tx_symbols_path; - newRun.rx_sync_path = []; % Leave empty for now + newRun.rx_sync_path = ""; % Leave empty for now newRun.rx_raw_path = rx_raw_path; newRun.filename = filename; newRun.tx_signal_path = tx_signal_path; @@ -197,10 +204,12 @@ for recIdx = 1:n_recording db.appendToTable('Measurements', meas); - %% Submit DSP Routine - - % [out, ~] = submit_dsp(run_id, basePath, database_name, savePath, ... - % "parallel", parallel_dsp, "max_occurences", max_occurences); + %% Submit DSP Routine + + if subimt_DSP + [out, a] = submit_dsp(run_id, databasePath, database_name, savePath, ... + "parallel", parallel_dsp, "max_occurences", max_occurences); + end end diff --git a/projects/ECOC_2025/plots_from_database/plot_mpi_trial.m b/projects/ECOC_2025/plots_from_database/plot_mpi_trial.m index e737228..26a85c6 100644 --- a/projects/ECOC_2025/plots_from_database/plot_mpi_trial.m +++ b/projects/ECOC_2025/plots_from_database/plot_mpi_trial.m @@ -1,8 +1,20 @@ +local = 1; + +if local + databasePath = 'C:\Users\sioe\Documents\MATLAB\imdd_simulation\projects\ECOC_2025\'; +else + databasePath = '\\ntserver.tf.uni-kiel.de\scratch\sioe\ECOC_2025\'; +end -basePath = 'C:\Users\sioe\Documents\MATLAB\imdd_simulation\projects\ECOC_2025\'; database_name = 'ecoc2025_loops.db'; -database = DBHandler("pathToDB", [basePath, database_name]); +database = DBHandler("pathToDB", [databasePath, database_name]); + +figure(); +plotBoundaries = 1; +plotRealizations = 1; +cols = linspecer(3); % Ensure color count matches +% cols = cols(8,:); filterParams = database.tables; filterParams.Configurations = struct( ... @@ -10,7 +22,7 @@ filterParams.Configurations = struct( ... 'fiber_length', 0, ... 'db_mode', '"no_db"', ... 'interference_attenuation', [], ... - 'interference_path_length', 50, ... + 'interference_path_length', 10, ... 'is_mpi', 1, ... 'pam_level', 4, ... 'wavelength', 1310, ... @@ -23,8 +35,8 @@ filterParams.Configurations = struct( ... % filterParams.EqualizerParameters.diff_precode = int32(db_mode.db_encoded); % filterParams.EqualizerParameters.equalizer_structure = int32(equalizer_structure.vnle); -selectedFields = {'Configurations.run_id' 'Runs.date_of_run' 'Runs.rx_raw_path' 'Configurations.bitrate' 'Configurations.v_bias' 'Configurations.v_awg' 'Configurations.precomp_amp' 'Configurations.symbolrate' 'Configurations.pam_level'... - 'Configurations.db_mode' 'Configurations.rop_attenuation' 'Configurations.is_mpi' 'Configurations.interference_attenuation' 'Configurations.signal_attenuation' ... +selectedFields = {'Configurations.run_id' 'Runs.loop_id' 'Runs.date_of_run' 'Runs.rx_raw_path' 'Configurations.bitrate' 'Configurations.v_bias' 'Configurations.v_awg' 'Configurations.precomp_amp' 'Configurations.symbolrate' 'Configurations.pam_level'... + 'Configurations.db_mode' 'Configurations.rop_attenuation' 'Configurations.is_mpi' 'Configurations.interference_attenuation' 'Configurations.interference_path_length' 'Configurations.signal_attenuation' ... 'EqualizerParameters.equalizer_structure' 'EqualizerParameters.diff_precode' 'EqualizerParameters.eq_id' 'Measurements.power_pd_in' ... 'Measurements.power_mpi_interference' 'Measurements.power_mpi_signal' 'Results.BER' 'Results.BER_precoded' 'Results.SNR' 'Results.GMI' 'Results.Alpha' 'Results.date_of_processing'}; @@ -32,14 +44,18 @@ selectedFields = {'Configurations.run_id' 'Runs.date_of_run' 'Runs.rx_raw_path' dataTable.SIR = round(-6 - dataTable.power_mpi_interference); dataTable = cleanUpTable(dataTable); -% Filter by time -startTime = datetime('2025-04-12 18:00:00', 'InputFormat', 'yyyy-MM-dd HH:mm:ss'); -stopTime = datetime('2025-04-13 19:30:00', 'InputFormat', 'yyyy-MM-dd HH:mm:ss'); -dataTable.date_of_run = datetime(dataTable.date_of_run, 'InputFormat', 'yyyy-MM-dd HH:mm:ss.SSSSSS'); -dataTable.date_of_processing = datetime(dataTable.date_of_processing, 'InputFormat', 'yyyy-MM-dd HH:mm:ss.SSSSSS'); -dataTable = dataTable(dataTable.date_of_processing > startTime, :); -dataTable = dataTable(dataTable.date_of_processing < stopTime, :); +dataTable(dataTable.eq_id==0,:) = []; +% Filter by time +filter_by_time = 0; +if filter_by_time + startTime = datetime('2025-04-14 13:00:00', 'InputFormat', 'yyyy-MM-dd HH:mm:ss'); + stopTime = datetime('2025-04-14 19:30:00', 'InputFormat', 'yyyy-MM-dd HH:mm:ss'); + dataTable.date_of_run = datetime(dataTable.date_of_run, 'InputFormat', 'yyyy-MM-dd HH:mm:ss.SSSSSS'); + dataTable.date_of_processing = datetime(dataTable.date_of_processing, 'InputFormat', 'yyyy-MM-dd HH:mm:ss.SSSSSS'); + dataTable = dataTable(dataTable.date_of_processing > startTime, :); + dataTable = dataTable(dataTable.date_of_processing < stopTime, :); +end % Group by smth y_var = 'BER'; x_var = 'SIR'; @@ -53,16 +69,14 @@ dataTableGrpd_mean = groupIt(fixedVars, dataTable, @mean); dataTableGrpd_min = groupIt(fixedVars, dataTable, @min); dataTableGrpd_max = groupIt(fixedVars, dataTable, @max); -plotRealizations = 1; + % Create a new figure mkr = '.'; -figure(); hold on unique_loop_var = unique(dataTable.(loop_var)); -cols = linspecer(numel(unique_loop_var)); % Ensure color count matches -for i = 1:2%1:numel(unique_loop_var) +for i = 1%:numel(unique_loop_var) % Prepare filtered data for this loop variable loopValue = unique_loop_var(i); @@ -86,31 +100,38 @@ for i = 1:2%1:numel(unique_loop_var) % Display name (optional) idx = find(dataTable.(loop_var) == loopValue, 1, 'first'); dispname = equalizer_structure(dataTable.equalizer_structure(idx)); + dispname = [char(dispname),'; ',num2str(unique(dataTable.interference_path_length)),' m']; - % Plot bounded line - [hl, hp] = boundedline(x_values, y_mean, y_bounds, ... - 'alpha', 'transparency', 0.2, ... - 'cmap', cols(i,:), ... - 'nan', 'fill', ... - 'orientation', 'vert'); + if plotBoundaries + % Plot bounded line + [hl, hp] = boundedline(x_values, y_mean, y_bounds, ... + 'alpha', 'transparency', 0.2, ... + 'cmap', cols(i,:), ... + 'nan', 'fill', ... + 'orientation', 'vert'); + + % Style the main line: thinnest, dotted, no marker + set(hl, 'LineWidth', 1, 'LineStyle', '-', 'Marker', 'none', ... + 'Color', cols(i,:), 'DisplayName', string(dispname)); + + % Hide patch (shaded area) from legend + set(hp, 'HandleVisibility', 'off','LineStyle',':','LineWidth',0.5,'Marker','none'); + + % Add invisible scatter for DataTips + plt = scatter(x_values, y_mean, ... + 'Marker', 'o', 'MarkerEdgeColor', 'none', 'MarkerFaceColor', 'none', ... + 'HandleVisibility', 'off', 'PickableParts', 'all'); + else + plt= plot(x_values,y_mean,'LineWidth', 1, 'LineStyle', '-', 'Marker', 'none', ... + 'Color', cols(i,:), 'DisplayName', string(dispname)); + end + % Add data tips to the invisible scatter + pair_one = {'Run ID', dataTableGrpd_mean.run_id(loopFiltGrpd, :)}; + pair_two = {'Rate', dataTableGrpd_mean.bitrate(loopFiltGrpd, :) * 1e-9}; + pair_three = {'PD in', round(dataTableGrpd_mean.power_pd_in(loopFiltGrpd, :), 2)}; + addDatatips(plt, pair_one, pair_two, pair_three); - % Style the main line: thinnest, dotted, no marker - set(hl, 'LineWidth', 1, 'LineStyle', '-', 'Marker', 'none', ... - 'Color', cols(i,:), 'DisplayName', string(dispname)); - - % Hide patch (shaded area) from legend - set(hp, 'HandleVisibility', 'off','LineStyle',':','LineWidth',0.5,'Marker','none'); - - % Add invisible scatter for DataTips - sc_fake = scatter(x_values, y_mean, ... - 'Marker', 'o', 'MarkerEdgeColor', 'none', 'MarkerFaceColor', 'none', ... - 'HandleVisibility', 'off', 'PickableParts', 'all'); - - % Add data tips to the invisible scatter - pair_one = {'Run ID', dataTableGrpd_mean.run_id(loopFiltGrpd, :)}; - pair_two = {'Rate', dataTableGrpd_mean.bitrate(loopFiltGrpd, :) * 1e-9}; - pair_three = {'PD in', round(dataTableGrpd_mean.power_pd_in(loopFiltGrpd, :), 2)}; - addDatatips(sc_fake, pair_one, pair_two, pair_three); + % Optionally: outline bounds for better visibility (optional) % hnew = outlinebounds(hl, hp); @@ -145,6 +166,8 @@ if y_var == 'BER' ylim([1e-5, 0.1]); end +xlim([15,50]); + % Enable grid and beautify grid on; beautifyBERplot; diff --git a/projects/run_loop.m b/projects/run_loop.m index 35a7178..4eedbe8 100644 --- a/projects/run_loop.m +++ b/projects/run_loop.m @@ -2,23 +2,36 @@ % === Prepare base configuration === % databasePath = 'C:\Users\sioe\Documents\MATLAB\imdd_simulation\projects\ECOC_2025\'; -databasePath = 'Z:\2025\ECOC Silas\'; -database_name = 'ecoc2025_loops.db'; -db = DBHandler("pathToDB", [databasePath, database_name]); -conf = db.tables.Configurations; -confPrev = db.tables.Configurations; +local = 1; +if local + databasePath = 'C:\Users\sioe\Documents\MATLAB\imdd_simulation\projects\ECOC_2025\'; + savePath = 'Z:\2025\ECOC Silas\ecoc_2025\'; +else + databasePath = 'C:\Users\sioe\Documents\MATLAB\imdd_simulation\projects\ECOC_2025\'; + savePath = 'Z:\2025\ECOC Silas\ecoc_2025\'; +end -awg_upload_required = 0; +database_name = 'ecoc2025_loops.db'; + +db = DBHandler("pathToDB", [databasePath, database_name],"type",'mysql'); + +conf = db.tables.Configurations; +if ~exist('confPrev','var') + confPrev = db.tables.Configurations; +end + +awg_upload_required = 1; %still uploads every first round +subimt_DSP = 1; +recordlen = 5000000; +sequence_order = 17; +n_recording = 1; % Or any number you want % Define vector parameters directly in conf: conf.unique_elab_id = "20250408-842b0a3078172b48dd032795226fbe683190afc4"; -conf.symbolrate = 112e9; -conf.bitrate = conf.symbolrate .* floor(log2(6)*10)/10; -conf.pam_level = 4; conf.db_mode = db_mode.no_db; conf.pulsef_alpha = 0.2; -conf.v_bias = 2.5; -conf.v_awg = 0.95; +conf.v_bias = 2.65; +conf.v_awg = 0.9; conf.precomp_amp = -64; %-64 conf.wavelength = 1310; conf.laser_power = 11; @@ -26,8 +39,11 @@ conf.fiber_length = 0; conf.pd_in_desired = 9; conf.is_mpi = 1; conf.signal_attenuation = 0; -conf.interference_path_length = 1000; %m -conf.interference_attenuation = [40,20:-1:0]; +conf.interference_path_length = 0; %m +conf.interference_attenuation = 40;%[0:2:30,40]; +conf.pam_level = 4;%[4,6,8]; +conf.symbolrate = 56e9;%[56,72,96,112].*1e9; +conf.bitrate = conf.symbolrate .* floor(log2(6)*10)/10; conf.pam_source = []; if conf.is_mpi diff --git a/test/database_mysql_test.m b/test/database_mysql_test.m new file mode 100644 index 0000000..a33e57c --- /dev/null +++ b/test/database_mysql_test.m @@ -0,0 +1,17 @@ + +db = DBHandler("type","mysql"); + +db.tableNames +currentTime = datetime('now', 'Format', 'yyyyMMdd_HHmmss'); +newRun = db.tables.Runs; +newRun.run_id = NaN; +newRun.loop_id = 82; +newRun.date_of_run = datetime(currentTime, 'InputFormat', 'yyyyMMdd_HHmmss'); +newRun.tx_bits_path = 'pathtohell'; +newRun.tx_symbols_path = 'pathtohell2'; +newRun.rx_sync_path = ""; % Leave empty for now +newRun.rx_raw_path = 'pathtohell4'; +newRun.filename = 'filenametohell'; +newRun.tx_signal_path = 'pathtohell'; + +run_id = db.appendToTable('Runs', newRun); \ No newline at end of file