Skip to content
Snippets Groups Projects
Commit 6c35dddb authored by whuie2's avatar whuie2
Browse files

first

parent 2214f601
No related branches found
No related tags found
No related merge requests found
Comments_Adam.png

22.4 KiB

# AWG control
Files to control the AWG, ultimately for the creation of tweezers.
File added
%% Define awg structure and init
if ~exist('awg_trap', 'var') || ~isfield(awg_trap, 'running') || ~awg_trap.running
awg_trap = struct();
awg_trap.active_channels = [1, 1, 0, 0];
% Here you set which channels of the AWG you are using.
% Note that the only available options are 1, 1+2, 1+2+3+4
awg_trap.chAmp = [2500, 1320, 2500, 2500];
% mVp. Max possible 2500mVp, min 80mVp.
awg_trap.samplerate = 614.4e6;
% Maximum of 625e6, must be multiple of 512
awg_trap.numMemBlocks = 8192;
% Must be power of 2. In general, for the maximum array size
% you want to rearrange with BubbleSort, N, this should be at least N*(N+2).
% If not using BubbleSort just set to maybe 32.
awg_trap.freq_resolution = 100e3;
% GCD of trap frequencies. If you make an array with a different
% frequency resolution, then it might fail because when the waveform
% tries to loop there will be a phase jump (which kills the atoms)
awg_trap.memSamples = 512 * 240;
% Define memory in number of samples.
% First factor must be 512. Other factor must be an even integer multiple of
% the sampling rate / (freq_resolution * 512) , such that
% the total memSamples < 2^31/numMemBlocks/numActiveChannels.
% 2^31 comes from the total AWG memory limit. Note that the
% requirements here are again to avoid phase jumps.
awg_trap.running = false;
else
fprintf('To change these parameters you must turn the AWG off first!\n');
end
%% Init
[awg_trap, success] = initTrapAWG(wfms, awg_trap);
if success
awg_trap.running = true;
end
if awg_trap.cardInfo.serialNumber ~= 11198
% When using a system with multiple AWGs, sometimes the internal awg
% indexing gets switched around when the computer restarts - to avoid
% outputting the wrong signal to the wrong card, we make sure we are
% talking to the correct serial number.
fprintf('Talking to serial number %i', awg_trap.cardInfo.serialNumber);
disp('This is the wrong card! Turn it off immediately and diagnose!');
end
%% Update
if awg_trap.running
awg_trap = updateTrapAWG(wfms, awg_trap);
if isfield(wfms, 'name')
fprintf('Updating to %s\n', wfms.name);
else
fprintf('Updating to unnamed wfms\n');
end
else
fprintf('AWG must be running to update!\n');
end
%% Stop
% Look out, because oftentimes if a bug happens with the AWG initialization
% or termination it will hard crash MATLAB. The "running" variable tries to
% help this, but is not perfect.
if awg_trap.running
stopTrapAWG(awg_trap);
awg_trap.running = false;
else
fprintf('AWG is already off!\n');
end
%% Generate naive waveforms
% Schematic for how to generate an array of tweezers for two crossed AODs.
wfms = struct();
% Ch 0 (Old AOD)
numTweezers_0 = 67;
f0_0 = 98.2e6;
df_0 = 750e3;
ampScaling_0 = 0.25; % DO NOT EXCEED 0.25 when chAmp(1) = 2500mVp.
wfms.ch0 = staticArrayWfm(numTweezers_0, f0_0, df_0, ampScaling_0);
% Ch 1 (New AOD)
numTweezers_1 = 1;
f0_1 = 97e6;
df_1 = 10 * 350e3;
ampScaling_1 = 0.25; % DO NOT EXCEED 0.25 when chAmp(2) = 1320mVp.
wfms.ch1 = staticArrayWfm(numTweezers_1, f0_1, df_1, ampScaling_1);
wfms.name = sprintf('wfms_%d_%0.0f_%d_%0.0f_%s', numTweezers_0, df_0 / 1e3, numTweezers_1, df_1 / 1e3, '000');
%% Check current AWG step
% There are lots of "GetParam_i32" calls which are very useful. See the
% manual and programming guide for more information. For instance, this
% call returns the current block of memory the AWG is outputting.
[~,currentStep] = spcm_dwGetParam_i32(awg_trap.cardInfo.hDrv, mRegs('SPC_SEQMODE_STATUS'));
fprintf('AWG is currently on step %d\n',currentStep);
%% Identify the card
% This will make a little light blink on the back of the card, useful when
% working with multiple AWGs
mRegs = spcMCreateRegMap();
error = spcm_dwSetParam_i32(awg_trap.cardInfo.hDrv, mRegs('SPC_CARDIDENTIFICATION'), 0);
function [awg_trap, success] = initTrapAWG(wfms, awg_trap)
success = false;
%Set AWG parameters
samplerate = awg_trap.samplerate;
chAmp = awg_trap.chAmp;
memSamples = awg_trap.memSamples;
% helper maps to use label names for registers and errors
mRegs = spcMCreateRegMap();
mErrors = spcMCreateErrorMap();
% ----- init card and store infos in cardInfo struct -----
% This is the place where the AWG internal indexing can sometimes get
% messed up if you have multiple AWGs and the computer restarts
[success, cardInfo] = spcMInitCardByIdx(1);
if success
% ----- print info about the board -----
cardInfoText = spcMPrintCardInfo(cardInfo);
fprintf(cardInfoText);
else
spcMErrorMessageStdOut(cardInfo, 'Error: Could not open card\n', true);
return;
end
% ----- set the samplerate and internal PLL, no clock output -----
[success, cardInfo] = spcMSetupClockPLL(cardInfo, samplerate, 0); % clock output : enable = 1, disable = 0
if ~success
spcMErrorMessageStdOut(cardInfo, 'Error: spcMSetupClockPLL:\n\t', true);
return;
end
fprintf ('\n ..... Sampling rate set to %.1f MHz\n', cardInfo.setSamplerate / 1e6);
% Here are some examples of different triggering methods, either
% software triggering or hardware triggering with 4V activation
% ----- set software trigger, no trigger output -----
% [success, cardInfo] = spcMSetupTrigSoftware (cardInfo, 0); % trigger output : enable = 1, disable = 0
% if ~success
% spcMErrorMessageStdOut (cardInfo, 'Error: spcMSetupTrigSoftware:\n\t', true);
% return;
% end
%%%%%%%%%
% ----- extMode = risingEdge, trigTerm = 0, pulseWidth = 0, singleSrc = 1, extLine = 0 -----
% [success, cardInfo] = spcMSetupTrigExternal (cardInfo, mRegs('SPC_TM_POS'), 0, 0, 1, 0);
% if ~success
% spcMErrorMessageStdOut (cardInfo, 'Error: spcMSetupExternal:\n\t', true);
% return;
% end
% [success, cardInfo] = spcMSetupTrigExternalLevel (cardInfo, mRegs('SPC_TM_POS'), 4000, 0, 0, 0, 0, 1, 0);
% if ~success
% spcMErrorMessageStdOut (cardInfo, 'Error: spcMSetupExternal:\n\t', true);
% return;
% end
%%%%%%%%%
% ----- program all output channels with no offset and no filter -----
for ii = 0:(cardInfo.maxChannels-1)
[success, cardInfo] = spcMSetupAnalogOutputChannel(cardInfo, ii, chAmp(ii + 1), 0, 0, mRegs('SPCM_STOPLVL_ZERO'), 0, 0); % doubleOut = disabled, differential = disabled
if ~success
spcMErrorMessageStdOut(cardInfo, 'Error: spcMSetupInputChannel:\n\t', true);
return;
end
end
% Divide memory in segments
% ----- setup sequence mode, 1 channel, numMemBlocks segments, start segment 0 -----
[success, cardInfo] = spcMSetupModeRepSequence(cardInfo, 0, bi2de(awg_trap.active_channels), awg_trap.numMemBlocks, 0);
if ~success
spcMErrorMessageStdOut(cardInfo, 'Error: spcMSetupModeRepSequence:\n\t', true);
return;
end
firstStep = 0;
changeStep = 1;
firstSeg = 0;
% create signal
signals = [];
overPowerFlag = false;
awg_trap.cardInfo = cardInfo;
for ind = 1:cardInfo.maxChannels
if awg_trap.active_channels(ind)
wfm = wfms.(sprintf('ch%i', ind - 1));
signal = staticArraySignal(wfm, awg_trap);
else
signal = zeros(1, memSamples);
end
signals = [signals; signal];
end
signal_zero = zeros(1,memSamples);
%Step 1 - Set segments
% ----- set segment 0 -----
error = spcm_dwSetParam_i32(cardInfo.hDrv, mRegs('SPC_SEQMODE_WRITESEGMENT'), firstSeg);
error = spcm_dwSetParam_i32(cardInfo.hDrv, mRegs('SPC_SEQMODE_SEGMENTSIZE'), memSamples);
errorCode = spcm_dwSetData(cardInfo.hDrv, 0, memSamples, numel(awg_trap.active_channels), 0, ...
signals(1, :), signals(2, :), signals(3, :), signals(4, :));
% ----- set segment 1 -----
error = spcm_dwSetParam_i32(cardInfo.hDrv, mRegs('SPC_SEQMODE_WRITESEGMENT'), 1);
error = spcm_dwSetParam_i32(cardInfo.hDrv, mRegs('SPC_SEQMODE_SEGMENTSIZE'), memSamples);
errorCode = spcm_dwSetData (cardInfo.hDrv, 0, memSamples, numel(awg_trap.active_channels), 0, ...
signal_zero, signals(2, :), signals(3, :), signals(4, :));
% Step 2 - Set sequence steps
% step, nextStep, segment, loops, condition (0 => End loop always, 1 => End loop on trigger, 2 => End sequence)
% Understanding how the sequencereplay works on the AWG is crucial to
% understanding how to effectively program it. See the manual.
spcMSetupSequenceStep(cardInfo, firstStep, changeStep, firstSeg, 1, 1);
spcMSetupSequenceStep(cardInfo, changeStep, firstStep, firstSeg, 1, 0);
% Honestly for this next part, it is always a bit of trial and error. I
% am sure there is a better way to do this though... I've left some
% things which we don't actually use (like the commandMask syntax) in
% in case it is useful.
% ----- define series of commands -----
% commandMask = mRegs('M2CMD_CARD_START');
% commandMask = bitor (mRegs('M2CMD_CARD_START'), mRegs('M2CMD_CARD_ENABLETRIGGER'));
% commandMask = bitor (commandMask, mRegs('M2CMD_CARD_WAITREADY'));
% ----- set series of command -----
errorCode = spcm_dwSetParam_i32(cardInfo.hDrv, mRegs('SPC_M2CMD'), mRegs('M2CMD_CARD_START'));
errorCode = spcm_dwSetParam_i32(cardInfo.hDrv, mRegs('SPC_M2CMD'), mRegs('M2CMD_CARD_ENABLETRIGGER'));
if (errorCode ~= 0)
[~, cardInfo] = spcMCheckSetError(errorCode, cardInfo);
if errorCode == mErrors('ERR_TIMEOUT')
error = spcm_dwSetParam_i32(cardInfo.hDrv, mRegs('SPC_M2CMD'), mRegs('M2CMD_CARD_STOP'));
fprintf (' OK\n ................... replay stopped\n');
else
spcMErrorMessageStdOut(cardInfo, 'Error: spcm_dwSetParam_i32:\n\t', true);
return;
end
end
errorCode = spcm_dwSetParam_i32(awg_trap.cardInfo.hDrv, mRegs('SPC_M2CMD'), mRegs('M2CMD_CARD_FORCETRIGGER'));
awg_trap.cardInfo = cardInfo;
success = true;
end
function [signal] = staticArraySignal(wfm, awg_trap, memSamples)
%STATICARRAYSIGNAL Summary of this function goes here
% Detailed explanation goes here
if ~exist('memSamples', 'var')
memSamples = awg_trap.memSamples;
end
samplerate = awg_trap.samplerate;
t = (1:memSamples) / samplerate;
signal = sum(wfm.amp' .* (sin(2 * pi * wfm.freq' * t + wfm.phase')), 1);
numTweezers = length(wfm.freq);
scale = 2^15 - 1;
ampMax = scale / sqrt(numTweezers);
signal = ampMax * signal;
if max(abs(signal)) > 2^15
signal(signal > 2^15) = 2^15;
signal(signal < -2^15) = -2^15;
warnStruct = warning(); warning('on'); warning('Waveform goes above digital limit, signal will be clipped!'); warning(warnStruct);
end
end
function [wfm] = staticArrayWfm(numTweezers, f0, df, ampScaling)
%STATICARRAYWFM Summary of this function goes here
% Detailed explanation goes here
% Pretty sure this only works for odd numbers of arrays right now, but
% simple to make it work for even as well
wfm = struct();
wfm.amp = ampScaling * ones(1, numTweezers);
wfm.freq = f0 + df * ((1:numTweezers) - numTweezers / 2 - 1 / 2);
wfm.freq = wfm.freq;
% This is basically just a random guess of the phases. Ultimately you
% want to optimize the phases by minimizing mixing into sum and
% difference fourier modes, so this really is just a first
% approximation that kinda works.
phaseStruct = load('arrayPhase.mat');
phase = phaseStruct.arrayPhase;
if length(phase) < length(wfm.freq)
phase = repmat(phase, [1, 2]);
end
% disp('setting phases to 0!')
wfm.phase = phase(1:length(wfm.freq));
end
function stopTrapAWG(awg_trap)
% If you try and "stop" when the card wasn't actually running it will
% hard crash MATLAB
% helper maps to use label names for registers
mRegs = spcMCreateRegMap();
error = spcm_dwSetParam_i32(awg_trap.cardInfo.hDrv, mRegs('SPC_M2CMD'), mRegs('M2CMD_CARD_STOP'));
fprintf(' ...................... replay done\n');
% ***** close card *****
spcMCloseCard(awg_trap.cardInfo);
disp('AWG stopped');
end
\ No newline at end of file
function [awg_trap, success] = updateTrapAWG(wfms, awg_trap)
cardInfo = awg_trap.cardInfo;
memSamples = awg_trap.memSamples;
% helper maps to use label names for registers
mRegs = spcMCreateRegMap();
%Get currentStep
[~, currentStep] = spcm_dwGetParam_i32 (cardInfo.hDrv, 349950); % 349950 = SPC_SEQMODE_STATS
if currentStep ~= 0
fprintf('Current step in memory is not 0! Some things might go wrong!\n')
end
% compute signal
signals = [];
overPowerFlag = false;
for ind = 1:cardInfo.maxChannels
if awg_trap.active_channels(ind)
wfm = wfms.(sprintf('ch%i', ind - 1));
signal = staticArraySignal(wfm, awg_trap);
else
signal = zeros(1, memSamples);
end
signals = [signals; signal];
end
%Update the current step
default_memory_segment = 0;
error = spcm_dwSetParam_i32(cardInfo.hDrv, mRegs('SPC_SEQMODE_WRITESEGMENT'), default_memory_segment);
error = spcm_dwSetParam_i32(cardInfo.hDrv, mRegs('SPC_SEQMODE_SEGMENTSIZE'), memSamples);
errorCode = spcm_dwSetData(cardInfo.hDrv, 0, memSamples, numel(awg_trap.active_channels),...
0, signals(1, :), signals(2, :), signals(3, :), signals(4, :));
spcMSetupSequenceStep(cardInfo, currentStep, currentStep + 1, 0, 1, 0);
spcMSetupSequenceStep(cardInfo, currentStep + 1, 0, default_memory_segment, 1, 0);
spcMSetupSequenceStep(cardInfo, 0, 1, default_memory_segment, 1, 1);
awg_trap.cardInfo = cardInfo;
if ~overPowerFlag
success = true;
else
success = false;
end
end
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment