Laser Lock Box Instrument

Moku:Lab’s Laser Lock Box allows you to stabilize a laser’s frequency to a reference cavity or transition using high-performance modulation locking techniques. The Laser Lock Box includes a ‘Tap-to-Lock’ feature enabling you to quickly lock to any zero-crossing on the demodulated error signal.

The Laser Lock Box can have monitor points set up, providing a “virtual Oscillscope” view of input, output and internal signals. Once configured, these can be displayed and logged using the same API as the Oscilloscope object.

Example Usage

The following example code and a wide range of other pymoku demo scripts can be found at the pymoku Github repository.

laser_lock_box_basic.py
#
# pymoku example: Basic Laser Lock Box
#
# This example demonstrates how you can configure the laser lock box
# instrument
#
# (c) 2019 Liquid Instruments Pty. Ltd.
#
from pymoku import Moku
from pymoku.instruments import LaserLockBox

import matplotlib
import matplotlib.pyplot as plt
from matplotlib.ticker import FuncFormatter
from scipy import signal

def gen_butterworth(corner_frequency):
    """
    Generate coefficients for a second order butterworth low-pass filter.

    Corner frequencies for laser lock box second harmonic filtering should be in the range: 1 kHz < corner frequency < 31.25 MHz.
    """
    sample_rate = 31.25e6
    normalised_corner = corner_frequency / (sample_rate / 2)
    b, a = signal.butter(2, normalised_corner, 'low', analog = False)

    coefficient_array = [[1.0, b[0], b[1], b[2], -a[1], -a[2]],
                        [1.0, 1.0,  0.0,  0.0,  0.0, 0.0]]
    return coefficient_array

# Use Moku.get_by_serial() or get_by_name() if you don't know the IP
m = Moku.get_by_name('Moku')

try:
    i = m.deploy_or_connect(LaserLockBox)

    # set local oscillator, auxiliary and scan generators
    i.set_local_oscillator(source='internal', frequency=0, phase=90, pll_auto_acq = False)
    i.set_aux_sine(amplitude = 1.0, frequency = 10e3, phase=0, sync_to_lo = False, output = 'out1')
    i.set_scan(frequency=1e3, phase=0, output = 'out2', amplitude=1.0, waveform='triangle')

    # configure PIDs:
    i.set_pid_by_gain(1, g=1, kp=1)
    i.set_pid_by_gain(2, g=1, kp=1)

    # configure second harmonic rejection low pass filter
    coef_array = gen_butterworth(1e4)
    i.set_custom_filter(coef_array)

finally:
    # Close the connection to the Moku device
    # This ensures network resources and released correctly
    m.close()

The LaserLockBox Class

class pymoku.instruments.LaserLockBox
commit()

Apply all modified settings.

Note

If the autocommit feature has been turned off, this function can be used to manually apply any instrument settings to the Moku device. These instrument settings are those configured by calling all set_ and gen_ type functions. Manually calling this function allows you to atomically apply many instrument settings at once.

get_data(timeout=None, wait=True)

Get full-resolution data from the instrument.

This will pause the instrument and download the entire contents of the instrument’s internal memory. This may include slightly more data than the instrument is set up to record due to rounding of some parameters in the instrument.

All settings must be committed before you call this function. If pymoku.autocommit=True (the default) then this will always be true, otherwise you will need to have called commit first.

The download process may take a second or so to complete. If you require high rate data, e.g. for rendering a plot, see get_realtime_data.

If the wait parameter is true (the default), this function will wait for any new settings to be applied before returning. That is, if you have set a new timebase (for example), calling this with wait=True will guarantee that the data returned has this new timebase.

Note that if instrument configuration is changed, a trigger event must occur before data captured with that configuration set can become available. This can take an arbitrary amount of time. For this reason the timeout should be set appropriately.

Parameters:
  • timeout (float) – Maximum time to wait for new data, or None for indefinite.
  • wait (bool) – If true (default), waits for a new waveform to be captured with the most recently-applied settings, otherwise just return the most recently captured valid data.
Returns:

InstrumentData subclass, specific to the instrument.

