aboutsummaryrefslogtreecommitdiff
path: root/acquisition
diff options
context:
space:
mode:
authorBlaise Thompson <blaise@untzag.com>2018-04-15 19:43:48 -0500
committerBlaise Thompson <blaise@untzag.com>2018-04-15 19:43:48 -0500
commit37989608b63fdbc4d555a51b6135dea5a3555975 (patch)
treec0310d3427dd1bc81a0fb798792821a79b6fb770 /acquisition
parent14bc9be2a66cba11f88c87a3aebc93d142b19743 (diff)
2018-04-15 19:43
Diffstat (limited to 'acquisition')
-rw-r--r--acquisition/chapter.tex148
1 files changed, 74 insertions, 74 deletions
diff --git a/acquisition/chapter.tex b/acquisition/chapter.tex
index a7d434e..7f6d43f 100644
--- a/acquisition/chapter.tex
+++ b/acquisition/chapter.tex
@@ -26,7 +26,7 @@ the context of an MR-CMDS experiment. %
A scan in MR-CMDS typically means sending hardware to a whole series of different positions. %
As an example, a three-dimensional ``movie'' might be collected in the following way:
-\begin{codefragment}{python, label=aqn:lst:psuedoaqn}
+\begin{codefragment}{python, label=acq:lst:psuedoaqn}
w1_points = [14300, 14400, 14500, 14600, 14700] # wn
w2_points = [14100, 14200, 14300, 14400, 14500, 14600, 14700] # wn
d2_points = [100, 75, 50, 25, 0, 50, 75, 100, 125, 150, 175, 200] # fs
@@ -61,37 +61,37 @@ In this chapter I describe how I built such an acquisition software, PyCMDS. %
For context, some description of the acquisition software that PyCMDS replaced is warranted. %
On the ``ps table'' (focus on mixed vibrational-electronic spectroscopy of molecular systems),
-PyCMDS replaces `ps\_control', an older acquisition software first developed in [YEAR] by Kent
-Meyer [CITE]. %
-ps\_control was very-much not modular, designed by generations of graduate students to get to
+PyCMDS replaces `ps\_control', an older acquisition software first developed prior to 2004 by Kent
+Meyer \cite{MeyerKentA2004b}. %
+ps\_control was very-much not modular, designed by generations of graduate students each getting to
``minimum viable'' as quickly as possible. %
When I joined the group, ps\_control had become unsustainable. %
The ps table was being revamped with new hardware, and the old motherboard finally died, so new
software was desperately needed. %
On the ``fs table'' (focus on semiconductor photophysics), PyCMDS replaces `Control for Lots of
-Research in Spectroscopy' (COLORS), developed by Schuyler Kain [CITE]. %
+Research in Spectroscopy' (COLORS), developed by Schuyler Kain \cite{KainSchuyler2017a}. %
PyCMDS is, in many ways, inspired by COLORS. %
Kain's design was modular in many ways. %
Still, there were fundamental problems that COLORS could not address. %
Chief among them was Kain's approach to the National Instruments DAQ card, which did not allow for
-the flexibility required to introduce more interesting chopping schemes [SECTION]. %
+the flexibility required to introduce more interesting chopping schemes (see
+\autoref{act:sec:chop}). %
PyCMDS is a unified software for controlling hardware and collecting data in the Wright Group. %
-It is written almost entirely in Python, with a graphical user interface (GUI) made using Qt
-[CITE]. %
+It is written almost entirely in Python, with a graphical user interface (GUI) made using Qt. %
It is cross-platform, with a core capable of running on Linux, Windows and macOS. %
-It is open source, developed on GitHub. [CITE (GITHUB, PyCMDS)] %
+It is open source, developed on GitHub. \cite{GitHub} %
Today PyCMDS is used to drive both the ps and fs tables. %
PyCMDS is best thought of as a core program with three kinds of modular ``plugins'' that can be
extended as needed. %
The three plugin kinds are
\begin{ditemize}
- \item Hardware: things that can be set to a position (\autoref{aqn:sec:hardware}).
- \item Sensors: things that can be used to measure a signal (\autoref{aqn:sec:sensors}).
+ \item Hardware: things that can be set to a position (\autoref{acq:sec:hardware}).
+ \item Sensors: things that can be used to measure a signal (\autoref{acq:sec:sensors}).
\item Acquisition modules: things that can be used to define and carry out an acquisition, and
- associated post-processing (\autoref{aqn:sec:somatic}).
+ associated post-processing (\autoref{acq:sec:somatic}).
\end{ditemize}
The first design rule for PyCMDS is that these three things should be easy for the average
(motivated) user to add by herself. %
@@ -131,10 +131,10 @@ I have borrowed the terms ``autonomic'' and ``somatic'':
\dsignature{W. J\"{a}nig, Autonomic Nervous System (1989) \cite{JanigW1989a}}
\end{dquote}
-Within PyCMDS, the autonomic system [SECTION] handles the ``reflex'' motion that is part of active
-correction. %
-The somatic system [SECTION], on the other hand, handles the ``voluntary'' motion in the context of
-acquiring a multidimensional scan. %
+Within PyCMDS, the autonomic system (\autoref{acq:sec:autonomic}) handles the ``reflex'' motion
+that is part of active correction. %
+The somatic system (\autoref{acq:sec:somatic}), on the other hand, handles the ``voluntary'' motion
+in the context of acquiring a multidimensional scan. %
% BJT: consider a layout preview paragraph or two
@@ -146,7 +146,7 @@ experienced by a first time user of the software. %
When PyCMDS starts up, the GUI is constructed out of modules depending on which hardware and
sensors the user has instructed the program to address. %
A screenshot of the PyCMDS GUI, running on the fs table, is shown in
-\autoref{aqn:fig:pycmds_screenshot}. %
+\autoref{acq:fig:pycmds_screenshot}. %
On the left hand there is a single column displaying the current positions for all loaded
hardware. %
@@ -156,7 +156,7 @@ display. %
Each hardware knows its own limits, displayed in a tool tip when hovering over the control. %
Users cannot type values outside of hardware limits into the controls. %
Each hardware also has an ``ADVANCED'' button, which takes the user to a more extensive GUI to
-control lots more features [SECTION]. %
+control lots more features (\autoref{acq:sec:hardware}). %
At the very top, on the left hand side, is the ``SHUT DOWN'' button. %
On the right hand side there is a extensive set of nested tabs. %
@@ -164,11 +164,11 @@ The top level tabs are ``Program'', ``Hardware'', ``Devices'', ``Autonomic'', ``
``Plot''. %
Under each of these tabs is an entire separate set of display and control elements. %
Some of these elements are themselves tabbed, like the ``Somatic'' tab (active in
-\autoref{aqn:fig:pycmds_screenshot}), which has ``Queue'' and ``Scan'' sub-tabs. %
+\autoref{acq:fig:pycmds_screenshot}), which has ``Queue'' and ``Scan'' sub-tabs. %
At the top of the right hand side there is a progress bar and queue status display, which I will
discuss further in future sections. %
-When PyCMDS opens (\autoref{aqn:fig:pycmds_screenshot}), the user is first greeted with the
+When PyCMDS opens (\autoref{acq:fig:pycmds_screenshot}), the user is first greeted with the
``Somatic/Queue'' tab on the right hand side of the GUI. %
This is where she may instruct PyCMDS to do acquisitions. %
In PyCMDS, all acquisitions are done in a queue system. %
@@ -179,14 +179,15 @@ To instruct PyCMDS to do an acquisition, the user must first create a queue by e
name (default is ``queue''), and pressing the ``MAKE NEW QUEUE'' button. %
Alternatively the user may open an existing queue using ``OPEN QUEUE''. %
Next, the user must add the desired acquisition(s) to the queue. %
-There are several acquisition modules, each with a different purpose [SECTION]. %
+There are several acquisition modules, each with a different purpose
+(\autoref{acq:sec:somatic}). %
Choose an acquisition module using the drop down menu. %
Enter a name for your acquisition, and any additional info that you might want to keep track of. %
Finally, fill out any additional information that acquisition module might require, and press
``APPEND TO QUEUE''. %
Once there are acquisitions in the queue, the user can press ``RUN QUEUE''. %
-\autoref{aqn:fig:pycmds_queue_screenshot} is a screenshot of the ``Somatic/Queue'' tab while a
+\autoref{acq:fig:pycmds_queue_screenshot} is a screenshot of the ``Somatic/Queue'' tab while a
queue is in progress. %
In this screen shot there are seven enqueued items, and PyCMDS is in the process of acquiring the
final one (index 6). %
@@ -198,7 +199,7 @@ parameters from that acquisition. %
This is useful when repeating an acquisition with slightly changed parameters, or simply when
inspecting what parameters were used in a given item. %
-\autoref{aqn:fig:pycmds_screenshot_during_scan} is a screenshot of PyCMDS during a representative
+\autoref{acq:fig:pycmds_screenshot_during_scan} is a screenshot of PyCMDS during a representative
acquisition. %
This time, the ``Somatic/Scan'' tab is chosen. %
On the left hand side, we can see that the ``SHUT DOWN'' and ``SET'' buttons are grayed out and
@@ -221,10 +222,11 @@ In this case, the displayed pixel (index 6, 40) took 2.448 seconds to acquire.
The other tabs are for more advanced interactions, and will be discussed further in future
sections. %
The ``Program'' tab contains various rarely-needed displays and inputs to configure PyCMDS. %
-The ``Hardware'' tab is where the advanced menu for each hardware appears [SECTION]. %
-The ``Devices'' tab is where sensor settings live [SECTION]. %
+The ``Hardware'' tab is where the advanced menu for each hardware appears
+(\autoref{acq:sec:hardware}). %
+The ``Devices'' tab is where sensor settings live (\autoref{acq:sec:sensors}). %
The ``Autonomic'' tab is where users configure the autonomic system for active correction
-[SECTION]. %
+(\autoref{acq:sec:autonomic}). %
The ``Somatic'' tab has already been described in this section. %
Finally, the ``Plot'' tab was intended to be a interactive, graphical post processing
environment. %
@@ -236,7 +238,7 @@ This functionality has not yet been implemented. %
\caption[PyCMDS at startup.]{
PyCMDS at startup, on the fs system. %
}
- \label{aqn:fig:pycmds_screenshot}
+ \label{acq:fig:pycmds_screenshot}
\end{figure}
\end{landscape}
@@ -246,7 +248,7 @@ This functionality has not yet been implemented. %
\caption[PyCMDS queue.]{
PyCMDS queue while acquiring data, on the ps system. %
}
- \label{aqn:fig:pycmds_queue_screenshot}
+ \label{acq:fig:pycmds_queue_screenshot}
\end{figure}
\end{landscape}
@@ -256,7 +258,7 @@ This functionality has not yet been implemented. %
\caption[PyCMDS while scanning.]{
PyCMDS scan tab while acquiring data, on the ps system. %
}
- \label{aqn:fig:pycmds_screenshot_during_scan}
+ \label{acq:fig:pycmds_screenshot_during_scan}
\end{figure}
\end{landscape}
@@ -449,8 +451,8 @@ All hardware and driver classes are children of the same parent \python{Hardware
These parent classes know how to communicate in a thread safe way, and they know the specific
attributes (like \python{name}), and signals (like \python{update_ui}) that all hardware and
sensors must have. %
-\autoref{aqn:fig:parent_hardware_class} shows the parent hardware class, and
-\autoref{aqn:fig:parent_driver_class} shows the parent driver class. %
+\autoref{acq:fig:parent_hardware_class} shows the parent hardware class, and
+\autoref{acq:fig:parent_driver_class} shows the parent driver class. %
Communication between the hardware and the driver goes via a queue, as mentioned previously. %
The hardware class has an attribute \python{q}, which is an instance of the \python{Q} class. %
@@ -469,7 +471,7 @@ driver can trigger signals like \python{update_ui} and modify Mutexes. %
For brevity, methods \python{close}, \python{update} and \python{wait_until_still} have been
omitted. %
}
- \label{aqn:fig:parent_hardware_class}
+ \label{acq:fig:parent_hardware_class}
\end{figure}
\begin{figure}
@@ -477,7 +479,7 @@ driver can trigger signals like \python{update_ui} and modify Mutexes. %
\caption[TODO]{
Parent class of all drivers. %
}
- \label{aqn:fig:parent_driver_class}
+ \label{acq:fig:parent_driver_class}
\end{figure}
\subsubsection{GUI components} % -----------------------------------------------------------------
@@ -547,12 +549,12 @@ For those wanting to learn more, all GUI components are defined in
\bash{PyCMDS/project/widgets.py}. %
\clearpage
-\section{Hardware} \label{aqn:sec:hardware} % ====================================================
+\section{Hardware} \label{acq:sec:hardware} % ====================================================
Hardware are things that 1. have a position, and 2. can be set to a destination. %
Typically they also have associated units and limits. %
They sometimes have an offset, as specified by the autonomic system
-(\autoref{aqn:sec:autonomic}). %
+(\autoref{acq:sec:autonomic}). %
Each hardware can be thought of as a dimension of the MR-CMDS experiment, and scans include a
specific traversal through this multidimensional space. %
@@ -561,9 +563,9 @@ In this section I briefly discuss PyCMDS' implementation for each type of hardwa
\subsection{Hardware inheritance} % --------------------------------------------------------------
All hardware classes are children of the parent \python{Hardware} class
-(\autoref{aqn:fig:hardware_class}), which is itself a child of the the global \python{Hardware}
-class shown in \autoref{aqn:fig:parent_hardware_class}. %
-By inspecting \autoref{aqn:fig:hardware_class}, we can see that all hardware require the following
+(\autoref{acq:fig:hardware_class}), which is itself a child of the the global \python{Hardware}
+class shown in \autoref{acq:fig:parent_hardware_class}. %
+By inspecting \autoref{acq:fig:hardware_class}, we can see that all hardware require the following
methods:
\begin{ditemize}
\item \python{close}
@@ -576,7 +578,7 @@ methods:
\item \python{@property units}
\end{ditemize}
-\autoref{aqn:fig:hardware_inheritance} shows the full inheritance tree, including all nine types of
+\autoref{acq:fig:hardware_inheritance} shows the full inheritance tree, including all nine types of
hardware currently supported by PyCMDS. %
In general the nesting is type/model, although there can be additional levels of nesting when
required, as can be seen in the case of OPA/TOPAS/TOPAS-C and OPA/TOPAS/TOPAS-800. %
@@ -597,7 +599,7 @@ Each of these classes can be directly instantiated as a minimum-viable instance,
\python{is_valid}, \python{on_address_initialized}, \python{poll}, and \python{@property units}
have been omitted. %
}
- \label{aqn:fig:hardware_class}
+ \label{acq:fig:hardware_class}
\end{figure}
\begin{figure}
@@ -605,7 +607,7 @@ Each of these classes can be directly instantiated as a minimum-viable instance,
\caption[Hardware inheritance.]{
CAPTION TODO
}
- \label{aqn:fig:hardware_inheritance}
+ \label{acq:fig:hardware_inheritance}
\end{figure}
\subsection{Delays} % ----------------------------------------------------------------------------
@@ -630,8 +632,8 @@ The delay GUI, by default, offers
\item \python{on_set_motor}
\item \python{on_set_zero}
\end{ditemize}
-\autoref{aqn:fig:delay_advanced} is a screenshot of the advanced panel for one of the Newport MFA
-[CITE] delay stages. %
+\autoref{acq:fig:delay_advanced} is a screenshot of the advanced panel for one of the Newport MFA
+\cite{MFA} delay stages. %
This advanced panel is pretty typical. %
Users may directly set the motor position or zero position. %
They may also change the label. % BJT: because...
@@ -645,7 +647,7 @@ can also account for double-passes and similar configurations. %
\caption[Representative delay stage advanced menu.]{
Advanced menu for one of the MFA-CC (SMC-100) delay stages, on the fs system. %
}
- \label{aqn:fig:delay_advanced}
+ \label{acq:fig:delay_advanced}
\end{figure}
\end{landscape}
@@ -665,7 +667,7 @@ Spectrometer driver instances require the following:
\item \python{set_turret}
\end{ditemize}
-\autoref{aqn:fig:spectrometer_advanced} is a screenshot of the MicroHR [CITE] advanced menu on the
+\autoref{acq:fig:spectrometer_advanced} is a screenshot of the MicroHR advanced menu on the
fs system. %
Nothing can be changed in the advanced menu except the label, and the offset can be seen. %
@@ -675,7 +677,7 @@ Nothing can be changed in the advanced menu except the label, and the offset can
\caption[Representative spectrometer advanced menu.]{
CAPTION TODO
}
- \label{aqn:fig:spectrometer_advanced}
+ \label{acq:fig:spectrometer_advanced}
\end{figure}
\end{landscape}
@@ -716,8 +718,8 @@ Many of these additional features have to do with the tuning curve, a crucial fe
The tuning curve contains motor positions needed to achieve each valid output color. %
Read more about my implementation of tuning curves in \autoref{cha:opa}. %
-\autoref{aqn:fig:opa_advanced} is a screenshot of the advanced menu for one of the TOPAS-C [CITE]
-OPAs on the fs table. %
+\autoref{acq:fig:opa_advanced} is a screenshot of the advanced menu for one of the TOPAS-C OPAs on
+the fs table. %
A large central plot displays the currently loaded tuning curve for one of the motors (chosen in
the pull down menu). %
Multiple filepath menus allow the user to specify each tuning curve. %
@@ -729,12 +731,11 @@ Each motor can be independently set and homed. %
\caption[Representative OPA advanced menu.]{
CAPTION TODO
}
- \label{aqn:fig:opa_advanced}
+ \label{acq:fig:opa_advanced}
\end{figure}
\end{landscape}
-\clearpage
-\section{Sensors (devices)} \label{aqn:sec:sensors} % ============================================
+\section{Sensors (devices)} \label{acq:sec:sensors} % ============================================
Sensors are the kind of things that actually measure data. %
In spectroscopy these can be photodiodes, array detectors, photo-multiplier tubes etc. %
@@ -743,12 +744,12 @@ In this section I describe the strategy that PyCMDS uses to represent sensors.
\subsection{The DAQ card} % ----------------------------------------------------------------------
The National Instruments PCI-6251 card is capable of eight analog inputs and 1 million samples per
-second (one sample per microsecond). %
+second (one sample per microsecond). \cite{PCI6251} %
Both instruments operate at 1 KHz, so that leaves 1000 samples per shot. %
It is important to be able to configure all of the timings within each shot. %
-\autoref{aqn:fig:samples} shows the GUI designed to control the sample level timing of the NI
-PCI-6251 card. %
+\autoref{acq:fig:samples} shows the GUI designed to control the sample level timing of the NI
+PCI-6251 card \cite{PCI6251}. %
All 1000 samples for the current shot are displayed in the large central plot. %
Users may allocate regions of samples to be assigned to particular channels. %
A second region may be allocated for explicit baseline subtraction. %
@@ -758,11 +759,11 @@ subtracted and the signal is (optionally) inverted. %
All of this results in a single processed value for each channel on each shot. %
Users may also allocate exactly one sample for chopper monitoring. %
-\autoref{aqn:fig:shots} is a screenshot of the shots GUI. %
+\autoref{acq:fig:shots} is a screenshot of the shots GUI. %
Only one channel is shown, chosen by the pull down menu on the right hand side. %
Each point is one processed value from all of the samples designated for that particular shot. %
Because this instrument is using dual chopping at this time, only one out of four shots has a large
-amount of light, so most shots are near zero in \autoref{aqn:fig:shots}. %
+amount of light, so most shots are near zero in \autoref{acq:fig:shots}. %
[SHOTS PROCESSING]
@@ -775,7 +776,7 @@ amount of light, so most shots are near zero in \autoref{aqn:fig:shots}. %
\caption{
CAPTION TODO
}
- \label{aqn:fig:samples}
+ \label{acq:fig:samples}
\end{figure}
\end{landscape}
@@ -785,7 +786,7 @@ amount of light, so most shots are near zero in \autoref{aqn:fig:shots}. %
\caption{
CAPTION TODO
}
- \label{aqn:fig:shots}
+ \label{acq:fig:shots}
\end{figure}
\end{landscape}
@@ -802,14 +803,14 @@ Sometimes, a sensor returns an entire array of information. %
In cases like these, PyCMDS expands the dimensionality of the scan to accommodate the many-valued
sensor. %
-For example, consider \autoref{aqn:fig:array_as_axis}. %
+For example, consider \autoref{acq:fig:array_as_axis}. %
This simple tune test was taken with an array detector, rather than using a scanning
monochromator. %
Although only one piece of hardware was scanned, the data is considered to be
\emph{two}-dimensional, with the second dimension being $\bar{\nu}_a$, the differential color axis
for the array vs the OPA setpoint. %
-The data in \autoref{aqn:fig:array_as_axis} does not occupy a rectangular region in this
+The data in \autoref{acq:fig:array_as_axis} does not occupy a rectangular region in this
parameterization. %
This is because the range of colors covered at each monochromator setpoint is different, with a
smaller dispersion (more colors across the finite array) at higher energies. %
@@ -822,10 +823,10 @@ It has been derived previously by \textcite{KainSchuyler2017a}. %
\caption[Array detector serving as an axis.]{
CAPTION TODO (2017-11-06 OPA2)
}
- \label{aqn:fig:array_as_axis}
+ \label{acq:fig:array_as_axis}
\end{figure}
-\section{Autonomic} \label{aqn:sec:autonomic} % ==================================================
+\section{Autonomic} \label{acq:sec:autonomic} % ==================================================
The autonomic system is used to define ``reflexes'' for PyCMDS---operations that are automatically
applied when certain conditions are met. %
@@ -844,7 +845,7 @@ means that PyCMDS is prepared for corrections that have not yet been fully imple
automated power correction. %
Simple plain-text \bash{.coset} files define the offset arrays. %
-They are automatically generated using processing scripts in \python{attune} [CITE]. %
+They are automatically generated using processing scripts in \python{attune}. %
Their headers prevent them from being loaded in the wrong spot. %
These files are internally represented as instances of the \python{CoSet} class, which is capable
of linear interpolation and extrapolation at the edges. %
@@ -861,10 +862,9 @@ In such cases, \emph{offsets always add}. %
\end{figure}
\end{landscape}
-\clearpage
-\section{Somatic} \label{aqn:sec:somatic} % =======================================================
+\section{Somatic} \label{acq:sec:somatic} % =======================================================
-In contrast with the autonomic system (\autoref{aqn:sec:autonomic}), the somatic system is all
+In contrast with the autonomic system (\autoref{acq:sec:autonomic}), the somatic system is all
about voluntary, user specified motion. %
This is where the fun stuff happens---the acquisitions!
@@ -931,8 +931,8 @@ This object has the same shape as the full multidimensional scan, and contains t
that hardware for that pixel in the scan. %
Then, a \bash{.data} file is created to accept the data that is about to be collected. %
A bunch of signals go off, telling PyCMDS that it needs to yield to somatic control. %
-Then PyCMDS simply sits in a loop generated by \python{numpy.ndindex} [CITE] and visits each pixel
-in turn. %
+Then PyCMDS simply sits in a loop generated by \python{numpy.ndindex} \cite{ndindex} and visits
+each pixel in turn. %
\python{ndindex} is a n-dimensional iterator over a given array shape. %
Written simply, it does the following:
\begin{codefragment}{python}
@@ -962,7 +962,7 @@ So that when evaluated:
This simple algorithm is used to visit each pixel in the entire PyCMDS scan space. %
At each pixel, something much like the following happens. %
-\begin{codefragment}{python, label=aqn:lst:loop_simple}
+\begin{codefragment}{python, label=acq:lst:loop_simple}
for idx in ndindex(shape):
for hardware in hardwares::
hardware.set(idx)
@@ -980,14 +980,14 @@ The simplicity of this central loop truly shows the power of abstraction in PyCM
Acquisition modules are defined interfaces which know how to assemble a scan. %
-\autoref{aqn:fig:aqn_file} shows an aqn file for an acquisition using SCAN. %
+\autoref{acq:fig:aqn_file} shows an aqn file for an acquisition using SCAN. %
\begin{figure}
\includebash{"acquisition/example.aqn"}
\caption[Example aqn file.]{
CAPTION TODO
}
- \label{aqn:fig:aqn_file}
+ \label{acq:fig:aqn_file}
\end{figure}
\subsubsection{SCAN}
@@ -998,7 +998,7 @@ SCAN is capable of acquisitions of arbitrary dimensionality. %
Users simply append as many axes as they want. %
Acquistions are done with the trailing (highest index) axis as the innermost loop. %
Arbitrary expressions (PyCMDS calls them ``constants'') are also possible, as can be seen in
-\autoref{aqn:fig:aqn_file}. %
+\autoref{acq:fig:aqn_file}. %
\subsubsection{TUNE TEST}
@@ -1072,7 +1072,7 @@ because indeed that is all that can be generalized. %
\caption[TODO]{
TODO
}
- \label{aqn:fig:slack}
+ \label{acq:fig:slack}
\end{figure}
\section{Future directions} % ====================================================================
@@ -1202,7 +1202,7 @@ S_n &=& (1-c)\left(\frac{n}{N}\right)^{\frac{\tau_{\mathrm{step}}}{\tau_{\mathrm
\begin{figure}
\includegraphics[scale=0.5]{"processing/PyCMDS/ideal axis positions/exponential"}
\caption[TODO]{TODO}
- \label{aqn:fig:exponential_steps}
+ \label{acq:fig:exponential_steps}
\end{figure}
\subsubsection{Gaussian}