aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBlaise Thompson <blaise@untzag.com>2018-03-30 13:54:43 -0500
committerBlaise Thompson <blaise@untzag.com>2018-03-30 13:54:43 -0500
commit9d8496be4cf2719c3dd7ca2a4b4de91ad4abeeb3 (patch)
treef52b56e26397336eb28ad0093c829327915332e0
parent9185c93d9e2034bdaae4f49a592fba9251f5f9f4 (diff)
2018-03-30 13:54
-rw-r--r--acquisition/chapter.tex153
-rw-r--r--acquisition/hardware_inheritance1
-rw-r--r--active_correction/chapter.tex39
-rw-r--r--dissertation.tex8
-rw-r--r--opa/autotune_preamp.pngbin0 -> 353762 bytes
-rw-r--r--opa/c2.pngbin0 -> 411523 bytes
-rw-r--r--opa/chapter.tex141
-rw-r--r--opa/curve.pngbin0 -> 149957 bytes
-rw-r--r--opa/d2.pngbin0 -> 168710 bytes
-rw-r--r--opa/figures.py369
-rw-r--r--opa/frequency domain examples.pngbin0 -> 179493 bytes
-rw-r--r--opa/introduction.pngbin0 -> 358658 bytes
-rw-r--r--opa/poweramp flowchart.pngbin0 -> 90565 bytes
-rw-r--r--opa/poweramp.pngbin0 -> 676481 bytes
-rw-r--r--opa/preamp flowchart.pngbin0 -> 52647 bytes
-rw-r--r--opa/preamp.pngbin0 -> 569491 bytes
-rw-r--r--opa/ranges.pngbin0 -> 75168 bytes
-rw-r--r--opa/reproducability.pngbin0 -> 223442 bytes
-rw-r--r--opa/signal_and_idler_motortune.pngbin0 -> 131292 bytes
19 files changed, 672 insertions, 39 deletions
diff --git a/acquisition/chapter.tex b/acquisition/chapter.tex
index 832e698..bd08edd 100644
--- a/acquisition/chapter.tex
+++ b/acquisition/chapter.tex
@@ -9,28 +9,99 @@
\clearpage
-In the Wright Group, \gls{PyCMDS} replaces the old acquisition softwares `ps control', written by
-Kent Meyer and `Control for Lots of Research in Spectroscopy' written by Schuyler Kain.
-
-PyCMDS directly addresses the hardware during experiments.
+MR-CMDS relies on a good number of instrumental capabilities. %
+Fundamentally, MR-CMDS is about delivering multiple pulses of light to a given sample. %
+The frequency and relative arrival time (delay) of each pulse must be scanned in the context of a
+basic multidimensional experiment. %
+Scanning frequency requires using motors to change crystal angles and other optics within Optical
+Parametric Amplifiers (OPAs). %
+Scanning delay typically involves moving mirrors very small distances such that the optical path
+length of certain beam-lines changes. %
+In addition to these ``first-order'' controls, the power of MR-CMDS is enhanced with additional
+control of pulse intensity and polarization. % TODO: citations to motivate this 'enhancement'
+Each of these is an optomechanical device. %
+An automated monchromator is typically used to spectrally resolve or isolate output signal. %
+
+An acquisition in MR-CMDS typically means going 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}
+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
+for w2 in w2_points:
+ set_w2(w2)
+ for w1 in w1_points:
+ set_w1(w1)
+ for d2 in d2_points:
+ set_d2(d2)
+ measure_signal()
+\end{codefragment}
+In this simple example, there are 5 \python{w1} destinations, 7 \phon{w2} destinations, and 12
+\python{d2} destinations, so there are a total of $5\times7\times12=420$ pixels in the
+three-dimensional scan. %
+The acquisition software must set the hardware to each of these points and acquire data at each of
+them. %
+Each hardware motion and signal measurement takes roughly one second, so this acquisition would
+take roughly 7 minutes to complete. %
+In practice, real scans are composed of $\sim$100 to $\sim$100,000 pixels, and take between 1
+minute and one day to acquire. %
+
+Because of the highly specialized nature of these experiments, MR-CMDS instruments typically
+require custom software to address all of simultaneous, repeated motor motion that a scan
+requires. %
+Because MR-CMDS is really a family of techniques which require different kinds of motor motion,
+this acqusition software should be flexable enough to meet the creativity of its users. %
+Furthermore, because MR-CMDS is a bleeding edge, rapidly evolving technique the instrumental
+software must be built in an extendable way to accommodate the ever-changing hardware
+configurations. %
+In this chapter I describe how I built such an acquisition software. %
\section{Overview} % =============================================================================
-PyCMDS has, through software improvements alone, dramatically lessened scan times...
+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. %
+It is cross-platform, running on Linux, Windows and macOS. %
+It is open source, developed on GitHub. % TODO: cite PyCMDS on github
+PyCMDS is used to drive both of the MR-CMDS instruments maintained by the Wright Group: the ``fs
+table'', focused on semiconductor photophysics, and the ``ps table'', focused on molecular
+systems. %
+In the Wright Group, \gls{PyCMDS} replaces the old acquisition softwares `ps control', ritten by
+Kent Meyer and `Control for Lots of Research in Spectroscopy' written by Schuyler Kain.
-\begin{ditemize}
- \item simultaneous motor motion
- \item digital signal processing % TODO: reference section when it exists
- \item ideal axis positions \ref{acq:sec:ideal_axis_positions}
-\end{ditemize}
+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}. %
+On the left hand there is a single column displaying the current positions for all loaded
+hardware. %
+Users may enter new destinations and hit the ``SET'' button. %
+Positions have units, which are changeable through the pull-down menu next to the control and
+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. %
+
+The large right-hand section is tabbed...
-% TODO: screenshot
+\begin{figure}
+ \caption{
+ TODO (PyCMDS screenshot, including limits in tool tip)
+ }
+ \label{aqn:fig:pycmds_screenshot}
+\end{figure}
-% TODO: modularity
+To perform an acquisition, a user goes to the SOMATIC tab and enters an item into the QUEUE...
-% TODO: n-dimensional scans...
+During the acquisition...
+Progress bar...
+Cannot hit SET...
+QUEUE states...
-% TODO: calibration
+\begin{figure}
+ \caption{
+ TODO (PyCMDS screenshot while acquiring a 2D delay scan)
+ }
+ \label{aqn:fig:pycmds_screenshot_during_scan}
+\end{figure}
\section{Structure} % ============================================================================
@@ -124,8 +195,56 @@ Note that multithreading is very different from multiprocessing. %
\subsection{High level objects} % ----------------------------------------------------------------
-PyCMDS is made to be extended and developed by and for immature programmers, so it is crucial to
-create something that is less complicated...
+Towards the goal of stability and extensability, PyCMDS makes heavy use of abstraction and
+inheritance. %
+
+Abstraction means that complex implementation details are hidden by simple interfaces. %
+For example, consider the simple case of setting an OPA to a particular color. %
+For OPAs in the Wright Group, this operation requires the following:
+\begin{ditemize}
+ \item Load the OPA tuning curve, find which motors must move.
+ \item Interpolate the discrete tuning curve, and evaluate that interpolated curve at the desired
+ destination.
+ \item Send each motor towards their new destination.
+ \item Wait for the motors to arrive, check that nothing has gone wrong.
+\end{ditemize}
+This is not even to mention the complexity of spawning and sending information between the main
+thread and working threads. %
+Through abstraction, PyCMDS is able to wrap all this complexity into the \python{OPA} class and
+it's \python{set_position} method---so doing all of the operations above is as simple as
+\python{opa.set_position(1300, 'nm')}. %
+Importantly, abstraction does not magically get rid of the complexity. %
+It simply \emph{hides} the complexity so that it becomes tractable to write simple interfaces to
+accomplish complex things. %
+
+PyCMDS implements abstraction through inheritance. %
+In object oriented programming, inheritance is when one class is based on another. %
+The \emph{child} class acquires all of the properties of the \emph{parent} class. %
+The child class, then, can modify or extend the properties that it needs, without needing to
+re-implement the properties that it shares with the parent. %
+Let's consider PyCMDS hardware again. %
+Every single unique hardware in PyCMDS lives in it's own worker thread, so the basic problem of
+information transfer through queues and Mutexes is shared between them. %
+A \python{Hardware} class which is parent to \emph{all} hardwares can define the methods and
+attributes necessary to abstract this basic thread communication issue. %
+Every type of delay stage addressed by PyCMDS needs to handle the basic task of translating between
+``natural'' units (femtosecond, picosecond, nanosecond) and ``native'' units (typically mm). %
+They all need an attribute \python{zero_position}, in native units, and a method to do the
+conversion. %
+A class common to all delay stages can abstract away all of these conversion details. %
+In summary, an inheritance-based system for implementing delay stages might look like this:
+\begin{codefragment}{bash}
+Hardware # implements basic thread control
+└── Delay # implements conversion between natural and native units
+ ├── Homemade
+ ├── Thorlabs
+ └── Newport
+\end{codefragment}
+The powerful thing about this strategy is that the three driver-specific classes (...) need only
+implement minimal driver-specific code, typically start, set close...
+This means that code is more maintainable and less buggy...
+Easier to change high-level behavior without redoing low-level code...
+Only implemented once...
At it's most basic PyCMDS defines the following simple data types (derived from
\python{PyCMDS_object}):
@@ -336,6 +455,8 @@ For DAQ cards, shots and samples...
Power of digital processing...
+Old boxcar: 300 ns window, ~10 micosecond delay. Onset of saturation ~2 V.
+
% TODO: screenshots
\subsection{Sensors as axes} % -------------------------------------------------------------------
diff --git a/acquisition/hardware_inheritance b/acquisition/hardware_inheritance
index 0a13a1b..3504a8c 100644
--- a/acquisition/hardware_inheritance
+++ b/acquisition/hardware_inheritance
@@ -3,7 +3,6 @@ Hardware
│ ├── Aerotech
│ ├── LTS300
│ ├── MFA
-│ ├── MFA
│ └── PMC
├── Filter
│ └── Homebuilt
diff --git a/active_correction/chapter.tex b/active_correction/chapter.tex
index ee20859..ef19f40 100644
--- a/active_correction/chapter.tex
+++ b/active_correction/chapter.tex
@@ -18,23 +18,36 @@
\clearpage
-\section{Hardware} % -----------------------------------------------------------------------------
+\section{Introduction} % =========================================================================
-\subsection{Delay Stages}
+MR-CMDS is subject to a number of possible artifacts, many of them stemming from the imperfect
+nature of the frequency-tunable light sources we currently have. %
+It is self-evidently desirable to correct these artifacts, when possible. %
+Indeed many of these artifacts, such as OPA power, phase mismatch and absorption effects have
+regularly been corrected for. % TODO: link to examples in applications section
+These corrections are applied after measurement, typically including information from other sources
+(such as absorption spectra, in the case of absorption effect corrections).
-% TODO: discuss _all 3_ delay configurations.... implications for sign conventions etc
+A more interesting class of corrections are ``active'' corrections---that is, corrections that must
+be actively applied during acquisition and cannot be applied in post processing. %
+These corrections are more insidious, and they are often neglected because the hardware and/or
+software does not allow for them. %
-\section{Signal Acquisition}
+In this chapter I explore some of these active correction strategies that are useful in the context
+of MR-CMDS. %
+Some of these strategies have already been implemented, others are partially implemented, and
+others are still just ideas. %
+I hope to show that active correction is a particularly useful strategy in MR-CMDS. %
-Old boxcar: 300 ns window, ~10 micosecond delay. Onset of saturation ~2 V.
+\section{Spectral delay correction} % ============================================================
-\subsection{Digital Signal Processing}
+\section{Poynting correction} % ==================================================================
-% TODO:
+\section{Excitation power correction} % ==========================================================
-\section{Artifacts and Noise} % ------------------------------------------------------------------
+\section{Chopping} % =============================================================================
-\subsection{Scatter}
+\subsection{Scatter} % ---------------------------------------------------------------------------
Scatter is a complex microscopic process whereby light traveling through a material elastically
changes its propagation direction. %
@@ -270,10 +283,6 @@ Now, substituting in BRAZARD formalism:
\frac{<D_{PR}>D}{D_{PR}}}{<PR><PU>}
\end{equation}
-\section{Light Generation} % ---------------------------------------------------------------------
+\section{Fibrillation} % =========================================================================
-\subsection{Automated OPA Tuning}
-
-\section{Optomechanics} % ------------------------------------------------------------------------
-
-\subsection{Automated Neutral Density Wheels}
+\section{Conclusions} % ========================================================================== \ No newline at end of file
diff --git a/dissertation.tex b/dissertation.tex
index 5d6d456..30290b0 100644
--- a/dissertation.tex
+++ b/dissertation.tex
@@ -67,12 +67,12 @@ This dissertation is approved by the following members of the Final Oral Committ
% chapters ----------------------------------------------------------------------------------------
-%\include{introduction/chapter}
+\include{introduction/chapter}
\part{Background}
-%\include{spectroscopy/chapter}
-%\include{materials/chapter}
-%\include{software/chapter}
+\include{spectroscopy/chapter}
+\include{materials/chapter}
+\include{software/chapter}
\part{Development}
\include{processing/chapter}
diff --git a/opa/autotune_preamp.png b/opa/autotune_preamp.png
new file mode 100644
index 0000000..570d4fb
--- /dev/null
+++ b/opa/autotune_preamp.png
Binary files differ
diff --git a/opa/c2.png b/opa/c2.png
new file mode 100644
index 0000000..a546d44
--- /dev/null
+++ b/opa/c2.png
Binary files differ
diff --git a/opa/chapter.tex b/opa/chapter.tex
index b92f62a..75459b5 100644
--- a/opa/chapter.tex
+++ b/opa/chapter.tex
@@ -1,4 +1,7 @@
-\chapter{A robust, fully automated algorithm to collect high quality OPA tuning curves}
+% TODO: DONALDSON HAS AUTOMATED OPA TUNING DOWN?
+
+\chapter{A robust, fully automated algorithm to collect high quality OPA tuning
+ curves} \label{cha:opa}
\begin{dquote}
Principle design features of the new EVV 2DIR optical delivery system include the following:
@@ -13,6 +16,138 @@
\clearpage
-This chapter pasted from publication...
+In frequency-domain Multi-Resonant Coherent Multidimensional Spectroscopy (MR-CMDS), automated
+Optical Parametric Amplifiers (OPAs) are used to actively scan excitation color axes. %
+To accomplish these experiments, exquisite OPA performance is required. %
+During the experiment, motors inside the OPA move to pre-recorded positions to optimize output at
+the desired color. %
+Parametric conversion (``mixing'') strategies are now readily avalible, extending the 800 nm pumped
+OPA tuning range into the visible, near-infrared, and mid-infrared. %
+
+OPAs are very sensitive to changes in upstream lasers and lab conditions, so OPA tuning is
+regularly required. %
+Manual OPA tuning can easily take a full day. %
+Automated OPA tuning makes OPA upkeep easier, faster and more reproducible, facilitating frequency
+domain experiments. %
+The major challenges in automated OPA tuning are:
+\begin{enumerate}
+ \item Expensive to take high resoltion data.
+ \item Need smooth curves for interpolation, especially at edges where output is low.
+ \item Optimization metrics are not necessarily separable along motor dimensions.
+\end{enumerate}
+
+\section{Introduction} % =========================================================================
+
+\section{TOPAS-C} % ==============================================================================
+
+% TODO: introduction to the internal design of the OPA
+
+\section{Preamp} % ===============================================================================
+
+\begin{figure}
+ \includegraphics[width=\textwidth]{opa/preamp}
+ \caption{
+ CAPTION TODO
+ }
+ \label{opa:fig:preamp}
+\end{figure}
+
+In TOPAS-C OPAs, a small portion of input light is used to generate a signal seed in a BBO crystal
+``C1''. %
+A motorized delay stage ``D1'' is used to temporally overlap a particular color in chirped white
+light with 800 nm pump. %
+C1 angle is tuned to optimize phase matching. %
+Measured seed intensity and color for all combinations of C1 and D1 position are shown in
+\autoref{fig:preamp}. %
+
+Output color and intensity are not separable along the preamp motor axes. %
+We therefore use a multidimensional fitting strategy to find the best preamp motor positions, as
+shown below. %
+
+% TODO: procedure
+
+\begin{figure}
+ \includegraphics[width=\linewidth]{opa/autotune_preamp}
+ \caption{
+ CAPTION TODO
+ }
+ \label{opa:fig:autotune_preamp}
+\end{figure}
+
+A representative preamp tune procedure output image is shown in \autoref{fig:autotune_preamp}. %
+The thick black line is the final output curve. %
+The dark grey lines are the contours of constant color. %
+The colorbar shows the Delaunay-interpolated intensity values for each motor position. %
+
+Preamp tuning takes less than 20 minutes, in large part due to a NIR array detector which collects
+the full spectrum at each motor position. %
+
+\section{Poweramp} % =============================================================================
+
+\begin{figure}
+ \includegraphics[width=\linewidth]{opa/poweramp}
+ \caption{
+ CAPTION TODO
+ }
+ \label{opa:fig:poweramp}
+\end{figure}
+
+Once generated, the seed goes on to be amplified in a second BBO crystal ``C2'' with the rest of
+the 800 nm pump. %
+Optimizing this amplification step is primarily a matter of setting C2 angle. %
+A small delay correction ``D2'' is necessary to account for dispersion in the seed optics. %
+To fully explore poweramp behavior, we need to tak a C2-D23 scan for each seed color. %
+Measured output intensity and color in this 3D space is represented in \autoref{fig:poweramp}. %
+Note that the motor axes are scans about the previously recorded tuning curve value. %
+
+The best position (zero displacement along both axes) is chosen to maximize output intensity while
+keeping the output color identical to the seed color. %
+Optimizing for zero detuining rather than simply for output intensity has led to better OPA
+performance and stability. %
+Like in the preamp case, color and intensity are not fully separable along the poweramp motor
+dimensions (this is especially true at the edge output colors). %
+In the poweramp, the increased dimensionaity makes it too expensive to do a full multidimensional
+tuning procedure. %
+Instead we emply an iterative procedure as diagrammed below. %
+
+% TODO: procedure
+
+We always end the iteration(s) with C2 so that the OPA's color calibration is as good as
+possible. %
+Typically only one iteration is required but multiple iterations may be necessary if dramatic OPA
+realignment has occurred. %
+In total, poweramp tuning typically takes less than 1 hour. %
+Representative procedure output images for D2 (\autoref{op:fig:d2}) and C2 (\autoref{opa:fig:c2})
+are shown. %
+
+\begin{figure}
+ \includegraphics[width=\textwidth]{opa/d2}
+ \caption{
+ CAPTION TODO
+ }
+ \label{opa:fig:d2}
+\end{figure}
+
+\begin{figure}
+ \includegraphics[width=\textwidth]{opa/c2}}
+ \caption{
+ CAPTION TODO
+ }
+ \label{opa:fig:c2}
+\end{figure}
+
+For the D2 figure, the lower panel shows the intensity of the data taken. %
+Note the thick grey line, which represents the chosen points before the final spline step. %
+The top panel compares the old tuning curve (thin) with the output tuning curve (thick). %
+For the C2 image, the bottom panel represents the color of each fit mapped onto detuning. %
+Each separate marker color represents a different setpoint. %
+As with D2, the C2 upper panel compares the old tuning curve (thin black) with the output tuning
+curve (colored X's). %
+
+\section{Mixers} % ===============================================================================
+
+\section{Generalizability} % =====================================================================
+
+\section{Future directions} % ====================================================================
-% DONALDSON HAS AUTOMATED OPA TUNING DOWN? \ No newline at end of file
+% TODO: discuss Attune \ No newline at end of file
diff --git a/opa/curve.png b/opa/curve.png
new file mode 100644
index 0000000..6290ce0
--- /dev/null
+++ b/opa/curve.png
Binary files differ
diff --git a/opa/d2.png b/opa/d2.png
new file mode 100644
index 0000000..3c1cf87
--- /dev/null
+++ b/opa/d2.png
Binary files differ
diff --git a/opa/figures.py b/opa/figures.py
new file mode 100644
index 0000000..efc8d45
--- /dev/null
+++ b/opa/figures.py
@@ -0,0 +1,369 @@
+### import ####################################################################
+
+
+import os
+import collections
+
+import numpy as np
+
+import matplotlib
+import matplotlib.pyplot as plt
+matplotlib.rcParams['font.size'] = 14
+
+import WrightTools as wt
+import WrightData as wd
+
+
+### define ####################################################################
+
+
+width = 14
+
+gd_path = wt.kit.get_path_matching('Google Drive')
+
+data_path = os.path.join(gd_path, 'Blaise', 'unpublished Thompson - Automated OPA Tuning')
+
+
+### recent examples ###########################################################
+
+
+if False:
+ # prepare figure
+ wf = 0.01
+ cols = ['cbar', 1, 1, 'cbar']
+ aspects = [[[0, 1], 0.5]]
+ fig, gs = wt.artists.create_figure(width=width/2., nrows=2, cols=cols, hspace=0.5, wspace=0.5, aspects=aspects)
+ # dOD colorbar
+ cax = plt.subplot(gs[:, 0])
+ limit = 0.05
+ ticks = np.linspace(-limit, limit, 5)
+ wt.artists.plot_colorbar(cax=cax, cmap='signed', label='dOD', ticklocation='left', ticks=ticks)
+ # example 1 (MoS2 TA)
+ ax = plt.subplot(gs[0, 1])
+ p = os.path.join(gd_path, 'MX2', 'CMDS', '2016.05.26', 'SCAN [w2, wmw1, d2] 2016.05.30 18_17_55 TA', 'SCAN [w2, wmw1, d2] 2016.05.30 18_17_55 TA.data')
+ data = wt.data.from_PyCMDS(p, verbose=False)
+ data = data.chop('w2', 'wmw1', verbose=False)[11]
+ data = data.split('wmw1', 13250, verbose=False)[1]
+ data.smooth(2)
+ data.dOD('dI', 'I')
+ data.dI.clip(-limit, limit)
+ xi = data.axes[1].points
+ yi = data.axes[0].points
+ zi = data.channels[0].values
+ X, Y, Z = wt.artists.pcolor_helper(xi, yi, zi)
+ ax.pcolor(X, Y, Z, vmin=-limit, vmax=limit, cmap=wt.artists.colormaps['signed'])
+ wt.artists.diagonal_line(xi, yi)
+ ax.grid()
+ plt.setp(ax.get_xticklabels(), visible=False)
+ plt.setp(ax.get_yticklabels(), visible=False)
+ ax.set_xlabel('$\\mathsf{\\bar\\nu_{probe}=\\bar\\nu_{m}}$', fontsize=18)
+ ax.set_ylabel('$\\mathsf{\\bar\\nu_{pump}}$', fontsize=18)
+ ax.set_xlim(xi.min(), xi.max())
+ ax.set_ylim(yi.min(), yi.max())
+ # example 2 (MoS2 TrEE)
+ ax = plt.subplot(gs[0, 2])
+ data = wd.get('2015.12 Czech', check_remote=False)['movie']
+ data = data.chop('w1', 'd2')[29]
+ data.transpose()
+ xi = data.axes[1].points
+ yi = data.axes[0].points
+ zi = data.channels[0].values
+ X, Y, Z = wt.artists.pcolor_helper(xi, yi, zi)
+ ax.pcolor(X, Y, Z, cmap=wt.artists.colormaps['default'])
+ ax.grid()
+ ax.axhline(0, c='k', lw=1)
+ ax.axvline(data.w2.points, c='k', lw=4, alpha=0.25)
+ plt.setp(ax.get_xticklabels(), visible=False)
+ plt.setp(ax.get_yticklabels(), visible=False)
+ ax.set_xlabel('$\\mathsf{\\bar\\nu_{1}=\\bar\\nu_{m}}$', fontsize=18)
+ ax.set_ylabel('$\\mathsf{\\tau_{21}}$', fontsize=18)
+ ax.set_xlim(xi.min(), xi.max())
+ ax.set_ylim(yi.min(), yi.max())
+ # example 3 (PbSe TrEE)
+ ax = plt.subplot(gs[1, 1])
+ data = wt.data.from_pickle('PbSe.p')
+ data = data.chop('w2', 'w1')[12]
+ xi = data.axes[1].points
+ yi = data.axes[0].points
+ zi = data.channels[0].values
+ zi -= zi.min()
+ zi += 0.001
+ zi /= zi.max()
+ zi **= 0.5
+ X, Y, Z = wt.artists.pcolor_helper(xi, yi, zi)
+ ax.pcolor(X, Y, Z, cmap=wt.artists.colormaps['default'])
+ wt.artists.diagonal_line(xi, yi)
+ ax.grid()
+ plt.setp(ax.get_xticklabels(), visible=False)
+ plt.setp(ax.get_yticklabels(), visible=False)
+ ax.set_xlabel('$\\mathsf{\\bar\\nu_{1}=\\bar\\nu_{m}}$', fontsize=18)
+ ax.set_ylabel('$\\mathsf{\\bar\\nu_{2}}$', fontsize=18)
+ ax.set_xlim(xi.min(), xi.max())
+ ax.set_ylim(yi.min(), yi.max())
+ # example 4 (TRSF)
+ ax = plt.subplot(gs[1, 2])
+ data = wd.get('2013.10 Boyle', check_remote=False)['full 2D TRSF']
+ xi = data.axes[1].points
+ yi = data.axes[0].points
+ zi = data.channels[0].values
+ X, Y, Z = wt.artists.pcolor_helper(xi, yi, zi)
+ ax.pcolor(X, Y, Z, cmap=wt.artists.colormaps['default'])
+ wt.artists.diagonal_line(xi, yi)
+ ax.grid()
+ plt.setp(ax.get_xticklabels(), visible=False)
+ plt.setp(ax.get_yticklabels(), visible=False)
+ ax.set_xlabel('$\\mathsf{\\bar\\nu_{1}}$', fontsize=18)
+ ax.set_ylabel('$\\mathsf{\\bar\\nu_{2}}$', fontsize=18)
+ ax.set_xlim(xi.min(), xi.max())
+ ax.set_ylim(yi.min(), yi.max())
+ # homodyne colorbar
+ cax = plt.subplot(gs[:, -1])
+ wt.artists.plot_colorbar(cax=cax, label='amplitude')
+ # finish
+ plt.savefig('frequency domain examples.png', dpi=300, transparent=True, pad_inches=1)
+ plt.close(fig)
+
+
+### curve #####################################################################
+
+
+if False:
+ # prepare figure
+ fig, gs = wt.artists.create_figure(width=width/2., nrows=2, cols=[1],
+ default_aspect=0.3)
+ # get curve
+ d = os.path.join(gd_path, 'Development', 'OPA tuning', 'tuning records', 'TOPAS-C 10743', 'signal', '2016.05.28', 'OPA1 (10743) curves')
+ curves = [os.path.join(d, 'OPA1 (10743) base - 2016.05.28 12_56_14.crv'),
+ os.path.join(d, 'OPA1 (10743) mixer1 - 2015.11.09'),
+ os.path.join(d, 'OPA1 (10743) mixer2 - 2016.05.15 10_23_48'),
+ os.path.join(d, 'OPA1 (10743) mixer3 - 2013.06.01'),]
+ curve = wt.tuning.curve.from_TOPAS_crvs(curves, 'TOPAS-C', 'NON-NON-NON-Sig')
+ # preamp
+ ax = plt.subplot(gs[0, 0])
+ plt.setp(ax.get_xticklabels(), visible=False)
+ ax.grid()
+ ax.set_xticks([1200, 1400, 1600])
+ # C1
+ ax.scatter(curve.colors, curve.motors[0].positions, c='b', edgecolor='none')
+ ax.plot(curve.colors, curve.motors[0].positions, c='b', lw=2)
+ gone = [0, 7]
+ for i, tl in enumerate(ax.get_yticklabels()):
+ tl.set_color('b')
+ if i in gone:
+ tl.set_visible(False)
+ ax.set_ylabel('C1 (deg)', color='b', fontsize=18)
+ # D1
+ ax = ax.twinx()
+ ax.scatter(curve.colors, curve.motors[1].positions, c='r', edgecolor='none')
+ ax.plot(curve.colors, curve.motors[1].positions, c='r', lw=2)
+ gone = [5]
+ for i, tl in enumerate(ax.get_yticklabels()):
+ tl.set_color('r')
+ if i in gone:
+ tl.set_visible(False)
+ ax.set_ylabel('D1 (mm)', color='r', fontsize=18)
+ # poweramp
+ ax = plt.subplot(gs[1, 0])
+ ax.grid()
+ xi = np.linspace(1100, 1700, 4)
+ ax.set_xlim(xi.min(), xi.max())
+ ax.set_xticks([1200, 1400, 1600])
+ ax.set_xlabel('setpoint (nm)', fontsize=18)
+ # C2
+ ax.scatter(curve.colors, curve.motors[2].positions, c='b', edgecolor='none')
+ ax.plot(curve.colors, curve.motors[2].positions, c='b', lw=2)
+ gone = [0, 9]
+ for i, tl in enumerate(ax.get_yticklabels()):
+ tl.set_color('b')
+ if i in gone:
+ tl.set_visible(False)
+ ax.set_ylabel('C2 (deg)', color='b', fontsize=18)
+ # D2
+ ax = ax.twinx()
+ ax.scatter(curve.colors, curve.motors[3].positions, c='r', edgecolor='none')
+ ax.plot(curve.colors, curve.motors[3].positions, c='r', lw=2)
+ gone = [0, 5]
+ for i, tl in enumerate(ax.get_yticklabels()):
+ tl.set_color('r')
+ if i in gone:
+ tl.set_visible(False)
+ ax.set_ylabel('D2 (deg)', color='r', fontsize=18)
+ yticks = ax.yaxis.get_major_ticks()
+ # finish
+ plt.savefig('curve.png', dpi=300, transparent=True, pad_inches=1)
+ plt.close(fig)
+
+
+### tuning range ##############################################################
+
+
+if False:
+ # prepare figure
+ fig, gs = wt.artists.create_figure(width=width, nrows=1, cols=[1],
+ default_aspect=0.15)
+ # populate
+ ax = plt.subplot(gs[0, 0])
+ cs = ['k', 'grey', 'orange', 'r', 'c', 'm', 'g', 'b', 'k']
+ ranges = collections.OrderedDict()
+ ranges['Idler'] = [2600, 1600]
+ ranges['Signal'] = [1600, 1150]
+ ranges['SHI'] = [800, 1200]
+ ranges['SHS'] = [800, 580]
+ ranges['SFI'] = [600, 533]
+ ranges['SFS'] = [533, 480]
+ ranges['4HI'] = [590, 400]
+ ranges['4HS'] = [400, 290]
+ height = 0
+ for name, limits in ranges.items():
+ ax.plot(limits, [height, height], lw=10, label=name, c=cs[height+1])
+ height += 1
+ labels = [''] + ranges.keys() + ['']
+ [i.set_color(c) for i, c in zip(plt.gca().get_yticklabels(), cs)]
+ ax.set_yticklabels(labels)
+ ax.set_xlim(290, 2000)
+ ax.set_ylim(-1, len(ranges))
+ ax.set_xlabel('OPA output (nm)', fontsize=18)
+ ax.grid()
+ # finish
+ plt.savefig('ranges.png', dpi=300, transparent=True, pad_inches=1)
+ plt.close(fig)
+
+
+### huge preamp ###############################################################
+
+
+if False:
+ # prepare figure
+ fig, gs = wt.artists.create_figure(width=width, nrows=1, hspace=1,
+ cols=[ 1, 'cbar', 0.1, 1, 'cbar'],
+ aspects=[[[0, 0], 1]])
+ # get data
+ p = 'TOPAS_C_full_preamp.p'
+ data = wt.data.from_pickle(p)
+ #data.transpose()
+ # clip based on intensity
+ data.amplitude.clip(zmin=0.1, zmax=5)
+ # clip based on width
+ data.width.clip(zmin=10, zmax=100)
+ # clip based on center
+ data.center.clip(zmin=1140, zmax=1620)
+ # share NaNs
+ data.share_nans()
+ data.heal('center')
+ data.heal('amplitude')
+ # intensity
+ ax = plt.subplot(gs[0, 0])
+ cax = plt.subplot(gs[0, 1])
+ xi = data.c1.points
+ yi = data.d1.points
+ zi = data.amplitude.values
+ zi /= np.nanmax(zi)
+ X, Y, Z = wt.artists.pcolor_helper(xi, yi, zi)
+ cmap=wt.artists.colormaps['default']
+ cmap.set_under([0.75]*3, 1)
+ mappable = ax.pcolor(X, Y, Z, vmin=0, vmax=1, cmap=cmap)
+ plt.colorbar(mappable=mappable, cax=cax, ticklocation='right')
+ cax.set_ylabel('intensity', fontsize=18)
+ ax.set_xlim(xi.min(), xi.max())
+ ax.set_ylim(1.35, 1.8)
+ ax.contour(xi, yi, zi, 5, colors='k')
+ ax.set_xlabel('C1 (deg)', fontsize=18)
+ ax.set_ylabel('D1 (mm)', fontsize=18)
+ ax.grid()
+ # color
+ ax = plt.subplot(gs[0, 3])
+ cax = plt.subplot(gs[0, 4])
+ xi = data.c1.points
+ yi = data.d1.points
+ zi = data.center.values
+ X, Y, Z = wt.artists.pcolor_helper(xi, yi, zi)
+ cmap=wt.artists.colormaps['rainbow']
+ cmap.set_under([0.75]*3, 1)
+ mappable = ax.pcolor(X, Y, Z, vmin=np.nanmin(Z), vmax=np.nanmax(Z), cmap=cmap)
+ plt.colorbar(mappable=mappable, cax=cax)
+ cax.set_ylabel('color (nm)', fontsize=18)
+ ax.set_xlim(xi.min(), xi.max())
+ ax.set_ylim(1.35, 1.8)
+ ax.contour(xi, yi, zi, 25, colors='k')
+ ax.set_xlabel('C1 (deg)', fontsize=18)
+ plt.setp(ax.get_yticklabels(), visible=False)
+ ax.grid()
+ # finish
+ plt.savefig('preamp.png', dpi=300, transparent=True, pad_inches=1)
+ plt.close(fig)
+
+
+### actual preamp #############################################################
+
+
+if False:
+ p = os.path.join(gd_path, 'Development', 'OPA tuning', 'tuning records', 'TOPAS-C 10743', 'signal', '2016.05.14', 'TOPAS-C AUTOTUNE [w1, w1_Delay_1, wa] 2016.05.14 20_25_26', 'TOPAS-C AUTOTUNE [w1, w1_Delay_1, wa] 2016.05.14 20_25_26.data')
+ d = r'C:\Users\blais\Google Drive\Development\OPA tuning\tuning records\TOPAS-C 10743\signal\2016.04.25\OPA1 (10743) curves'
+ curves = [os.path.join(d, 'OPA1 (10743) base - 2016.04.25 22_46_02.crv'),
+ os.path.join(d, 'OPA1 (10743) mixer1 - 2015.11.09'),
+ os.path.join(d, 'OPA1 (10743) mixer2 - 2016.03.22 23_31_12'),
+ os.path.join(d, 'OPA1 (10743) mixer3 - 2013.06.01'),]
+ wt.tuning.TOPAS_C.process_preamp_motortune(1, p, curves, save=True)
+
+
+### huge poweramp #############################################################
+
+
+if False:
+ # prepare figure
+ fig, gs = wt.artists.create_figure(width=width, nrows=1, hspace=1,
+ cols=[ 1, 'cbar', 0.1, 1, 'cbar'],
+ aspects=[[[0, 0], 4/3.]])
+ # get data
+ p = 'TOPAS_C_full_poweramp_moments.p'
+ data = wt.data.from_pickle(p, verbose=False)
+ setpoints = np.linspace(1160, 1600, 12)
+ # clip, share NaNs
+ data.integral.clip(zmin=0.1, zmax=500)
+ data.one.clip(zmin=1140, zmax=1620)
+ # plot method
+ def plot(subplot_spec, cax, channel_index, cmap, yticklabels=False):
+ inner_gs = matplotlib.gridspec.GridSpecFromSubplotSpec(4, 3, subplot_spec=subplot_spec, wspace=0.0, hspace=0.0)
+ # fill in
+ for i, g in enumerate(inner_gs):
+ ax = plt.subplot(g)
+ if not ax.is_last_row():
+ plt.setp(ax.get_xticklabels(), visible=False)
+ if not ax.is_first_col():
+ plt.setp(ax.get_yticklabels(), visible=False)
+ if not yticklabels:
+ plt.setp(ax.get_yticklabels(), visible=False)
+ ax.grid()
+ if i == 10:
+ ax.set_xlabel('$\mathsf{\Delta}$C2 (deg)', fontsize=18)
+ cm = wt.artists.colormaps[cmap]
+ cm.set_under([0.75]*3)
+ setpoint = setpoints[i]
+ d = data.chop('d2', 'c2', {'w1': [setpoint, 'nm']})[0]
+ xi = d.c2.points
+ yi = d.d2.points
+ zi = d.channels[channel_index].values
+ vmin = data.channels[channel_index].min()
+ vmax = data.channels[channel_index].max()
+ X, Y, Z = wt.artists.pcolor_helper(xi, yi, zi)
+ ax.pcolor(X, Y, Z, vmin=vmin, vmax=vmax, cmap=cm)
+ ax.set_xlim(xi.min(), xi.max())
+ ax.set_ylim(yi.min(), yi.max())
+ wt.artists.corner_text(int(setpoint), fontsize=18, background_alpha=0.33)
+ ax.grid()
+ # intensity
+ subplot_spec = gs[0, 0]
+ cax = plt.subplot(gs[0, 1])
+ plot(subplot_spec, cax, 0, 'default', yticklabels=True)
+ wt.artists.plot_colorbar(cax=cax, cmap='default', label='intensity')
+ # color
+ subplot_spec = gs[0, 3]
+ cax = plt.subplot(gs[0, 4])
+ plot(subplot_spec, cax, 1, 'rainbow')
+ ticks = np.linspace(1140, 1620, 9)
+ wt.artists.plot_colorbar(cax=cax, cmap='rainbow', label='color (nm)', ticks=ticks)
+ # y label
+ fig.text(0.01, 0.55, '$\mathsf{\Delta}$D2 (deg)', fontsize=18, rotation=90)
+ # finish
+ plt.savefig('poweramp.png', dpi=300, transparent=True, pad_inches=1)
+ plt.close(fig)
diff --git a/opa/frequency domain examples.png b/opa/frequency domain examples.png
new file mode 100644
index 0000000..c86bb8f
--- /dev/null
+++ b/opa/frequency domain examples.png
Binary files differ
diff --git a/opa/introduction.png b/opa/introduction.png
new file mode 100644
index 0000000..869c073
--- /dev/null
+++ b/opa/introduction.png
Binary files differ
diff --git a/opa/poweramp flowchart.png b/opa/poweramp flowchart.png
new file mode 100644
index 0000000..7ab1dc4
--- /dev/null
+++ b/opa/poweramp flowchart.png
Binary files differ
diff --git a/opa/poweramp.png b/opa/poweramp.png
new file mode 100644
index 0000000..3f0fdb7
--- /dev/null
+++ b/opa/poweramp.png
Binary files differ
diff --git a/opa/preamp flowchart.png b/opa/preamp flowchart.png
new file mode 100644
index 0000000..01b04f1
--- /dev/null
+++ b/opa/preamp flowchart.png
Binary files differ
diff --git a/opa/preamp.png b/opa/preamp.png
new file mode 100644
index 0000000..abf3a24
--- /dev/null
+++ b/opa/preamp.png
Binary files differ
diff --git a/opa/ranges.png b/opa/ranges.png
new file mode 100644
index 0000000..07bbbcb
--- /dev/null
+++ b/opa/ranges.png
Binary files differ
diff --git a/opa/reproducability.png b/opa/reproducability.png
new file mode 100644
index 0000000..83ad67f
--- /dev/null
+++ b/opa/reproducability.png
Binary files differ
diff --git a/opa/signal_and_idler_motortune.png b/opa/signal_and_idler_motortune.png
new file mode 100644
index 0000000..092eb72
--- /dev/null
+++ b/opa/signal_and_idler_motortune.png
Binary files differ