# Examples for Python

# Arbitrary Waveform Generator

# arbitrarywavegen_basic.py

This example demonstrates how you can generate and output arbitrary waveforms using Moku AWG

#
# moku example: Arbitrary waveform generator
#
# This example demonstrates how you can generate and output arbitrary
# waveforms using Moku AWG
#
# (c) 2021 Liquid Instruments Pty. Ltd.
#
import numpy as np
from moku.instruments import ArbitraryWaveformGenerator

# generate a signal that the Arbitrary Waveform Genenrator should generate on the output
t = np.linspace(0, 1, 100)  # Evaluate our waveform at 100 points

# Simple square wave (can also use scipy.signal)
sq_wave = np.array([-1.0 if x < 0.5 else 1.0 for x in t])

# More interesting waveform. Note that we have to normalize this waveform
# to the range [-1, 1]
not_sq = np.zeros(len(t))
for h in np.arange(1, 15, 2):
    not_sq += (4 / (np.pi * h)) * np.cos(2 * np.pi * h * t)

not_sq = not_sq / max(abs(not_sq))

# Connect to your Moku by its ip address ArbitraryWaveformGenerator('192.168.###.###')
# or by its serial ArbitraryWaveformGenerator(serial=123)
i = ArbitraryWaveformGenerator('192.168.###.###', force_connect=False)

try:
    # Load and configure the waveform.
    i.generate_waveform(channel=1, sample_rate='Auto',
                        lut_data=list(sq_wave), frequency=10e3,
                        amplitude=1)
    i.generate_waveform(channel=2, sample_rate='Auto', lut_data=list(not_sq),
                        frequency=10e3, amplitude=1)

    # Set channel 1 to pulse mode 
    # 2 dead cycles at 0Vpp
    i.pulse_modulate(channel=1,dead_cycles=2,dead_voltage=0)

    # Set Channel 2 to burst mode
    # Burst mode triggering from Input 1 at 0.1 V
    # 3 cycles of the waveform will be generated every time it is triggered
    i.burst_modulate(channel=2, trigger_source='Input1',trigger_mode='NCycle',burst_cycles=3,trigger_level=0.1)

except Exception as e:
    print(f'Exception occurred: {e}')

finally:
    # Close the connection to the Moku device
    # This ensures network resources and released correctly
    i.relinquish_ownership()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53

# Data Logger

# datalogger_basic.py

This example demonstrates use of the Datalogger instrument to log time-series voltage data to a file.

#
# moku example: Basic Datalogger
#
# This example demonstrates use of the Datalogger instrument to log time-series
# voltage data to a (Binary or CSV) file.
#
# (c) 2021 Liquid Instruments Pty. Ltd.
#
import os
import time

from moku.instruments import Datalogger

# Connect to your Moku by its ip address using Datalogger('192.168.###.###')
# or by its serial number using Datalogger(serial=123)
i = Datalogger('192.168.###.###', force_connect=False)

try:
    # Configure the frontend
    i.set_frontend(channel=1, impedance='1MOhm', coupling="AC", range="10Vpp")
    # Log 100 samples per second
    i.set_samplerate(100)

    i.set_acquisition_mode(mode='Precision')

    # Generate Sine wave on Output1
    i.generate_waveform(channel=1, type='Sine', amplitude=1,
                        frequency=10e3)
    
    # Stop an existing log, if any, then start a new one. 10 seconds of both
    # channels
    logFile = i.start_logging(duration=10)

    # Track progress percentage of the data logging session
    is_logging = True
    while is_logging:
        # Wait for the logging session to progress by sleeping 0.5sec
        time.sleep(0.5)
        # Get current progress percentage and print it out
        progress = i.logging_progress()
        remaining_time = int(progress['time_to_end'])
        is_logging = remaining_time > 1
        print(f"Remaining time {remaining_time} seconds")

    # Download log from Moku, use liconverter to convert this .li file to .csv
    i.download("persist", logFile['file_name'], os.path.join(os.getcwd(), logFile['file_name']))
    print("Downloaded log file to local directory.")

except Exception as e:
    print(f'Exception occurred: {e}')
finally:
    # Close the connection to the Moku device
    # This ensures network resources and released correctly
    i.relinquish_ownership()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54

# Data Streaming

# datalogger_streaming.py

This example demonstrates use of the Datalogger instrument to stream time-series voltage data.

#
# moku example: Basic Datalogger streaming
#
# This example demonstrates use of the Datalogger instrument to
# stream time-series voltage data and plot it using matplotlib
#
# (c) 2022 Liquid Instruments Pty. Ltd.
#
import matplotlib.pyplot as plt

from moku.instruments import Datalogger

i = Datalogger('192.168.###.###', force_connect=False)

try:
    # generate a waveform on output channel 1
    i.generate_waveform(1, "Sine", frequency=100)

    # disable Input2 as we want to stream data only from Input1
    i.disable_channel(2)

    # set the sample rate to 10KSa/s
    i.set_samplerate(10e3)

    # stream the data for 10 seconds..
    i.start_streaming(10)

    # Set up the plotting parameters
    plt.ion()
    plt.show()
    plt.grid(b=True)
    plt.ylim([-1, 1])

    line1, = plt.plot([])

    # Configure labels for axes
    ax = plt.gca()

    # This loops continuously updates the plot with new data
    while True:
        # get the chunk of streamed data
        data = i.get_stream_data()
        if data:
            plt.xlim([data['time'][0], data['time'][-1]])
            # Update the plot
            line1.set_ydata(data['ch1'])
            line1.set_xdata(data['time'])
            plt.pause(0.001)

except Exception as e:
    i.stop_streaming()
    print(e)
finally:
    i.relinquish_ownership()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53

# lock_in_amplifier_streaming.py

This example demonstrates use of the Lockin Amplifier instrument to demodulate Input signal with a reference signal from local oscillator and stream the generated waveform from auxiliary output

#
# moku example: Plotting Lock-in Amplifier
#
# This example demonstrates how you can configure the Lock-in
# Amplifier instrument to demodulate an input signal from Input 1
# with the reference signal from the Local Oscillator to extract the
# X component and generate a sine wave on the auxiliary output

# (c) 2022 Liquid Instruments Pty. Ltd.
#

import matplotlib.pyplot as plt

from moku.instruments import LockInAmp

# Connect to your Moku by its ip address using
# LockInAmp('192.168.###.###')
# or by its serial number using LockInAmp(serial=123)
i = LockInAmp('192.168.xxx.xxx', force_connect=False)

