Skip to content

Commit

Permalink
Merge pull request #324 from qutech/triton_200/to_master
Browse files Browse the repository at this point in the history
Triton 200/to master
  • Loading branch information
terrorfisch committed Aug 3, 2018
2 parents 22ca8c8 + 4e8af27 commit d1c618e
Show file tree
Hide file tree
Showing 29 changed files with 1,121 additions and 201 deletions.
29 changes: 24 additions & 5 deletions MATLAB/+qc/awg_program.m
Original file line number Diff line number Diff line change
Expand Up @@ -78,14 +78,19 @@
% whole pulse time and can return data before the AWG stops playing
% the pulse.
if ~isempty(plsdata.awg.currentProgam)
waitingTime = min(max(plsdata.awg.registeredPrograms.(plsdata.awg.currentProgam).pulse_duration - (now() - plsdata.awg.triggerStartTime)*24*60*60, 0), plsdata.awg.maxPulseWait);
waitingTime = min(max(plsdata.awg.registeredPrograms.(plsdata.awg.currentProgam).pulse_duration + plsdata.awg.registeredPrograms.(plsdata.awg.currentProgam).added_to_pulse_duration - (now() - plsdata.awg.triggerStartTime)*24*60*60, 0), plsdata.awg.maxPulseWait);
if waitingTime == plsdata.awg.maxPulseWait
warning('Maximum waiting time ''plsdata.awg.maxPulseWait'' = %g s reached.\nIncrease if you experience problems with the data acquistion.', plsdata.awg.maxPulseWait);
end
pause(waitingTime);
end
% fprintf('Waited for %.3fs for pulse to complete\n', waitingTime);
end

% No longer needed since bug has been fixed
% qc.workaround_4chan_program_errors(a);

hws.arm_program(a.program_name);
hws.arm_program(a.program_name);

plsdata.awg.currentProgam = a.program_name;
bool = true;
msg = sprintf('Program ''%s'' armed', a.program_name);
Expand Down Expand Up @@ -115,7 +120,7 @@
% dacToArm{1}.arm_program(plsdata.awg.currentProgam);
% end

qc.awg_program('arm', 'program_name', globalProgram, 'verbosity', a.verbosity);
qc.awg_program('arm', 'program_name', globalProgram, 'verbosity', a.verbosity, 'arm_global_for_workaround_4chan_program_errors', []);

% --- remove ------------------------------------------------------------
elseif strcmp(ctrl, 'remove')
Expand Down Expand Up @@ -186,9 +191,23 @@

newProgram = qc.program_to_struct(a.program_name, a.pulse_template, a.parameters_and_dicts, a.channel_mapping, a.window_mapping);
newProgram = qc.get_minimal_program(newProgram);
% pulse_duration is just a helper field, can recognize whether
% program has changed without it. Removing it for the equality check
% below allows for changing the program duration dynamically on the
% AWG, e.g. for DNP.
if isfield(newProgram , 'added_to_pulse_duration')
newProgram = rmfield(newProgram , 'added_to_pulse_duration');
end

awgProgram = plsdata.awg.registeredPrograms.(a.program_name);
awgProgram = qc.get_minimal_program(awgProgram);
awgProgram = qc.get_minimal_program(awgProgram);
% pulse_duration is just a helper field, can recognize whether
% program has changed without it. Removing it for the equality check
% below allows for changing the program duration dynamically on the
% AWG, e.g. for DNP.
if isfield(awgProgram, 'added_to_pulse_duration')
awgProgram = rmfield(awgProgram, 'added_to_pulse_duration');
end

bool = isequal(newProgram, awgProgram);

Expand Down
32 changes: 32 additions & 0 deletions MATLAB/+qc/change_armed_program.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
function change_armed_program(program_name, turn_awg_off)
% CHANGE_ARMED_PROGRAM Force arming of a program on Tabor AWG
% This function calls change_armed_program and each Tabor channel pair
% which contains the indicated program. The program needs to be already
% present on the AWG.
% --- Inputs --------------------------------------------------------------
% program_name : Program name which is armed
% turn_awg_off : Turn AWG off after arming the program.
% Default is true.
% -------------------------------------------------------------------------
% (c) 2018/06 Pascal Cerfontaine (cerfontaine@physik.rwth-aachen.de)