get_frontend(channel)

Get the analog frontend configuration.

Parameters:channel (int; {1,2}) – Channel for which the relay settings are being retrieved
Returns:Array of bool with the front end configuration of channels - [0] 50 Ohm - [1] 10xAttenuation - [2] AC Coupling
get_realtime_data(timeout=None, wait=True)

Get downsampled data from the instrument with low latency.

Returns a new InstrumentData subclass (instrument-specific), containing a version of the data that may have been downsampled from the original in order to be transferred quickly.

This function always returns a new object at framerate (10Hz by default), whether or not there is new data in that object. This can be verified by checking the return object’s waveformid parameter, which increments each time a new waveform is captured internally.

The downsampled, low-latency nature of this data makes it particularly suitable for plotting in real time. If you require high-accuracy, high-resolution data for analysis, see get_data.

If the wait parameter is true (the default), this function will wait for any new settings to be applied before returning. That is, if you have set a new timebase (for example), calling this with wait=True will guarantee that the data returned has this new timebase.

Note that if instrument configuration is changed, a trigger event must occur before data captured with that configuration set can become available. This can take an arbitrary amount of time. For this reason the timeout should be set appropriately.

Parameters:
  • timeout (float) – Maximum time to wait for new data, or None for indefinite.
  • wait (bool) – If true (default), waits for a new waveform to be captured with the most recently-applied settings, otherwise just return the most recently captured valid data.
Returns:

InstrumentData subclass, specific to the instrument.

get_samplerate()
Returns:The current instrument sample rate (Hz)
set_aux_sine(*args, **kwargs)

Configure the aux sine signal.

:type amplitude : float; [0, 2.0] Vpp :param amplitude : Auxiliary sine wave amplitude

:type frequency : float; [0, 200e6] Hz :param frequency : Auxiliary sine wave frequency

:type phase : float; [0, 360] degrees :param phase : float; Auxiliary sine wave phase offset

:type sync_to_lo : bool :param sync_to_lo : True = enable phase synchronisation to local oscillator, False = use auxiliary frequency and phase values.

:type output : list; [‘out1’, ‘out2’, ‘none’] :param output : select which channel to output the auxiliary signal on.

set_channel_pid_enables(*args, **kwargs)

Enable or disable connection of the selected PID controller to it’s corresponding output channel. Fast = Output 1, Slow = Output 2.

:type pid_block : int; [1, 2] :param pid_block : PID controller - 1 = Fast, 2 = Slow

:type en : bool; :param en : enable or disable channel.

set_custom_filter(*args, **kwargs)

Configure the filter coefficients in the IIR filter.

Parameters:filt_coeffs (array;) – array containg Direct-Form 1 SOS filter coefficients in the following format:
s1 b0.1 b1.1 b2.1 a1.1 a2.1
s2 b0.2 b1.2 b2.2 a1.2 a2.2

Each ‘a’ coefficient must be a float in the range [-2.0, +2.0). ‘s’ coefficients are multiplied into each ‘b’ coefficient before being sent to the device. These products (sN x b0.N, sN x b1.N, sN x b2.N) must also fall in the range [-2.0, +2.0). Internally, the ‘a’ and ‘b’ coefficients are represented as signed 32-bit fixed-point numbers, with 30 fractional bits.

Filter coefficients can be computed using signal processing toolboxes in e.g. MATLAB or SciPy.

set_defaults(*args, **kwargs)

Reset the Oscilloscope to sane defaults.

set_framerate(*args, **kwargs)

Set framerate

set_frontend(channel, fiftyr=True, atten=False, ac=False)

Configures gain, coupling and termination for each channel.

Parameters:
  • channel (int; {1,2}) – Channel to which the settings should be applied
  • fiftyr (bool) – 50Ohm termination; default is 1MOhm.
  • atten (bool) – Turn on 10x attenuation. Changes the dynamic range between 1Vpp and 10Vpp.
  • ac (bool) – AC-couple; default DC.
set_input_gain(*args, **kwargs)

Set the main input gain (Input Channel 1).