try:
    # SetChannel 1 and 2 to DC coupled, 1 Mohm impedance, and
    # 400 mVpp range
    i.set_frontend(1, coupling='DC', impedance='1MOhm',
                   attenuation='0dB')
    i.set_frontend(2, coupling='DC', impedance='1MOhm',
                   attenuation='0dB')

    # Configure the demodulation signal to Local oscillator
    # with 1 MHz and 0 degrees phase shift
    i.set_demodulation('Internal', frequency=1e6, phase=0)

    # Set low pass filter to 1 kHz corner frequency with
    # 6 dB/octave slope
    i.set_filter(1e3, slope='Slope6dB')

    # Configure output signals
    # X component to Output 1
    # Aux oscillator signal to Output 2 at 1 MHz 500 mVpp
    i.set_outputs('X', 'Aux')
    i.set_aux_output(1e6, 0.5)

    # Set up signal monitoring
    # Configure monitor points to Input 1 and main output
    i.set_monitor(1, 'Input1')
    i.set_monitor(2, 'MainOutput')

    # Configure the trigger conditions
    # Trigger on Probe A, rising edge, 0V
    i.set_trigger(type='Edge', source='ProbeA', level=0)

    # View +- 1 ms i.e. trigger in the centre
    i.set_timebase(-1e-3, 1e-3)

    i.start_streaming(duration=20, rate=100e3)
    # Set up the plotting parameters
    plt.ion()
    plt.show()
    plt.grid(visible=True)
    plt.ylim([-1, 1])

    line1, = plt.plot([])
    line2, = plt.plot([])

    # Configure labels for axes
    ax = plt.gca()

    # This loops continuously updates the plot with new data
    while True:
        # Get new data
        data = i.get_stream_data()
        if data:
            plt.xlim([data['time'][0], data['time'][-1]])
            # Update the plot
            line1.set_ydata(data['ch1'])
            line2.set_ydata(data['ch2'])
            line1.set_xdata(data['time'])
            line2.set_xdata(data['time'])
            plt.pause(0.001)

except Exception as e:
    i.stop_streaming()
    print(f'Exception occurred: {e}')
finally:
    # Close the connection to the Moku device
    # This ensures network resources are released correctly
    i.relinquish_ownership()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86

# mim_dl_lia_streaming.py

This example demonstrates data streaming feature in Multi-instrument mode, deploying Datalogger in slot1 and Lockin Amplifier in slot2.

import matplotlib.pyplot as plt

from moku.instruments import Datalogger, LockInAmp, MultiInstrument

i = MultiInstrument('192.168.xxx.xxx', platform_id=2)

try:
    dl = i.set_instrument(1, Datalogger)
    lia = i.set_instrument(2, LockInAmp)

    connections = [dict(source="Input1", destination="Slot1InA"),
                   dict(source="Slot1OutA", destination="Slot2InA"),
                   dict(source="Slot1OutA", destination="Slot2InB"),
                   dict(source="Slot2OutA", destination="Output1")]

    i.set_connections(connections=connections)

    dl.generate_waveform(1, "Sine", frequency=1000)

    dl.start_streaming(10)

    dl.stream_to_file()

    lia.set_monitor(1, "Input1")

    lia.start_streaming(10)

    plt.ion()
    plt.show()
    plt.grid(b=True)
    plt.ylim([-1, 1])

    line1, = plt.plot([])
    line2, = plt.plot([])

    # Configure labels for axes
    ax = plt.gca()

    # This loops continuously updates the plot with new data
    while True:
        # Get new data
        data = lia.get_stream_data()

        # Update the plot
        if data:
            plt.xlim([data['time'][0], data['time'][-1]])
            line1.set_ydata(data['ch1'])
            line1.set_xdata(data['time'])
            plt.pause(0.001)

except Exception as e:
    print(e)
finally:
    i.relinquish_ownership()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53

# Digital Filter Box

This example demonstrates how you can configure the Digital Filter Box instrument to filter and display two signals.

#
# Python moku example: Plotting Digital Filter Box
#
# This example demonstrates how you can configure the Digital
# Filter Box instrument to filter and display two signals. Filter
# 1 takes its input from Input1 and applies a lowpass Butterworth
# filter. Filter 2 takes its input from Input1 + Input2 and applies
# a highpass Elliptic filter. The output of both filters are then
# displayed on the plot.
#
# (c) 2023 Liquid Instruments Pty. Ltd.
#

import matplotlib.pyplot as plt

from moku import MokuException
from moku.instruments import DigitalFilterBox

# Connect to your Moku by its ip address using
# DigitalFilterBox('192.168.###.###')
# or by its serial number using DigitalFilterBox(serial=123)
i = DigitalFilterBox('192.168.2.125', force_connect=True)

try:
    # SetChannel 1 and 2 to DC coupled, 1 Mohm impedance, and
    # default input range (400 mVpp range on Moku:Pro, 1 Vpp
    # range on Moku:Lab, 10 Vpp range on Moku:Go)
    i.set_frontend(1, coupling='DC', impedance='1MOhm',
                   attenuation='0dB')
    i.set_frontend(2, coupling='DC', impedance='1MOhm',
                   attenuation='0dB')

    # Channel1 signal: Input 1
    # Channel2 signal: Input 1 + Input 2
    i.set_control_matrix(1, input_gain1=1, input_gain2=0)
    i.set_control_matrix(2, input_gain1=1, input_gain2=1)

    # Configure Digital Filter on Channel 1 and Channel 2
    # Channel1 is a 8th-order Butterworth lowpass filter
    # Channel2 is a 8th-order Elliptic highpass filter
    # 3.906 MHz is for Moku:Go
    # Please change sampling rate for other Moku devices.
    i.set_filter(1, "3.906MHz", shape="Lowpass", 
                 type="Butterworth", low_corner=1e3,
                 order=8)
    i.set_filter(2, "3.906MHz", shape="Highpass", 
                 type="Elliptic",high_corner=100e3,
                 order=8)

    # Monitor ProbeA: Filter Channel1 output
    # Monitor ProbeB: Filter Channel2 output
    i.set_monitor(1, "Output1")
    i.set_monitor(2, "Output2")

    # Enable Digital Filter Box output ports
    i.enable_output(1, signal=True, output=True)
    i.enable_output(2, signal=True, output=True)

    # View +- 0.5 ms i.e. trigger in the centre
    i.set_timebase(-0.5e-3, 0.5e-3)

    # Set up the plotting parameters
    plt.ion()
    plt.show()
    plt.grid(visible=True)
    plt.ylim([-0.01, 0.01])

    line1, = plt.plot([],label="Lowpass Filter Output")
    line2, = plt.plot([],label="Highpass Filter Output")

    # Configure labels for axes
    ax = plt.gca()
    ax.legend(handles=[line1, line2])
    plt.xlabel("Time [Second]")
    plt.ylabel("Amplitude [Volt]")

    # This loops continuously updates the plot with new data
    while True:
        # Get new data
        data = i.get_data()
        if data:
            plt.xlim([data['time'][0], data['time'][-1]])
            # Update the plot
            line1.set_ydata(data['ch1'])
            line2.set_ydata(data['ch2'])
            line1.set_xdata(data['time'])
            line2.set_xdata(data['time'])
            plt.pause(0.001)
except MokuException as e:
    print("Couldn't configure Moku. Please check your IP address and that you've updated the script parameters (such as sampling rate) to match your device.")
    raise e
finally:
    # Releasing ownership of the Moku allows other users to connect
    # to it without forcing a takeover.
    i.relinquish_ownership()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95

