From 9d8496be4cf2719c3dd7ca2a4b4de91ad4abeeb3 Mon Sep 17 00:00:00 2001 From: Blaise Thompson Date: Fri, 30 Mar 2018 13:54:43 -0500 Subject: 2018-03-30 13:54 --- acquisition/chapter.tex | 153 +++++++++++++-- acquisition/hardware_inheritance | 1 - active_correction/chapter.tex | 39 ++-- dissertation.tex | 8 +- opa/autotune_preamp.png | Bin 0 -> 353762 bytes opa/c2.png | Bin 0 -> 411523 bytes opa/chapter.tex | 141 +++++++++++++- opa/curve.png | Bin 0 -> 149957 bytes opa/d2.png | Bin 0 -> 168710 bytes opa/figures.py | 369 +++++++++++++++++++++++++++++++++++++ opa/frequency domain examples.png | Bin 0 -> 179493 bytes opa/introduction.png | Bin 0 -> 358658 bytes opa/poweramp flowchart.png | Bin 0 -> 90565 bytes opa/poweramp.png | Bin 0 -> 676481 bytes opa/preamp flowchart.png | Bin 0 -> 52647 bytes opa/preamp.png | Bin 0 -> 569491 bytes opa/ranges.png | Bin 0 -> 75168 bytes opa/reproducability.png | Bin 0 -> 223442 bytes opa/signal_and_idler_motortune.png | Bin 0 -> 131292 bytes 19 files changed, 672 insertions(+), 39 deletions(-) create mode 100644 opa/autotune_preamp.png create mode 100644 opa/c2.png create mode 100644 opa/curve.png create mode 100644 opa/d2.png create mode 100644 opa/figures.py create mode 100644 opa/frequency domain examples.png create mode 100644 opa/introduction.png create mode 100644 opa/poweramp flowchart.png create mode 100644 opa/poweramp.png create mode 100644 opa/preamp flowchart.png create mode 100644 opa/preamp.png create mode 100644 opa/ranges.png create mode 100644 opa/reproducability.png create mode 100644 opa/signal_and_idler_motortune.png 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}{D_{PR}}}{} \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 Binary files /dev/null and b/opa/autotune_preamp.png differ diff --git a/opa/c2.png b/opa/c2.png new file mode 100644 index 0000000..a546d44 Binary files /dev/null and b/opa/c2.png 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 Binary files /dev/null and b/opa/curve.png differ diff --git a/opa/d2.png b/opa/d2.png new file mode 100644 index 0000000..3c1cf87 Binary files /dev/null and b/opa/d2.png 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 Binary files /dev/null and b/opa/frequency domain examples.png differ diff --git a/opa/introduction.png b/opa/introduction.png new file mode 100644 index 0000000..869c073 Binary files /dev/null and b/opa/introduction.png differ diff --git a/opa/poweramp flowchart.png b/opa/poweramp flowchart.png new file mode 100644 index 0000000..7ab1dc4 Binary files /dev/null and b/opa/poweramp flowchart.png differ diff --git a/opa/poweramp.png b/opa/poweramp.png new file mode 100644 index 0000000..3f0fdb7 Binary files /dev/null and b/opa/poweramp.png differ diff --git a/opa/preamp flowchart.png b/opa/preamp flowchart.png new file mode 100644 index 0000000..01b04f1 Binary files /dev/null and b/opa/preamp flowchart.png differ diff --git a/opa/preamp.png b/opa/preamp.png new file mode 100644 index 0000000..abf3a24 Binary files /dev/null and b/opa/preamp.png differ diff --git a/opa/ranges.png b/opa/ranges.png new file mode 100644 index 0000000..07bbbcb Binary files /dev/null and b/opa/ranges.png differ diff --git a/opa/reproducability.png b/opa/reproducability.png new file mode 100644 index 0000000..83ad67f Binary files /dev/null and b/opa/reproducability.png differ diff --git a/opa/signal_and_idler_motortune.png b/opa/signal_and_idler_motortune.png new file mode 100644 index 0000000..092eb72 Binary files /dev/null and b/opa/signal_and_idler_motortune.png differ -- cgit v1.2.3