global plsdata
hws = plsdata.awg.hardwareSetup;

if nargin < 2 || isempty(turn_awg_off)
turn_awg_off = true;
end

known_awgs = util.py.py2mat(hws.known_awgs);

for k = 1:length(known_awgs)
known_programs{k} = util.py.py2mat(py.getattr(known_awgs{k}, '_known_programs'));

if isfield(known_programs{k}, program_name)
known_awgs{k}.change_armed_program(program_name);
end
end

if turn_awg_off
awgctrl('off');
end
143 changes: 93 additions & 50 deletions MATLAB/+qc/conf_seq.m
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,6 @@
% This function gets only underscore arguments to be more consistend with
% qctoolkit. Other variables in this function are camel case.
%
% TODO
% * Implement dbz feedback (use polarizefn to arm another program that has
% no defined measurements and thus needs no reconfiguring of the Alazar)
%
% --- Outputs -------------------------------------------------------------
% scan : special-measure scan
%
Expand All @@ -33,44 +29,55 @@
% objects to avoid erroneous saving when the scan is executed.
defaultArgs = struct(...
... Pulses
'program_name', 'default_program', ...
'pulse_template', 'default_pulse', ...
'parameters_and_dicts', {plsdata.awg.defaultParametersAndDicts}, ...
'channel_mapping', plsdata.awg.defaultChannelMapping, ...
'window_mapping', plsdata.awg.defaultWindowMapping, ...
'add_marker', {plsdata.awg.defaultAddMarker}, ...
'force_update', false, ...
'add_custom_pulse', false, ... % Automatically add a custom pulse in sequence
'add_custom_pulse_fn', @tune.add_dbz_fid, ... % Can specify a custom function here which modifies the variable a below
'save_custom_var_fn', @tune.get_global_opts,...% Can specify a function which returns data to be saved in the scan
'program_name', 'default_program', ...
'pulse_template', 'default_pulse', ...
'parameters_and_dicts', {plsdata.awg.defaultParametersAndDicts}, ...
'channel_mapping', plsdata.awg.defaultChannelMapping, ...
'window_mapping', plsdata.awg.defaultWindowMapping, ...
'add_marker', {plsdata.awg.defaultAddMarker}, ...
'force_update', false, ...
...
... Measurements
'operations', {plsdata.daq.defaultOperations}, ...
... Pulse modification
'pulse_modifier_args', struct(), ... % Additional arguments passed to the pulse_modifier_fn
'pulse_modifier', false, ... % Automatically change the variable a (all input arguments) below, can be used to dynamically modify the pulse
'pulse_modifier_fn', @tune.add_dbz_fid, ... % Can specify a custom function here which modifies the variable a (all input arguments) below
...
... Other
'nrep', 10, ... % numer of repetition of pulse
'fig_id', 2000, ...
'fig_position', [-1919 2 1693 994], ...
'disp_ops', 'default', ... % Refers to operations: List of indices of operations to show
'disp_dim', [1 2], ... % dimension of display
'delete_getchans', [1], ... % Refers to getchans: Indices of getchans (including those generated by procfns) to delete after the scan is complete
'procfn_ops', {{}}, ... % Refers to operations: One entry for each virtual channel, each cell entry has two element: fn, args and dim.
... If there are more entries than operations, the nth+1 entry is applied to the 1st operation again.
'saveloop', 100, ... % save every nth loop
'dnp', false, ... % enable DNP
'arm_global', false, ... % If true, set the program to be armed via tunedata.global_opts.conf_seq.arm_program_name.
... % If you use this, all programs need to be uploaded manually before the scan and need to
... % have the same Alazar configuration.
'rf_sources', [true true], ... % turn RF sources on and off automatically
'verbosity', 10 ... % 0: display nothing, 10: display all except when arming program, 11: display all
... Saving variables
'save_custom_var_fn', @tune.get_global_opts,... % Can specify a function which returns data to be saved in the scan
'save_custom_var_args', {{'dnp', 'tune_gui'}}, ...
...
... Measurements
'operations', {plsdata.daq.defaultOperations}, ...
...
... Other
'nrep', 10, ... % Numer of repetition of pulse
'fig_id', 2000, ...
'fig_position', [-1919 2 1693 994], ...
'disp_ops', ' default', ... % Refers to operations: List of indices of operations to show
'disp_dim', [1 2], ... % dimension of display
'delete_getchans', [1], ... % Refers to getchans: Indices of getchans (including those generated by procfns) to delete after the scan is complete
'procfn_ops', {{}}, ... % Refers to operations: One entry for each virtual channel, each cell entry has four or five element: fn, args, dim, operation index, (optional) identifier
... If there are more entries than operations, the nth+1 entry is applied to the 1st operation again.
'saveloop', 0, ... % save every nth loop
'useCustomCleanupFn', false, ... % If this flag is true
'customCleanupFn', [], ... % clean up anything else you would like cleaned up
'useCustomConfigFn', false, ... % If this flag is true
'customConfigFn', [], ... % add a custom config function which is executed directly before the AWG is turned on
'arm_global', false, ... % If true, set the program to be armed via tunedata.global_opts.conf_seq.arm_program_name.
... % If you use this, all programs need to be uploaded manually before the scan and need to
... % have the same Alazar configuration.
'rf_sources', [true true], ... % turn RF sources on and off automatically
'verbosity', 10 ... % 0: display nothing, 10: display all except when arming program, 11: display all
);
a = util.parse_varargin(varargin, defaultArgs);
aOriginal = a;