# Frequency Response Analyzer

# freq_response_analyzer_basic.py

This example demonstrates how you can generate output sweeps using the Frequency Response Analyzer instrument, and view one frame of the transfer function data.

#
# moku example: Basic Frequency Response Analyzer
#
# This example demonstrates how you can generate output sweeps using the
# Frequency Response Analyzer instrument, and view one frame of the transfer
# function data.
#
# (c) 2021 Liquid Instruments Pty. Ltd.
#
from moku.instruments import FrequencyResponseAnalyzer

# Connect to your Moku by its ip address using FrequencyResponseAnalyzer('192.168.###.###')
# or by its serial number using FrequencyResponseAnalyzer(serial=123)
i = FrequencyResponseAnalyzer('192.168.###.###', force_connect=False)

try:
    # Configure output sweep parameters (100Hz-20MHz)
    i.set_sweep(start_frequency=20e6, stop_frequency=100, num_points=256,
                averaging_time=1e-3, averaging_cycles=5, settling_cycles=5,
                settling_time=1e-3)

    # Configure output sweep amplitudes
    # Channel 1 - 0.1Vpp
    # Channel 1 - 0.1Vpp
    i.set_output(1, 0.1)
    i.set_output(2, 0.1)

    # Start the sweep
    i.start_sweep()

    # Get a single sweep frame. This will block until the sweep is complete,
    # beware if your range includes low frequencies!
    frame = i.get_data()

    # Print out the data for Channel 1
    print(frame['ch1']['frequency'], frame['ch1']['magnitude'],
          frame['ch1']['phase'])

    # Print out the data for Channel 2
    print(frame['ch2']['frequency'], frame['ch2']['magnitude'],
          frame['ch2']['phase'])

except Exception as e:
    print(f'Exception occurred: {e}')
finally:
    # Close the connection to the Moku device
    # This ensures network resources and released correctly
    i.relinquish_ownership()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48

# freq_response_analyzer_plotting.py

This example demonstrates how you can generate output sweeps using the Frequency Response Analyzer instrument, and view transfer function data in real-time.

#
# moku example: Plotting Frequency Response Analyzer
#
# This example demonstrates how you can generate output sweeps using the
# Frequency Response Analyzer instrument, and view transfer function data
# in real-time.
#
# (c) 2021 Liquid Instruments Pty. Ltd.
#
import matplotlib.pyplot as plt
from moku.instruments import FrequencyResponseAnalyzer

# Connect to your Moku by its ip address using FrequencyResponseAnalyzer('192.168.###.###')
# or by its serial number using FrequencyResponseAnalyzer(serial=123)
i = FrequencyResponseAnalyzer('192.168.###.###', force_connect=False)

# Define output sweep parameters here for readability
f_start = 20e6  # Hz
f_end = 100  # Hz
sweep_length = 512
log_scale = True
amp_ch1 = 0.5  # Vpp
amp_ch2 = 0.5  # Vpp
averaging_time = 1e-6  # sec
settling_time = 1e-6  # sec
averaging_cycles = 1
settling_cycles = 1

try:
    # Set the output sweep amplitudes
    i.set_output(1, amp_ch1)
    i.set_output(2, amp_ch2)

    # Set the sweep configuration
    i.set_sweep(start_frequency=f_start, stop_frequency=f_end,
                num_points=sweep_length, averaging_time=averaging_time,
                settling_time=settling_time, averaging_cycles=averaging_cycles,
                settling_cycles=settling_cycles)

    # Start the output sweep in loop mode
    i.start_sweep()

    # Set up the amplitude plot
    plt.subplot(211)
    if log_scale:
        # Plot log x-axis if frequency sweep scale is logarithmic
        line1, = plt.semilogx([])
        line2, = plt.semilogx([])
    else:
        line1, = plt.plot([])
        line2, = plt.plot([])
    ax_1 = plt.gca()
    ax_1.set_xlabel('Frequency (Hz)')
    ax_1.set_ylabel('Magnitude (dB)')

    # Set up the phase plot
    plt.subplot(212)
    if log_scale:
        line3, = plt.semilogx([])
        line4, = plt.semilogx([])
    else:
        line3, = plt.plot([])
        line4, = plt.plot([])
    ax_2 = plt.gca()
    ax_2.set_xlabel('Frequency (Hz)')
    ax_2.set_ylabel('Phase (Cycles)')

    plt.ion()
    plt.show()
    plt.grid(b=True)

    # Retrieves and plot new data
    while True:
        frame = i.get_data()
        ch1Data = frame['ch1']
        ch2Data = frame['ch2']

        # Set the frame data for each channel plot
        plt.subplot(211)

        ch1MagnitudeData = ch1Data['magnitude']
        ch2MagnitudeData = ch2Data['magnitude']
        line1.set_ydata(ch1MagnitudeData)
        line2.set_ydata(ch2MagnitudeData)
        line1.set_xdata(ch1Data['frequency'])
        line2.set_xdata(ch2Data['frequency'])

        # Phase
        plt.subplot(212)
        ch1PhaseData = ch1Data['phase']
        ch2PhaseData = ch2Data['phase']
        line3.set_ydata(ch1PhaseData)
        line4.set_ydata(ch2PhaseData)
        line3.set_xdata(ch1Data['frequency'])
        line4.set_xdata(ch2Data['frequency'])

        # Ensure the frequency axis is a tight fit
        ax_1.set_xlim(min(ch1Data['frequency']), max(ch2Data['frequency']))
        ax_2.set_xlim(min(ch1Data['frequency']), max(ch2Data['frequency']))
        ax_1.relim()
        ax_1.autoscale_view()
        ax_2.relim()
        ax_2.autoscale_view()

        # Redraw the lines
        plt.draw()

        plt.pause(0.001)

except Exception as e:
    print(f'Exception occurred: {e}')
finally:
    # Close the connection to the Moku device
    # This ensures network resources and released correctly
    i.relinquish_ownership()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115

# Laser Lock Box

# laser_lock_box_basic.py

This example demonstrates how you can configure the Laser Lock Box Instrument and monitor the signals at Input 1 and Input 2.

#
# moku example: Basic Laser Lock Box
#
# This example demonstrates how you can configure the Laser Lock Box 
# Instrument and monitor the signals at Input 1 and Input 2.

# (c) 2022 Liquid Instruments Pty. Ltd.
#

from moku.instruments import LaserLockBox

# Connect to your Moku by its ip address using LaserLockBox('192.168.###.###')
# or by its serial number using LaserLockBox(serial=123)
i = LaserLockBox('192.168.xxx.xxx', force_connect=False)