Parameters:gain (int; {-20, 0, 24, 48} dB) – Input gain
set_local_oscillator(*args, **kwargs)

Configure the local oscillator. The local oscillator can be generated internally with configurable frequency and phase offset, externally via ADC 2 or internally with a PLL phase locked to ADC 2 plus an additional phase offset.

:type frequency : float; [0, 200e6] Hz :param frequency : Internal demodulation frequency

:type phase : float; [0, 360] degrees :param phase : float; Internal demodulation phase

:type source : list; [‘internal’, ‘external’, ‘external_pll’] :param source : Local Oscillator Source

:type pll_auto_acq : bool :param pll_auto_acq : Enable PLL Auto Acquire

set_monitor(*args, **kwargs)

Select the point inside the laser lock box to monitor.

There are two monitoring channels available, ‘A’ and ‘B’; you can mux any of the internal monitoring points to either of these channels.

The source is one of:
  • error_signal: error signal (after low-pass filter)
  • pid_fast: output of the fast pid
  • pid_slow: output of the slow pid
  • offset_fast: offset on the input to the fast pid
  • in1: input channel 1
  • in2: input channel 2
  • out1: output channel 1
  • out2: output channel 2
  • scan: scan signal
  • lo: local oscillator signal
  • aux: auxiliary sinewave signal
Parameters:
  • monitor_ch (string; {'A','B'}) – Monitor channel
  • source (string; {'error', 'pid_fast', 'pid_slow', 'offset_fast', 'offset_slow', 'in1', 'in2', 'out1', 'out2', 'scan', 'lo', 'aux', 'slow_scan'}) – Signal to monitor
set_offsets(*args, **kwargs)

Set offsets throughout the laser locker.

:type position : list; [‘pid_input’, ‘out1’, ‘out2’] :param position : The desired point to add an offset

:type offset : float, [-2.0, 2.0] Volts. :param offset : voltage offset.

set_output_enables(*args, **kwargs)

Enable or disable the selected output channel.

:type ch : int; [1, 2] :param ch : 1 = Output 1, 2 = Output 2

:type en : bool; :param en : enable or disable channel.

set_output_range(*args, **kwargs)

Set upper and lower bounds for the signal on each DAC channel. The auxilliary waveform is not restricted to these bounds when added to either DAC channel.

:type ch : int; [1, 2] :param ch : 1 = Output 1, 2 = Output 2

Parameters:
  • maximum (float, [-1.0, 1.0] Volts;) – maximum value the output signal can be before clipping occurs.
  • maximum – maximum value the output signal can be before clipping occurs.
set_pid_by_freq(*args, **kwargs)

Configure the selected PID controller using crossover frequencies.

:type pid_block : int; [1,2] :param pid_block : PID controller - 1 = Fast, 2 = Slow

Parameters:
  • kp (float; [-1e3,1e3]) – Proportional gain factor
  • i_xover (float; [1e-3,1e6] Hz) – Integrator crossover frequency
  • d_xover (float; [1,10e6] Hz) – Differentiator crossover frequency
  • si (float; float; [-1e3,1e3]) – Integrator gain saturation
  • sd (float; [-1e3,1e3]) – Differentiator gain saturation
  • enable (bool;) – enables pid outputs
Raises:

InvalidConfigurationException – if the configuration of PID gains is not possible.

set_pid_by_gain(*args, **kwargs)

Configure the selected PID controller using gain coefficients.

:type pid_block : int; [1,2] :param pid_block : PID controller - 1 = Fast, 2 = Slow

Parameters:
  • g (float; [0,2^16 - 1]) – Gain
  • kp (float; [-1e3,1e3]) – Proportional gain factor
  • ki (float; [0, 31.25e6] with a resolution of 31.25e6 / 2^24-1 when pid_block = 1 [0, 488.28e3] with a resolution of 488.28 / 2^24-1 when pid_block = 2.) – Integrator gain factor.
  • kd (float; [0, 31.25e6] when pid_block = 1, [0, 488.28e3] when pid_block = 2) – Differentiator gain factor
  • si (float; float; [-1e3,1e3]) – Integrator gain saturation
  • sd (float; [-1e3,1e3]) – Differentiator gain saturation
  • enable (bool;) – enables pid outputs