if a.add_custom_pulse
if a.pulse_modifier
try
a = feval(a.add_custom_pulse_fn, a); % Add any proprietary function here
a = feval(a.pulse_modifier_fn, a); % Add any proprietary function here
catch err
warning('Could not add custom pulse:\n%s', err.getReport());
warning('Could not run pulse_modifier_fn successfully. Continuing as if pulse_modifier was false:\n%s', err.getReport());
a = aOriginal;
end
end

Expand All @@ -85,8 +92,17 @@
scan = struct('configfn', [], 'cleanupfn', [], 'loops', struct('prefn', []));

% Save file and arguments with which scan was created (not stricly necessary)
try
if ischar(aOriginal.pulse_modifier_fn)
scan.data.pulse_modifier_fn = fileread(which(aOriginal.pulse_modifier_fn));
else
scan.data.pulse_modifier_fn = fileread(which(func2str(aOriginal.pulse_modifier_fn)));
end
catch err
warning('Could not load pulse_modifier_fn for saving in scan for reproducibility:\n%s', err.getReport());
end
scan.data.conf_seq_fn = fileread([mfilename('fullpath') '.m']);
scan.data.conf_seq_args = a;
scan.data.conf_seq_args = aOriginal;

% Configure channels
scan.loops(1).getchan = {'ATSV', 'time'};
Expand Down Expand Up @@ -177,7 +193,19 @@

% Add custom variables for documentation purposes
scan.configfn(end+1).fn = @smaconfigwrap_save_data;
scan.configfn(end).args = {'custom_var', a.save_custom_var_fn};
scan.configfn(end).args = {'custom_var', a.save_custom_var_fn, a.save_custom_var_args};

% Add custom cleanup fn
if a.useCustomCleanupFn && ~isempty(a.customCleanupFn)
scan.configfn(end+1).fn = a.customCleanupFn;
scan.configfn(end).args = {};
end

% Add custom config fn
if a.useCustomConfigFn && ~isempty(a.customConfigFn)
scan.configfn(end+1).fn = a.customConfigFn;
scan.configfn(end).args = {};
end

% Delete unnecessary data
scan.cleanupfn(end+1).fn = @qc.cleanupfn_delete_getchans;
Expand Down Expand Up @@ -220,21 +248,23 @@
end