try:
    # SetChannel 1 and 2 to DC coupled, 1 Mohm impedance, and 400 mVpp range
    i.set_frontend(1, coupling='DC', impedance='1MOhm',gain='0dB')
    i.set_frontend(2, coupling='DC', impedance='1MOhm',gain='-20dB')

    # Configure the scan oscillator to a 10 Hz 500 mVpp positive ramp
    # signal from Output 1
    i.set_scan_oscillator(enable=True,shape='PositiveRamp',
        frequency=10,amplitude=0.5,output='Output1')

    # Configure the demodulation signal to Local oscillator with 1 MHz and
    # 0 degrees phase shift
    i.set_demodulation('Internal',frequency=1e6,phase=0)

    # Configure a 4th order low pass filter with 100 kHz corner frequency
    i.set_filter(shape='Lowpass',low_corner=100e3,order=4)

    # Set the fast PID controller to -10 dB proportional gain and
    # intergrator crossover frequency at 3 kHz
    i.set_pid_by_frequency(1,-10,int_crossover=3e3)
    # Set the slow PID controller to -10 dB proportional gain and
    # intergrator crossover frequency at 50 Hz
    i.set_pid_by_frequency(2,-10,int_crossover=50)


except Exception as e:
    print(f'Exception occurred: {e}')
finally:
    # Close the connection to the Moku device
    # This ensures network resources are released correctly
    i.relinquish_ownership()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46

# laser_lock_box_plotting.py

This example demonstrates how you can configure the Laser Lock Box Instrument and monitor the signals at Input 1 and Input 2.

#
# moku example: Plotting Laser Lock Box
#
# This example demonstrates how you can configure the Laser Lock Box 
# Instrument and monitor the signals at Input 1 and Input 2.

# (c) 2022 Liquid Instruments Pty. Ltd.
#

import matplotlib.pyplot as plt
from moku.instruments import LaserLockBox

# Connect to your Moku by its ip address using LaserLockBox('192.168.###.###')
# or by its serial number using LaserLockBox(serial=123)
i = LaserLockBox('192.168.xxx.xxx', force_connect=False)

try:
    # SetChannel 1 and 2 to DC coupled, 1 Mohm impedance, and 400 mVpp range
    i.set_frontend(1, coupling='DC', impedance='1MOhm',gain='0dB')
    i.set_frontend(2, coupling='DC', impedance='1MOhm',gain='-20dB')

    # Configure the scan oscillator to a 10 Hz 500 mVpp positive ramp
    # signal from Output 1
    i.set_scan_oscillator(enable=True,shape='PositiveRamp',
        frequency=10,amplitude=0.5,output='Output1')

    # Configure the demodulation signal to Local oscillator with 1 MHz and
    # 0 degrees phase shift
    i.set_demodulation('Internal',frequency=1e6,phase=0)

    # Configure a 4th order low pass filter with 100 kHz corner frequency
    i.set_filter(shape='Lowpass',low_corner=100e3,order=4)

    # Set the fast PID controller to -10 dB proportional gain and
    # intergrator crossover frequency at 3 kHz
    i.set_pid_by_frequency(1,-10,int_crossover=3e3)
    # Set the slow PID controller to -10 dB proportional gain and
    # intergrator crossover frequency at 50 Hz
    i.set_pid_by_frequency(2,-10,int_crossover=50)
    
    # Enable the output channels
    i.set_output(1,True,True);
    i.set_output(2,True,True);

    # Set up signal monitoring
    # Configure monitor points to Input 1 and Input2
    i.set_monitor(1,'Input1')
    i.set_monitor(2,'Input2')
    
    # Configure the trigger conditions
    # Trigger on Probe A, rising edge, 0V
    i.set_trigger(type='Edge', source='ProbeA', level=0)
    
    # View +- 1 ms i.e. trigger in the centre
    i.set_timebase(-1e-3,1e-3)

    # Get initial data frame to set up plotting parameters. This can be done
    # once if we know that the axes aren't going to change (otherwise we'd do
    # this in the loop)
    data = i.get_data()

    # Set up the plotting parameters
    plt.ion()
    plt.show()
    plt.grid(visible=True)
    plt.ylim([-1, 1])
    plt.xlim([data['time'][0], data['time'][-1]])

    line1, = plt.plot([])
    line2, = plt.plot([])

    # Configure labels for axes
    ax = plt.gca()

    # This loops continuously updates the plot with new data
    while True:
        # Get new data
        data = i.get_data()

        # Update the plot
        line1.set_ydata(data['ch1'])
        line2.set_ydata(data['ch2'])
        line1.set_xdata(data['time'])
        line2.set_xdata(data['time'])
        plt.pause(0.001)

except Exception as e:
    print(f'Exception occurred: {e}')
finally:
    # Close the connection to the Moku device
    # This ensures network resources are released correctly
    i.relinquish_ownership()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92

# Lock-in Amplifier

# lock_in_amplifier_basic.py

This example demonstrates how you can configure the Lock-in Amplifier instrument to demodulate an input signal from Input 1 with the reference signal from the Local Oscillator to extract the X component and generate a sine wave on the auxiliary output

#
# moku example: Basic Lock-in Amplifier
#
# This example demonstrates how you can configure the Lock-in Amplifier
#  instrument to demodulate an input signal from Input 1 with the reference
#  signal from the Local Oscillator to extract the X component and generate
#  a sine wave on the auxiliary output

# (c) 2022 Liquid Instruments Pty. Ltd.
#
from moku.instruments import LockInAmp

# Connect to your Moku by its ip address using LockInAmp('192.168.###.###')
# or by its serial number using LockInAmp(serial=123)
i = LockInAmp('192.168.xxx.xxx', force_connect=False)

try:
    # SetChannel 1 and 2 to DC coupled, 1 Mohm impedance, and 400 mVpp range
    i.set_frontend(1, coupling='DC', impedance='1MOhm',attenuation='0dB')
    i.set_frontend(2, coupling='DC', impedance='1MOhm',attenuation='0dB')

    # Configure the demodulation signal to Local oscillator with 1 MHz and
    # 0 degrees phase shift
    i.set_demodulation('Internal',frequency=1e6,phase=0)

    # Set low pass filter to 1 kHz corner frequency with 6 dB/octave slope
    i.set_filter(1e3,slope='Slope6dB')

    # Configure output signals
    # X component to Output 1 
    # Aux oscillator signal to Output 2 at 1 MHz 500 mVpp
    i.set_outputs('X','Aux')
    i.set_aux_output(1e6,0.5)

except Exception as e:
    print(f'Exception occurred: {e}')
finally:
    # Close the connection to the Moku device
    # This ensures network resources are released correctly
    i.relinquish_ownership()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40

# lock_in_amplifier_plotting.py

This example demonstrates how you can configure the Lock-in Amplifier instrument to demodulate an input signal from Input 1 with the reference signal from the Local Oscillator to extract the X component and generate a sine wave on the auxiliary output

#
# moku example: Plotting Lock-in Amplifier
#
# This example demonstrates how you can configure the Lock-in Amplifier
#  instrument to demodulate an input signal from Input 1 with the reference
#  signal from the Local Oscillator to extract the X component and generate
#  a sine wave on the auxiliary output

# (c) 2022 Liquid Instruments Pty. Ltd.
#

import matplotlib.pyplot as plt
from moku.instruments import LockInAmp