Raises:

InvalidConfigurationException – if the configuration of PID gains is not possible.

set_pid_enables(*args, **kwargs)

Enable or disable the selected PID controller.

:type pid_block : int; [1, 2] :param pid_block : PID controller - 1 = Fast, 2 = Slow

:type en : bool; :param en : enable or disable PID controller described in pid_block.

set_precision_mode(*args, **kwargs)

Change aquisition mode between downsampling and decimation. Precision mode, a.k.a Decimation, samples at full rate and applies a low-pass filter to the data. This improves precision. Normal mode works by direct downsampling, throwing away points it doesn’t need.

Parameters:state (bool) – Select Precision Mode
set_samplerate(*args, **kwargs)

Manually set the sample rate of the instrument.

The sample rate is automatically calculated and set in set_timebase.

This interface allows you to specify the rate at which data is sampled, and set a trigger offset in number of samples. This interface is useful for datalogging and capturing of data frames.

Parameters:
  • samplerate (float; 0 < samplerate <= MAX_SAMPLERATE smp/s) – Target samples per second. Will get rounded to the nearest allowable unit.
  • trigger_offset (int; -2^16 < trigger_offset < 2^31) – Number of samples before (-) or after (+) the trigger point to start capturing.
Raises:

ValueOutOfRangeException – if either parameter is out of range.

set_scan(*args, **kwargs)

Configure the scanning generator.

:type amplitude : float; [0, 2.0] Vpp :param amplitude : Scan amplitude

:type frequency : float; [0, 1e6] Hz :param frequency : Scan frequency

:type phase : float; [0, 360] degrees :param phase : float; Scan phase offset

:type waveform : List; [‘sawtooth’, ‘triangle’] :param sync_to_lo : Scan waveform type.

:type output : list; [‘out1’, ‘out2’, ‘none’] :param output : select which channel to output the scan signal on.

set_timebase(*args, **kwargs)

Set the left- and right-hand span for the time axis. Units are seconds relative to the trigger point.

Parameters:
  • t1 (float) – Time, in seconds, from the trigger point to the left of screen. This may be negative (trigger on-screen) or positive (trigger off the left of screen).
  • t2 (float) – As t1 but to the right of screen.
Raises:

InvalidConfigurationException – if the timebase is backwards or zero.

set_trigger(*args, **kwargs)

Set the trigger source for the monitor channel signals. This can be either of the input or monitor signals, the external input or the scan output.

Parameters:
  • source (string, {'in1','in2','scan','A','B','ext'}) – Trigger Source. May be either an input or monitor channel (as set by set_monitor()), external or the scan output. External refers to the back-panel connector of the same name, allowing triggering from an externally-generated digital [LV]TTL or CMOS signal.
  • edge (string, {'rising','falling','both'}) – Which edge to trigger on. In Pulse Width modes this specifies whether the pulse is positive (rising) or negative (falling), with the ‘both’ option being invalid.
  • level (float, [-10.0, 10.0] volts) – Trigger level
  • minwidth (float, seconds) – Minimum Pulse Width. 0 <= minwidth < (2^32/samplerate). Can’t be used with maxwidth.
  • maxwidth (float, seconds) – Maximum Pulse Width. 0 <= maxwidth < (2^32/samplerate). Can’t be used with minwidth.
  • hysteresis (float, [100e-6, 1.0] volts) – Hysteresis around trigger point.
  • hf_reject (bool) – Enable high-frequency noise rejection
  • mode (string, {'auto', 'normal'}) – Trigger mode.
  • trig_on_scan_rising (bool) – trigger only during rising portion of scan signal.
set_xmode(*args, **kwargs)

Set rendering mode for the horizontal axis.

Parameters:xmode (string, {'roll','sweep','fullframe'}) – Respectively; Roll Mode (scrolling), Sweep Mode (normal oscilloscope trace sweeping across the screen) or Full Frame (like sweep, but waits for the frame to be completed).