Skip to content

Commit 60eabb3

Browse files
committed
Merge branch 'dev'
2 parents 7ac0c4e + 6cbf5a9 commit 60eabb3

File tree

4 files changed

+249
-0
lines changed

4 files changed

+249
-0
lines changed
Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
function data = acquireAnalogWaveform
2+
% Acquire analog waveform on an NI DAQ. Can be used to debug timing during tile scans.
3+
%
4+
% function data = acquireAnalogWaveform
5+
%
6+
% Purpose
7+
% This function is a bit rough and ready but should do the job. You will need to change
8+
% the DAQ name and maybe channel for your purposes. Copy file to a different location to
9+
% do this. If you edit in place in the BakingTray path, then you will need to revert
10+
% changes if you pull the latest version from GitHub.
11+
%
12+
% This function comes from the 'vidrio' AI examples at https://github.com/SWC-Advanced-Microscopy/MATLAB_DAQmx_examples
13+
% This code will NOT work with a vDAQ
14+
%
15+
%
16+
% Inputs
17+
% None -- please read through and edit the code to ensure you understand how it works
18+
%
19+
% Outputs
20+
% data -- vector data values from the desired AI line.
21+
%
22+
%
23+
% Rob Campbell - SWC, 2024
24+
25+
26+
27+
%Define a cleanup function
28+
tidyUp = onCleanup(@cleanUpFunction);
29+
30+
%% Parameters for the acquisition (device and channels)
31+
devName = 'resscan'; % the name of the DAQ device as shown in MAX
32+
taskName = 'hardAI'; % A string that will provide a label for the task
33+
physicalChannels = 0; % A scalar or an array with the channel numbers
34+
35+
36+
37+
% Task configuration
38+
sampleRate = 1E3; % Sample Rate in Hz (1 kHz is plenty for most purposes)
39+
secsToAcquire = 10; % Number of seconds over which to acquire data
40+
41+
42+
try
43+
% Create a DAQmx task
44+
hTask = dabs.ni.daqmx.Task(taskName);
45+
46+
47+
% Set up analog input on device defined by variable devName
48+
hTask.createAIVoltageChan(devName,physicalChannels,[],-10,10);
49+
50+
51+
% Configure the sampling rate and the number of samples
52+
numberOfSamples = secsToAcquire * sampleRate; % The finite number of samples to acquire
53+
hTask.cfgSampClkTiming(sampleRate,'DAQmx_Val_FiniteSamps',numberOfSamples,'OnboardClock');
54+
55+
56+
%We configured no triggers, so the acquisition starts as soon as hTask.start is run
57+
58+
59+
% Start the task and plot the data
60+
hTask.start % start the acquisition
61+
62+
fprintf('Acquiring data...')
63+
hTask.waitUntilTaskDone; % wait till all requested samples are acquired
64+
fprintf('\n')
65+
66+
% "Scaled" sets the input to be represented as a voltage value.
67+
% "Native" would have it be a raw integer (e.g. 16 bit number if this is a 16 bit DAQ)
68+
data = hTask.readAnalogData([],'scaled',0); % read all available data
69+
70+
catch ME
71+
daqDemosHelpers.errorDisplay(ME)
72+
return
73+
74+
end %try/catch
75+
76+
77+
% - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
78+
function cleanUpFunction
79+
%This runs when the function ends
80+
if exist('hTask','var')
81+
fprintf('Cleaning up DAQ task\n');
82+
hTask.stop; % Calls DAQmxStopTask
83+
delete(hTask); % The destructor (dabs.ni.daqmx.Task.delete) calls DAQmxClearTask
84+
else
85+
fprintf('No task variable present for clean up\n')
86+
end
87+
end %close cleanUpFunction
88+
89+
end
90+
91+
92+
93+
94+
95+
96+
97+
98+
99+
100+
101+
102+
103+
104+
105+
106+
107+
108+
109+
110+
111+
112+
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
# Stage Motion Times
2+
3+
This folder contains code related to timing stage motions.
4+
This can be used for debugging if you are concerned that your stages are moving too slowly, not enough time is being allocated to allowing them to settle, etc.
5+
6+
## Before starting
7+
8+
Before running any code related to stage timing you should quit and restart MATLAB.
9+
On a minority of rigs it has been observed that, over time, MATLAB/ScanImage/BakingTray, begins to slow down by factor of 2 or 3 and restarting MATLAB solves this.
10+
11+
For more accurate values you should have the stages assembled as an X/Y pair and a water bath filled to the typical level placed on top.
12+
13+
It is also a good idea with PI stages to first test how long it takes for a step and settle motion in PI MikroMove.
14+
You can generate graphs showing things like position over time, position error over time, etc.
15+
This provides a really solid baseline indicating what to expect.
16+
17+
Once you are ready: start BakingTray at the MATLAB command line.
18+
19+
20+
21+
## Quick test of stage motion times
22+
Run `softwareTimedMotionTime.m` then make plots of the resulting output.
23+
Read through the code before running the function!
24+
You can edit variables in-line to change behavior.
25+
It is recommended to copy file to a new location to do this, otherwise you will have to revert changes before pulling the latest version of BakingTray when you want to update.
26+
27+
## Checking motion times in a tile scan
28+
You can start a tile scan in BakingTray without having to turn on the laser, the PMTs, make a directory, etc.
29+
To do this:
30+
31+
1. Open the Prepare Sample window
32+
2. Open the Preview window
33+
3. Hit "ROI" and draw a box in the area you want to tile scan
34+
4. Select "tiled: manual ROI" under "Scan Mode" in the main BakingTray window
35+
5. run `hBT.scanner.armScanner` to set up ScanImage for the tile scan
36+
6. run `hBT.runTileScan` to initiate and run the tile scan. You might need to press "Abort" in ScanImage to do more tile scans or disarm the scanner (below).
37+
7. run `hBT.scanner.disarmScanner` after the tile scan is finished and if you plan to do no more.
38+
39+
You can, for example, acquire the Y galvo signal to see how long it takes for each stage motion to complete.
40+
You might want to set the number of Z planes to 1 for this.
41+
The easiest way to decrease the step size of the stages should you need to, is to increase the zoom number in ScanImage.
42+
43+
44+
## Acquiring data from a tile scan
45+
The `sitools.ai_recorder` class can be used to pull in data from an AI line while ScanImage runs.
46+
Clone from https://github.com/BaselLaserMouse/ScanImageTools and read the docs.
47+
It should be compatible with both the vDAQ and an NI DAQ.
48+
T the Y galvo waveform into an AI line that is free and set up the AI recorder to acquire this.
49+
You can either edit the class file, or instantiate the class and modify properties at the CLI.
50+
To save data, check the Save checkbox in ScanImage and choose a directory to which data are to be saved.
51+
Then run the tile scan as above.
52+
The recorder will keep saving data to disk until you hit Abort in ScanImage.
53+
You can use `readAIrecoderBinFile` to read data for analysis;
54+
55+
You can find the interval between frames using MATLAB's findpeaks function:
56+
```matlab
57+
findpeaks(yData) % check visually if it looks right
58+
[pks,loc]=findpeaks(yData);
59+
plot(lok,pks,'.')
60+
%Then apply a threshold and get the times. e.g.
61+
timesOfPeaks = loc(pks>0);
62+
63+
% Divide by the sample rate to get time in seconds
64+
timesInSec = timesOfPeaks / 1000; % in this case data were acquired at 1kHz
65+
plot(diff(peakTimes))
66+
67+
```
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
function out = softwareTimedMotionTime
2+
% Perform a bunch of blocking relative motions in X and Y and see how long they take
3+
%
4+
% Inputs
5+
% none
6+
%
7+
% Outputs
8+
% A structure containing motion times in seconds
9+
%
10+
% Rob Campbell - SWC, 2024
11+
12+
hBT = BakingTray.getObject;
13+
14+
moveBySize = 1;
15+
nMotions = 100;
16+
17+
xTimes = zeros(1,nMotions);
18+
19+
fprintf('Doing X motions')
20+
for ii=1:nMotions
21+
tic
22+
hBT.moveXYby(moveBySize,0,true);
23+
moveBySize = moveBySize*-1; % so next mostion is the other way
24+
xTimes(ii)=toc;
25+
26+
27+
if mod(ii,2) == 0
28+
fprintf('.')
29+
end
30+
31+
pause(0.5); % Because in practice we never rock and back forth with no delay
32+
end
33+
34+
fprintf('\n')
35+
36+
out.xMotionTimes = xTimes;
37+
38+
39+
40+
41+
yTimes = zeros(1,nMotions);
42+
43+
fprintf('Doing Y motions')
44+
for ii=1:nMotions
45+
tic
46+
hBT.moveXYby(0,moveBySize,true);
47+
moveBySize = moveBySize*-1; % so next mostion is the other way
48+
yTimes(ii)=toc;
49+
50+
if mod(ii,2) == 0
51+
fprintf('.')
52+
end
53+
54+
pause(0.5); % Because in practice we never rock and back forth with no delay
55+
end
56+
57+
fprintf('\n')
58+
59+
60+
61+
% Build output structure
62+
out.xMotionTimes = xTimes;
63+
out.yMotionTimes = yTimes;
64+
65+
66+
67+
68+
69+
70+
888 Bytes
Binary file not shown.

0 commit comments

Comments
 (0)