# Connect to your Moku by its ip address using LockInAmp('192.168.###.###')
# or by its serial number using LockInAmp(serial=123)
i = LockInAmp('192.168.xxx.xxx', force_connect=False)

try:
    # SetChannel 1 and 2 to DC coupled, 1 Mohm impedance, and 400 mVpp range
    i.set_frontend(1, coupling='DC', impedance='1MOhm',attenuation='0dB')
    i.set_frontend(2, coupling='DC', impedance='1MOhm',attenuation='-20dB')

    # Configure the demodulation signal to Local oscillator with 1 MHz and
    # 0 degrees phase shift
    i.set_demodulation('Internal',frequency=1e6,phase=0)

    # Set low pass filter to 1 kHz corner frequency with 6 dB/octave slope
    i.set_filter(1e3,slope='Slope6dB')

    # Configure output signals
    # X component to Output 1 
    # Aux oscillator signal to Output 2 at 1 MHz 500 mVpp
    i.set_outputs('X','Aux')
    i.set_aux_output(1e6,0.5)

    # Set up signal monitoring
    # Configure monitor points to Input 1 and main output
    i.set_monitor(1,'Input1')
    i.set_monitor(2,'MainOutput')
    
    # Configure the trigger conditions
    # Trigger on Probe A, rising edge, 0V
    i.set_trigger(type='Edge', source='ProbeA', level=0)
    
    # View +- 1 ms i.e. trigger in the centre
    i.set_timebase(-1e-3,1e-3)

    # Get initial data frame to set up plotting parameters. This can be done
    # once if we know that the axes aren't going to change (otherwise we'd do
    # this in the loop)
    data = i.get_data()

    # Set up the plotting parameters
    plt.ion()
    plt.show()
    plt.grid(visible=True)
    plt.ylim([-1, 1])
    plt.xlim([data['time'][0], data['time'][-1]])

    line1, = plt.plot([])
    line2, = plt.plot([])

    # Configure labels for axes
    ax = plt.gca()

    # This loops continuously updates the plot with new data
    while True:
        # Get new data
        data = i.get_data()

        # Update the plot
        line1.set_ydata(data['ch1'])
        line2.set_ydata(data['ch2'])
        line1.set_xdata(data['time'])
        line2.set_xdata(data['time'])
        plt.pause(0.001)

except Exception as e:
    print(f'Exception occurred: {e}')
finally:
    # Close the connection to the Moku device
    # This ensures network resources are released correctly
    i.relinquish_ownership()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84

# Logic Analyzer

# logic_analyzer_plotting.py

This example demonstrates how you can configure the Logic Analyzer instrument to retrieve a single frame of data for all 16 channels

#
# moku example: Basic Logic Analyzer
#
# This example demonstrates how to use Pattern Generator in
# Logic Analyzer and generate and observe patterns on DIO pins.
#
# (c) 2022 Liquid Instruments Pty. Ltd.
#

import matplotlib.pyplot as plt
from moku.instruments import LogicAnalyzer

# Connect to your Moku by its ip address using
# LogicAnalyzer('192.168.###.###')
# or by its serial number using LogicAnalyzer(serial=123)
i = LogicAnalyzer('192.168.###.###')

try:

    patterns = [{"pin": 1, "pattern": [1] * 1024},  # logic high
                {"pin": 2, "pattern": [0] * 1024},  # logic low
                {"pin": 3, "pattern": [0, 1] * 512},
                {"pin": 4, "pattern": [1, 0] * 512}]

    i.set_pattern_generator(1, patterns=patterns, divider=8)

    pin_status = [{"pin": 1, "state": "PG1"},
                  {"pin": 2, "state": "PG1"},
                  {"pin": 3, "state": "PG1"},
                  {"pin": 4, "state": "PG1"}]

    i.set_pins(pins=pin_status)
    data = i.get_data(wait_reacquire=True, include_pins=[1, 2, 3, 4])

    pin1, = plt.step(data["time"], data["pin1"])
    pin2, = plt.step(data["time"], [i + 2 for i in data["pin2"]])
    pin3, = plt.step(data["time"], [i + 4 for i in data["pin3"]])
    pin4, = plt.step(data["time"], [i + 6 for i in data["pin4"]])

    plt.ion()
    plt.show()
    plt.grid(True)
    plt.ylim([-1, 8])
    plt.yticks([0, 2, 4, 6], labels=["Pin1", "Pin2", "Pin3", "Pin4"])

    while True:
        data = i.get_data(wait_reacquire=True,
                          include_pins=[1, 2, 3, 4])

        pin1.set_xdata(data["time"])
        pin2.set_xdata(data["time"])
        pin3.set_xdata(data["time"])
        pin4.set_xdata(data["time"])

        pin1.set_ydata(data["pin1"])
        pin2.set_ydata([i + 2 for i in data["pin2"]])
        pin3.set_ydata([i + 4 for i in data["pin3"]])
        pin4.set_ydata([i + 6 for i in data["pin4"]])

        plt.pause(0.001)


except Exception as e:
    raise e
finally:
    # Close the connection to the Moku device
    # This ensures network resources and released correctly
    i.relinquish_ownership()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68

# Multi-instrument Mode

# mim_wg_osc.py

Multi-instrument Mode on Moku:Go (two-slot), deploying the Waveform Generator and Oscilloscope at once. This example is easily ported to Moku:Pro by changing the "platform_id" to one supported by that hardware.

import matplotlib.pyplot as plt

from moku.instruments import MultiInstrument
from moku.instruments import Oscilloscope, WaveformGenerator

m = MultiInstrument('192.168.###.###', platform_id=2)
try:
    wg = m.set_instrument(1, WaveformGenerator)
    osc = m.set_instrument(2, Oscilloscope)

    connections = [dict(source="Input1", destination="Slot1InA"),
                   dict(source="Slot1OutA", destination="Slot2InA"),
                   dict(source="Slot1OutA", destination="Slot2InB"),
                   dict(source="Slot2OutA", destination="Output1")]

    print(m.set_connections(connections=connections))

    wg.generate_waveform(1, "Sine")
    osc.set_timebase(-5e-3, 5e-3)
    data = osc.get_data()

    # Set up the plotting parameters
    plt.ion()
    plt.show()
    plt.grid(b=True)
    plt.ylim([-1, 1])
    plt.xlim([data['time'][0], data['time'][-1]])

    line1, = plt.plot([])
    line2, = plt.plot([])

    # Configure labels for axes
    ax = plt.gca()

    # This loops continuously updates the plot with new data
    while True:
        # Get new data
        data = osc.get_data()

        # Update the plot
        line1.set_ydata(data['ch1'])
        line2.set_ydata(data['ch2'])
        line1.set_xdata(data['time'])
        line2.set_xdata(data['time'])
        plt.pause(0.001)

except Exception as e:
    raise e
finally:
    # Close the connection to the Moku device
    # This ensures network resources and released correctly
    m.relinquish_ownership()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52

# mim_wg_sa.py

Multi-instrumemt Mode on Moku:Go (two slot), deploying the Waveform Generator and Spectrum Analyzer at once. This example is easily ported to Moku:Pro by changing the "platform_id" to one supported by that hardware.