% Add user procfns
nProcFn = numel(scan.loops(1).procfn);
for opInd = 1:numel(a.procfn_ops) % count through operations
if isempty(a.procfn_ops{opInd})
warning('Using empty procfns has not been tested yet. It might work or it might not!');
a.disp_ops(a.disp_ops(opInd) >= opInd) = a.disp_ops(a.disp_ops(opInd) >= opInd) - 1;
continue;
end
inchan = nGetChan + mod(opInd-1, nOperations)+1;
if isfield(scan.loops(1), 'procfn')
nProcFn = numel(scan.loops(1).procfn);
else
nProcFn = 0;
end
for opInd = 1:numel(a.procfn_ops) % count through operations
inchan = nGetChan + a.procfn_ops{opInd}{4};
scan.loops(1).procfn(end+1).fn(1) = struct( ...
'fn', a.procfn_ops{opInd}{1}, ...
'args', {a.procfn_ops{opInd}{2}}, ...
'inchan', inchan, ...
'outchan', nProcFn + opInd ...
);
scan.loops(1).procfn(end).dim = a.procfn_ops{opInd}{3};
if numel(a.procfn_ops{opInd}) >= 5
scan.loops(1).procfn(end).identifier = a.procfn_ops{opInd}{5};
end
end

% Configure display
Expand All @@ -246,18 +276,27 @@
scan.disp(end+1).loop = 1;
scan.disp(end).channel = nGetChan + a.disp_ops(l);
scan.disp(end).dim = d;
scan.disp(end).title = prepare_title(sprintf(['%s: '], a.operations{1+mod(l-1, nOperations)}{:}));

if a.disp_ops(l) <= nOperations
opInd = a.disp_ops(l)
else
opInd = a.procfn_ops{a.disp_ops(l)-nOperations}{4};
end

if opInd <= numel(a.operations)
scan.disp(end).title = prepare_title(sprintf(['%s: '], a.operations{opInd}{:}));
elseif length(a.procfn_ops{opInd - nOperations}) > 4
scan.disp(end).title = prepare_title(sprintf(['%s: '], a.procfn_ops{opInd - nOperations}{5}));
else
scan.disp(end).title = '';
end
end
end

if a.saveloop > 0
scan.saveloop = [1, a.saveloop];
end

% Add polarization
if a.dnp
warning('DNP currently not implemented, but basically need to add postfn/prefn which arms a different program w/o measurements and thus w/o Alazar reconfiguration');
end
end


Expand All @@ -267,4 +306,8 @@
str = strrep(str, '_', ' ');
str = str(1:end-2);

str = strrep(str, 'RepAverage', 'RSA');
str = strrep(str, 'Downsample', 'DS');
str = strrep(str, 'Qubit', 'Q');

end
19 changes: 14 additions & 5 deletions MATLAB/+qc/daq_operations.m
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@
else
daq.register_operations(a.program_name, qc.operations_to_python(a.operations));
msg = sprintf('Operations for program ''%s'' added', a.program_name);
qc.workaround_alazar_single_buffer_acquisition();
% qc.workaround_alazar_single_buffer_acquisition();
end
bool = true;

Expand All @@ -52,14 +52,23 @@
% Operations need to have been added beforehand
masks = util.py.py2mat(py.getattr(daq, '_registered_programs'));
masks = util.py.py2mat(masks.(a.program_name));
operations = masks.operations;
operations = masks.operations;
masks = util.py.py2mat(masks.masks);

maskIdsFromOperations = cellfun(@(x)(char(x.maskID)), util.py.py2mat(operations), 'UniformOutput', false);
maskIdsFromMasks = cellfun(@(x)(char(x.identifier)), util.py.py2mat(masks), 'UniformOutput', false);

output = [];
for k = 1:numel(masks)
for k = 1:length(operations)
maskIndex = find( cellfun(@(x)(strcmp(x, maskIdsFromOperations{k})), maskIdsFromMasks) );
if numel(maskIndex) ~= 1
error('Found several masks with same identifier. Might be a problem in qctoolkit or in this function.');
end

if isa(operations{k}, 'py.atsaverage._atsaverage_release.ComputeDownsampleDefinition')
output(k) = util.py.py2mat(size(masks{k}.length));
output(k) = util.py.py2mat(size(masks{maskIndex}.length));
elseif isa(operations{k}, 'py.atsaverage._atsaverage_release.ComputeRepAverageDefinition')
n = util.py.py2mat(masks{k}.length.to_ndarray);
n = util.py.py2mat(masks{maskIndex}.length.to_ndarray);
if any(n ~= n(1))
error('daq_operations assumes that all masks should have the same length if using ComputeRepAverageDefinition.');
end
Expand Down

0 comments on commit d1c618e

Please sign in to comment.