import matplotlib.pyplot as plt

from moku.instruments import MultiInstrument
from moku.instruments import SpectrumAnalyzer, WaveformGenerator

m = MultiInstrument("192.168.###.###", platform_id=2)
try:
    w = m.set_instrument(1, WaveformGenerator)
    s = m.set_instrument(2, SpectrumAnalyzer)

    connections = [dict(source="Input1", destination="Slot1InA"),
                   dict(source="Slot1OutA", destination="Slot2InA")]

    print(m.set_connections(connections=connections))

    w.generate_waveform(1, "Sine", frequency=10e5)
    s.set_span(frequency1=0, frequency2=10e5)
    s.set_rbw('Auto')

    line1, = plt.plot([])
    plt.ion()
    plt.show()
    plt.grid(b=True)
    plt.autoscale(axis='x', tight=True)

    # Get an initial frame of data to set any frame-specific plot parameters
    frame = s.get_data()

    # Format the x-axis as a frequency scale
    ax = plt.gca()

    # Get and update the plot with new data
    while True:
        frame = s.get_data()

        # Set the frame data for each channel plot
        line1.set_ydata(frame['ch1'])
        # Frequency axis shouldn't change, but to be sure
        line1.set_xdata(frame['frequency'])
        # Ensure the frequency axis is a tight fit
        ax.relim()
        ax.autoscale_view()

        # Redraw the lines
        plt.draw()
        plt.pause(0.001)

except Exception as e:
    raise e
finally:
    # Close the connection to the Moku device
    # This ensures network resources and released correctly
    m.relinquish_ownership()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53

# Oscilloscope

# oscilloscope_basic.py

This script demonstrates how to use the Oscilloscope instrument to retrieve a single frame of dual-channel voltage data.

#
# moku example: Basic Oscilloscope
#
# This script demonstrates how to use the Oscilloscope instrument
# to retrieve a single frame of dual-channel voltage data.
#
# (c) 2021 Liquid Instruments Pty. Ltd.
#
from moku.instruments import Oscilloscope

# Connect to your Moku by its ip address using Oscilloscope('192.168.###.###')
# or by its serial number using Oscilloscope(serial=123)
i = Oscilloscope('192.168.###.###', force_connect=False)

try:
    # Set the span to from -1ms to 1ms i.e. trigger point centred
    i.set_timebase(-1e-3, 1e-3)

    # Get and print a single frame  of data (time series
    # of voltage per channel)
    data = i.get_data()
    print(data['ch1'], data['ch2'], data['time'])

except Exception as e:
    print(f'Exception occurred: {e}')
finally:
    # Close the connection to the Moku device
    # This ensures network resources are released correctly
    i.relinquish_ownership()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29

# oscilloscope_plotting.py

This example demonstrates how you can configure the Oscilloscope instrument, and view triggered time-voltage data frames in real-time.

#
# moku example: Plotting Oscilloscope
#
# This example demonstrates how you can configure the Oscilloscope instrument,
# and view triggered time-voltage data frames in real-time.
#
# (c) 2021 Liquid Instruments Pty. Ltd.
#
import matplotlib.pyplot as plt
from moku.instruments import Oscilloscope

# Connect to your Moku by its ip address using Oscilloscope('192.168.###.###')
# or by its serial number using Oscilloscope(serial=123)
i = Oscilloscope('192.168.###.###', force_connect=False)

try:
    # Trigger on input Channel 1, rising edge, 0V 
    i.set_trigger(type='Edge', source='Input1', level=0)

    # View +-5usec, i.e. trigger in the centre
    i.set_timebase(-5e-6, 5e-6)

    # Generate an output sine wave on Channel 1, 1Vpp, 1MHz, 0V offset
    i.generate_waveform(1, 'Sine', amplitude=1, frequency=1e6)

    # Set the data source of Channel 1 to be Input 1
    i.set_source(1, 'Input1')

    # Set the data source of Channel 2 to the generated output sinewave
    i.set_source(2, 'Input2')


    # Get initial data frame to set up plotting parameters. This can be done
    # once if we know that the axes aren't going to change (otherwise we'd do
    # this in the loop)
    data = i.get_data()

    # Set up the plotting parameters
    plt.ion()
    plt.show()
    plt.grid(b=True)
    plt.ylim([-1, 1])
    plt.xlim([data['time'][0], data['time'][-1]])

    line1, = plt.plot([])
    line2, = plt.plot([])

    # Configure labels for axes
    ax = plt.gca()

    # This loops continuously updates the plot with new data
    while True:
        # Get new data
        data = i.get_data()

        # Update the plot
        line1.set_ydata(data['ch1'])
        line2.set_ydata(data['ch2'])
        line1.set_xdata(data['time'])
        line2.set_xdata(data['time'])
        plt.pause(0.001)
        
except Exception as e:
    print(f'Exception occurred: {e}')
finally:
    # Close the connection to the Moku device
    # This ensures network resources and released correctly
    i.relinquish_ownership()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68

# Phasemeter

# phasemeter_basic.py

This example demonstrates how you can configure the Phasemeter instrument to measure 4 independent signals.

#
# moku example: Basic Phasemeter
#
# This example demonstrates how you can configure the Phasemeter
# instrument to measure 4 independent signals.

# (c) 2022 Liquid Instruments Pty. Ltd.
#

from moku.instruments import Phasemeter

# Connect to your Moku by its ip address using Phasemeter('192.168.###.###')
# or by its serial number using Phasemeter(serial=123)
i = Phasemeter('192.168.###.###', force_connect=False)

try:
	# SetChannel 1 and 2 to DC coupled, 1 MOhm impedance, and 400 mVpp range
	i.set_frontend(1, coupling='DC', impedance='1MOhm', range='400mVpp')
	i.set_frontend(2, coupling='DC', impedance='1MOhm', range='400mVpp')
	i.set_frontend(3, coupling='DC', impedance='1MOhm', range='400mVpp')
	i.set_frontend(4, coupling='DC', impedance='1MOhm', range='400mVpp')

	# Configure Output channel 1 to generate sine waves at 1 Vpp, 2 MHz
	i.generate_output(1, 'Sine', amplitude=1, frequency=2e6)
	# Configure Output channel 2 to be phase locked to Input 2 signal at an
	# amplitude of 0.5 Vpp
	i.generate_output(2, 'Sine', amplitude=0.5, phase_locked=True)
	# Configure Output channel 3 and 4 to generate measured phase at a
	# scaling of 1 V/cycle and 10 V/cycle respectively
	i.generate_output(3, 'Phase', scaling=1)
	i.generate_output(4, 'Phase', scaling=10)

	# Set the acquisition speed to 596Hz for all channels
	i.set_acquisition_speed('596Hz')

	# Set all input channels to 2 MHz, bandwidth 100 Hz
	i.set_pm_loop(1, auto_acquire=False, frequency=2e6, bandwidth='100Hz')
	i.set_pm_loop(2, auto_acquire=False, frequency=2e6, bandwidth='100Hz')
	i.set_pm_loop(3, auto_acquire=False, frequency=2e6, bandwidth='100Hz')
	i.set_pm_loop(4, auto_acquire=False, frequency=2e6, bandwidth='100Hz')

	# Get all the data available from the Moku
	data = i.get_data();


except Exception as e:
	print(f'Exception occurred: {e}')
finally:
	# Close the connection to the Moku device
	# This ensures network resources are released correctly
	i.relinquish_ownership()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50

# PID Controller

# pidcontroller_basic.py

This script demonstrates how to configure one of the two PID Controllers in the PID Controller instrument. Configuration is done by specifying frequency response characteristics of the controller.

# moku example: Basic PID Controller
#
# This script demonstrates how to configure one of the two PID Controllers
# in the PID Controller instrument. Configuration is done by specifying
# frequency response characteristics of the controller.
#
# (c) 2022 Liquid Instruments Pty. Ltd.
#

from moku.instruments import PIDController

# Connect to your Moku by its ip address using PIDController('192.168.###.###')
# or by its serial number using PIDController(serial=123)
i = PIDController('192.168.###.###', force_connect=False)

try:
    # Configures the control matrix:
    # Channel 1: input 1 gain = 1 dB, input 2 gain = 0 dB
    # Channel 2: input 2 gain = 0 dB, input 2 gain = 1 dB
    i.set_control_matrix(channel=1, input_gain1=1, input_gain2=0)
    i.set_control_matrix(channel=2, input_gain1=0, input_gain2=1)

    # Configure PID Control loop 1 using frequency response characteristics
    #   P = -10dB
    #   I Crossover = 100Hz
    #   D Crossover = 10kHz
    #   I Saturation = 10dB
    #   D Saturation = 10dB
    #   Double-I = OFF
    i.set_by_frequency(channel=1, prop_gain=-10, int_crossover=1e2,
                       diff_crossover=1e4, int_saturation=10,
                       diff_saturation=10)

    #  Configure PID Control loop 2 using gain 
    #   Proportional gain = 10
    #   Differentiator gain = -5
    #   Differentiator gain corner = 5 kHz
    i.set_by_gain(channel=2, overall_gain=0, prop_gain=10, diff_gain=-5, 
        diff_corner=5e3,)
    
    # Enable the outputs of the PID controller
    i.enable_output(1, signal=True, output=True)
    i.enable_output(2, signal=True, output=True)
    
except Exception as e:
    print(f'Exception occurred: {e}')
finally:
    # Close the connection to the Moku device
    # This ensures network resources and released correctly
    i.relinquish_ownership()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49

# pidcontroller_plotting.py

This script demonstrates how to configure both PID Controllers in the PID Controller instrument. Configuration on the Channel 1 PID is done by specifying frequency response characteristics, while Channel 2 specifies the gain characteristics.

The output response of each PID Controller channel is plotted in real-time.

# moku example: PID Controller Plotting Example
#
# This script demonstrates how to configure both PID Controllers
# in the PID Controller instrument. Configuration on the Channel 1
# PID is done by specifying frequency response characteristics,
# while Channel 2 specifies the gain characteristics.
#
# The output response of each PID Controller channel is plotted
# in real-time.
#
# (c) 2022 Liquid Instruments Pty. Ltd.
#
import matplotlib.pyplot as plt
from moku.instruments import PIDController

# Connect to your Moku by its ip address using PIDController('192.168.###.###')
# or by its serial number using PIDController(serial=123)
i = PIDController('192.168.###.###', force_connect=False)

try:
    # Configures the control matrix:
    # Channel 1: input 1 gain = 1 dB, input 2 gain = 0 dB
    # Channel 2: input 2 gain = 0 dB, input 2 gain = 1 dB
    i.set_control_matrix(channel=1, input_gain1=1, input_gain2=0)
    i.set_control_matrix(channel=2, input_gain1=0, input_gain2=1)

    # Configure the Channel 1 PID Controller using frequency response
    # characteristics
    #   P = -10dB
    #   I Crossover = 100Hz
    #   D Crossover = 10kHz
    #   I Saturation = 10dB
    #   D Saturation = 10dB
    #   Double-I = OFF
    # Note that gains must be converted from dB first
    i.set_by_frequency(channel=1, prop_gain=-10, int_crossover=1e2,
                       diff_crossover=1e4, int_saturation=10,
                       diff_saturation=10)

    # Configure the Channel 2 PID Controller using gain characteristics
    #   Overall Gain = 6dB
    #   I Gain       = 20dB 
    i.set_by_gain(channel=2, overall_gain=6.0, prop_gain=20)

    # Set the probes to monitor Output 1 and Output 2
    i.set_monitor(1, 'Output1')
    i.set_monitor(2, 'Output2')

    # Set the timebase
    i.set_timebase(-1e-3, 1e-3) # +- 1msec
    i.set_trigger(type='Edge', source='ProbeA', level=0)

    # Enable the output channels of the PID controller
    i.enable_output(1, True, True)
    i.enable_output(2, True, True)

    # Get initial data frame to set up plotting parameters. This can be done
    # once if we know that the axes aren't going to change (otherwise we'd do
    # this in the loop)
    data = i.get_data()

    # Set up the plotting parameters
    plt.ion()
    plt.show()
    plt.grid(b=True)
    plt.ylim([-1, 1])
    plt.xlim([data['time'][0], data['time'][-1]])

    line1, = plt.plot([])
    line2, = plt.plot([])

    # Configure labels for axes
    ax = plt.gca()

    # This loops continuously updates the plot with new data
    while True:
        # Get new data
        data = i.get_data()

        # Update the plot
        line1.set_ydata(data['ch1'])
        line2.set_ydata(data['ch2'])
        line1.set_xdata(data['time'])
        line2.set_xdata(data['time'])
        plt.pause(0.001)

except Exception as e:
    print(f'Exception occurred: {e}')
finally:
    # Close the connection to the Moku device
    # This ensures network resources and released correctly
    i.relinquish_ownership()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91

# Programmable Power Supplies

# powersupply_basic.py

This example will demonstrate how to configure the power supply units of the Moku:Go.

#
# moku example: Basic Programmable Power Supply Unit 
#
#  This example will demonstrate how to configure the power supply
#  units of the Moku:Go.
#
# (c) 2021 Liquid Instruments Pty. Ltd.
#
from moku.instruments import Oscilloscope

# Connect to your Moku by its ip address using Oscilloscope('192.168.###.###')
# or by its serial number using Oscilloscope(serial=123)
# An instrument must be deployed to establish the connection with the
# Moku, in this example we will use the Oscilloscope.
i = Oscilloscope('192.168.xxx.xxx', force_connect=False)

try:
    # Configure Power Supply Unit 1 to 2 V and 0.1 A
    i.set_power_supply(1,enable=True,voltage=2, current=0.1)
    
    # Read the current status of Power Supply Unit 1 
    print(i.get_power_supply(1))

except Exception as e:
    print(f'Exception occurred: {e}')
finally:
    # Close the connection to the Moku device
    # This ensures network resources and released correctly
    i.relinquish_ownership()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29

# Spectrum Analyzer

# spectrumanalyzer_basic.py

This example demonstrates how you can use the Spectrum Analyzer instrument to to retrieve a single spectrum data frame over a set frequency span.

#
# moku example: Basic Spectrum Analyzer
#
# This example demonstrates how you can use the Spectrum Analyzer instrument to
# to retrieve a single spectrum data frame over a set frequency span.
#
# (c) 2021 Liquid Instruments Pty. Ltd.
#
from moku.instruments import SpectrumAnalyzer

# Connect to your Moku by its ip address using SpectrumAnalyzer('192.168.###.###')
# or by its serial number using SpectrumAnalyzer(serial=123)
i = SpectrumAnalyzer('192.168.###.###', force_connect=False)

# Deploy the Spectrum Analyzer to your Moku
try:
    # Configure the Spectrum Analyzer 
    i.set_span(0, 10e6)
    i.set_rbw('Auto')  # Auto-mode

    # Get the scan results and print them out (power vs frequency,
    # two channels)
    data = i.get_data()
    print(data['ch1'], data['ch2'], data['frequency'])

except Exception as e:
    print(f'Exception occurred: {e}')
finally:
    # Close the connection to the Moku device
    # This ensures network resources and released correctly
    i.relinquish_ownership()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31

# spectrumanalyzer_plotting.py

This example demonstrates how you can configure the Spectrum Analyzer instrument and plot its spectrum data in real-time.

#
# moku example: Plotting Spectrum Analyzer
#
# This example demonstrates how you can configure the Spectrum Analyzer
# instrument and plot its spectrum data in real-time. 
#
# (c) 2021 Liquid Instruments Pty. Ltd.
#
import logging

import matplotlib.pyplot as plt
from moku.instruments import SpectrumAnalyzer

logging.basicConfig(format='%(asctime)s:%(name)s:%(levelname)s::%(message)s')
logging.getLogger('moku_client').setLevel(logging.INFO)

# Connect to your Moku by its ip address using SpectrumAnalyzer('192.168.###.###')
# or by its serial number using SpectrumAnalyzer(serial=123)
i = SpectrumAnalyzer('192.168.###.###', force_connect=False)

try:
    # Configure the Spectrum Analyzer 
    i.set_span(frequency1=0, frequency2=30e3)
    i.disable_output(1)
    i.set_rbw('Auto')  # Auto-mode
    
    # Configure ADC inputs
    i.set_frontend(1, impedance='1MOhm', coupling='DC', range='10Vpp')
    i.set_frontend(2, impedance='1MOhm', coupling='DC', range='10Vpp')

    # Set up basic plot configurations
    line1, = plt.plot([])
    line2, = plt.plot([])
    plt.ion()
    plt.show()
    plt.grid(b=True)
    plt.ylim([-2, 2])
    plt.autoscale(axis='x', tight=True)

    # Get an initial frame of data to set any frame-specific plot parameters
    frame = i.get_data()

    # Format the x-axis as a frequency scale
    ax = plt.gca()

    # Get and update the plot with new data
    while True:
        frame = i.get_data()
        
        # Set the frame data for each channel plot
        line1.set_ydata(frame['ch1'])
        line2.set_ydata(frame['ch2'])
        # Frequency axis shouldn't change, but to be sure
        line1.set_xdata(frame['frequency'])
        line2.set_xdata(frame['frequency'])
        # Ensure the frequency axis is a tight fit
        ax.relim()
        ax.autoscale_view()

        # Redraw the lines
        plt.draw()
        plt.pause(0.001)

except Exception as e:
    print(f'Exception occurred: {e}')
finally:
    # Close the connection to the Moku device
    # This ensures network resources and released correctly
    i.relinquish_ownership()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70

# Waveform Generator

# waveformgenerator_basic.py

This example demonstrates how you can use the Waveform Generator instrument to generate a sinewave on Channel 1 and a square wave on Channel 2.

#
# moku example: Waveform Generator Basic
#
# This example demonstrates how you can use the Waveform Generator
# instrument to generate a sinewave on Channel 1 and a squarewave on Channel 2.
#
# (c) 2021 Liquid Instruments Pty. Ltd.
#
from moku.instruments import WaveformGenerator

# Connect to your Moku by its ip WaveformGenerator('192.168.###.###')
# or by its serial m = WaveformGenerator(serial=123)
i = WaveformGenerator('192.168.###.###', force_connect=False)

try:
    # Generate a sine wave on channel 1, 0.5 Vpp, 5 kHz
    # Generate a square wave on channel 2, 1 Vpp, 1 kHz, 50% duty cycle
    i.generate_waveform(channel=1, type='Sine', amplitude=0.5, frequency=5e3)
    i.generate_waveform(channel=2, type='Square', amplitude=1.0, frequency=1e3, duty=50)

except Exception as e:
    print(f'Exception occurred: {e}')
finally:
    # Close the connection to the Moku device
    # This ensures network resources and released correctly
    i.relinquish_ownership()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26

# waveformgenerator_modulation.py

This example demonstrates how you can use the Waveform Generator instrument to generate an amplitude modulated sine wave on Channel 1, and a sweep modulated sine wave on Channel 2.

#
# moku example: Waveform Generator Modulation
#
# This example demonstrates how you can use the Waveform Generator instrument
# to generate an amplitude modulated sine wave on Channel 1, and a sweep
# modulated sine wave on Channel 2.
#
# (c) 2021 Liquid Instruments Pty. Ltd.
#
from moku.instruments import WaveformGenerator

# Connect to your Moku by its ip address using WaveformGenerator('192.168.###.###')
# or by its serial number using WaveformGenerator(serial=123)
i = WaveformGenerator('192.168.###.###', force_connect=False)

try:
    # Generate a sine wave on channel 1, 0.5 Vpp, 5 kHz
    # Generate a sine wave on channel 2, 1 Vpp, 1 MHz
    i.generate_waveform(channel=1, type='Sine', amplitude=0.5, frequency=5e3)
    i.generate_waveform(channel=2, type='Sine', amplitude=1.0, frequency=1e6)

    # Configure amplitude modulation on channel 1. 
    # Use internal reference as modulation source, modulation deption 50%, 
    # modulated at a frequency of 1Hz
    i.set_modulation(channel=1, type='Amplitude', source='Internal', depth=50,
                     frequency=1)
    
    # Configure Channel 2 with sweep trigger modulation.
    # Use Input 1 as trigger source, trigger level is 0.1 V. 
    # Start the sweep at waveform frequency 1 MHz and  stop at 10 Hz, each sweep is 3 seconds.
    i.set_sweep_mode(channel=2, source='Input1', stop_frequency=10.0,
                     sweep_time=3.0, trigger_level=0.1)
    
except Exception as e:
    print(f'Exception occurred: {e}')
finally:
    # Close the connection to the Moku device
    # This ensures network resources and released correctly
    i.relinquish_ownership()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39