# 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) Liquid Instruments Pty. Ltd.
#
import numpy as np
from moku.instruments import ArbitraryWaveformGenerator
# Replace with your Moku's IP address.
MOKU_IP = '192.168.###.###'
# Generate a signal that the Arbitrary Waveform Generator 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 the Moku (force_connect will overtake an existing connection).
with ArbitraryWaveformGenerator(MOKU_IP, force_connect=True) as i:
# 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,
)
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
# Moku Compile
# moku_compile_adder.py
This example demonstrates how you can configure your Moku to run the Adder example (opens new window) as a Moku Compile instrument in Multi-Instrument Mode.
#
# moku example: Adder Moku Compile instrument
#
# This example demonstrates how you can configure your Moku to run a Moku Compile
# instrument in Multi-Instrument Mode, which adds and subtracts two input signals
# and outputs the results to the Oscilloscope.
#
# (c) Liquid Instruments Pty. Ltd.
#
import matplotlib.pyplot as plt
from moku.instruments import MokuCompile, MultiInstrument, Oscilloscope
# Replace with your Moku's IP address.
MOKU_IP = '192.168.###.###'
# Connect to the Moku (force_connect will overtake an existing connection).
with MultiInstrument(MOKU_IP, num_slots=2, force_connect=True) as m:
# Set the instruments and upload Moku Compile bitstreams from your device
# to your Moku
bitstream = "path/to/project/adder/bitstreams.tar.gz"
mc = m.set_instrument(1, MokuCompile, bitstream=bitstream)
osc = m.set_instrument(2, Oscilloscope)
# Configure the connections
connections = [
dict(source="Slot1OutA", destination="Slot2InA"),
dict(source="Slot1OutB", destination="Slot2InB"),
dict(source="Slot2OutA", destination="Slot1InA"),
dict(source="Slot2OutB", destination="Slot1InB"),
]
m.set_connections(connections=connections)
# Configure the Oscilloscope to generate a ramp wave and square wave with
# equal frequencies, then sync the phases
osc.generate_waveform(1, 'Square', amplitude=1, frequency=1e3, duty=50)
osc.generate_waveform(2, 'Ramp', amplitude=1, frequency=1e3, symmetry=50)
osc.sync_output_phase()
# Set the time span to cover four cycles of the waveforms
osc.set_timebase(-2e-3, 2e-3)
# Retrieve data
data = osc.get_data()
# Set up the plotting parameters
plt.plot(data['time'], data['ch1'], label='Add')
plt.plot(data['time'], data['ch2'], label='Subtract')
# Configure labels for axes
plt.xlabel("Time [Second]")
plt.ylabel("Amplitude [Volt]")
plt.grid(visible=True)
plt.legend(loc=0)
plt.show()
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
# moku_compile_arithmetic.py
This example demonstrates how you can configure your Moku to run the Arithmetic Unit example (opens new window) as a Moku Compile instrument in Multi-Instrument Mode.
#
# moku example: Arithmetic Moku Compile instrument
#
# This example demonstrates how you can configure your Moku to run a Moku Compile
# instrument that adds, subtracts or multiplies two input signals, selected with
# the control registers, and outputs the result to the Oscilloscope.
#
# (c) Liquid Instruments Pty. Ltd.
#
import matplotlib.pyplot as plt
from moku.instruments import MokuCompile, MultiInstrument, Oscilloscope
# Replace with your Moku's IP address.
MOKU_IP = '192.168.###.###'
# Connect to the Moku (force_connect will overtake an existing connection).
with MultiInstrument(MOKU_IP, num_slots=2, force_connect=True) as m:
# Set the instruments and upload Moku Compile bitstreams from your device
# to your Moku
bitstream = "path/to/project/arithmetic/bitstreams.tar.gz"
mcc = m.set_instrument(1, MokuCompile, bitstream=bitstream)
osc = m.set_instrument(2, Oscilloscope)
# Configure the connections
connections = [
dict(source="Slot1OutA", destination="Slot2InA"),
dict(source="Slot2OutB", destination="Slot2InB"),
dict(source="Slot2OutA", destination="Slot1InA"),
dict(source="Slot2OutB", destination="Slot1InB"),
]
m.set_connections(connections=connections)
# Configure the Oscilloscope to generate a ramp wave and square wave with
# equal frequencies, then sync the phases
osc.generate_waveform(1, 'Square', amplitude=50e-3, frequency=1e3, duty=50)
osc.generate_waveform(2, 'Ramp', amplitude=50e-3, frequency=1e3, symmetry=50)
osc.sync_output_phase()
# Set the time span to cover four cycles of the waveforms
osc.set_timebase(-2e-3, 2e-3)
osc.set_trigger(type="Edge", edge="Rising", level=0, mode="Normal", source="ChannelB")
# Set up the plotting figure
fig, axs = plt.subplots(3, sharex=True)
# Set Control Register 1 to choose to add (0b00), subtract (0b01) or
# multiply (0b10) the input signals
mcc.set_control(1, 0b00)
# Retrieve the data
data = osc.get_data(wait_reacquire=True)
# Plot the result and configure labels for the axes
axs[0].plot(data['time'], data['ch1'], color='r')
axs[0].grid(visible=True)
axs[0].set_title('Add - 0b00')
# Repeat these steps for each option
mcc.set_control(1, 0b01)
data = osc.get_data(wait_reacquire=True)
axs[1].plot(data['time'], data['ch1'], color='b')
axs[1].grid(visible=True)
axs[1].set_ylabel("Amplitude [Volt]")
axs[1].set_title('Subtract - 0b01')
mcc.set_control(1, 0b10)
data = osc.get_data(wait_reacquire=True)
axs[2].plot(data['time'], data['ch1'], color='y')
axs[2].grid(visible=True)
axs[2].set_title('Multiply - 0b10')
# Configure labels for axes
plt.xlabel("Time [Second]")
plt.tight_layout()
plt.show()
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
# 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) Liquid Instruments Pty. Ltd.
#
import os
import time
from moku.instruments import Datalogger
# Replace with your Moku's IP address.
MOKU_IP = '192.168.###.###'
# Connect to the Moku (force_connect will overtake an existing connection).
with Datalogger(MOKU_IP, force_connect=True) as i:
# Configure the frontend
i.set_frontend(channel=1, impedance='1MOhm', coupling="AC", range="10Vpp")
i.set_acquisition_mode(mode='Precision')
# Generate Sine wave on Output1
i.generate_waveform(channel=1, type='Sine', amplitude=1, frequency=10e3)
# Log 100 samples per second
# Stop an existing log, if any, then start a new one. 10 seconds of both
# channels
log_file = i.start_logging(duration=10, sample_rate=100)
# Track progress percentage of the data logging session
complete = False
while complete is False:
# 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()
complete = progress['complete']
if 'time_remaining' in progress:
print(f"Remaining time {progress['time_remaining']} seconds")
# Download log from Moku, use liconverter to convert this .li file to .csv
i.download("persist", log_file['file_name'], os.path.join(os.getcwd(), log_file['file_name']))
print("Downloaded log file to local directory.")
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
# 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) Liquid Instruments Pty. Ltd.
#
import matplotlib.pyplot as plt
from moku.instruments import Datalogger
# Replace with your Moku's IP address.
MOKU_IP = '192.168.###.###'
# Connect to the Moku (force_connect will overtake an existing connection).
with Datalogger(MOKU_IP, force_connect=True) as i:
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.enable_input(2, enable=False)
# set the sample rate to 10KSa/s
# stream the data for 10 seconds..
i.start_streaming(duration=10, sample_rate=10e3)
# Set up the plotting parameters
plt.ion()
plt.show()
plt.grid(visible=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:
if str(e) == "End of stream":
print("Streaming session complete!")
else:
i.stop_streaming()
raise
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
# 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) Liquid Instruments Pty. Ltd.
#
import matplotlib.pyplot as plt
from moku.instruments import LockInAmp
# Replace with your Moku's IP address.
MOKU_IP = '192.168.###.###'
# Connect to the Moku (force_connect will overtake an existing connection).
with LockInAmp(MOKU_IP, force_connect=True) as i:
try:
# Set Channel 1 and 2 to DC coupled, 1 MOhm impedance, and
# 400 mVpp range (on Moku:Pro)
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='6dB')
# 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:
if str(e) == "End of stream":
print("Streaming session complete!")
else:
i.stop_streaming()
raise
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
# 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
# Replace with your Moku's IP address.
MOKU_IP = '192.168.###.###'
# Connect to the Moku (force_connect will overtake an existing connection).
with MultiInstrument(MOKU_IP, num_slots=2, force_connect=True) as i:
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(duration=10, sample_rate=100)
dl.stream_to_file()
lia.set_monitor(1, "Input1")
lia.start_streaming(duration=10, rate=1e3)
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 = 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:
if str(e) == "End of stream":
print("Streaming session complete!")
else:
raise
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
# Digital Filter Box
# digital_filter_box_plotting.py
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) Liquid Instruments Pty. Ltd.
#
import matplotlib.pyplot as plt
from moku import MokuException
from moku.instruments import DigitalFilterBox
# Replace with your Moku's IP address.
MOKU_IP = '192.168.###.###'
# Connect to the Moku (force_connect will overtake an existing connection).
with DigitalFilterBox(MOKU_IP, force_connect=True) as i:
try:
# Set Channel 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.91 MSa/s is for Moku:Go
# Please change sampling rate for other Moku devices.
i.set_filter(1, "3.91MSa/s", shape="Lowpass", type="Butterworth", low_corner=1e3, order=8)
i.set_filter(2, "3.91MSa/s", 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], loc=1)
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:
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
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
# 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) Liquid Instruments Pty. Ltd.
#
from moku.instruments import FrequencyResponseAnalyzer
# Replace with your Moku's IP address.
MOKU_IP = '192.168.###.###'
# Connect to the Moku (force_connect will overtake an existing connection).
with FrequencyResponseAnalyzer(MOKU_IP, force_connect=True) as i:
# 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(wait_complete=True)
# 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'])
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
# 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) Liquid Instruments Pty. Ltd.
#
import matplotlib.pyplot as plt
from moku.instruments import FrequencyResponseAnalyzer
# Replace with your Moku's IP address.
MOKU_IP = '192.168.###.###'
# 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
# Connect to the Moku (force_connect will overtake an existing connection).
with FrequencyResponseAnalyzer(MOKU_IP, force_connect=True) as i:
# 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)')
ax_1.grid(True)
# 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 (degrees)')
ax_2.grid(True)
plt.ion()
plt.show()
# 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)
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
# GenInst
# geninst_oscilloscope.py
This example demonstrates how you can configure GenInst using Multi-Instrument Mode and output the result to the Oscilloscope.
#
# moku example: GenInst
#
# This example demonstrates how you can configure GenInst using
# Multi-Instrument Mode and output the result to the Oscilloscope.
# This example is written for Moku:Pro and can be changed for
# other devices.
# (c) Liquid Instruments Pty Ltd
#
import matplotlib.pyplot as plt
from moku.instruments import GenInst, MultiInstrument, Oscilloscope
# Replace with your Moku's IP address.
MOKU_IP = '192.168.###.###'
# Connect to the Moku (force_connect will overtake an existing connection).
# Change num_slots to:
# - 3, 5 or 8 for Moku:Delta, or
# - 4 for Moku:Pro, or
# - 2 or 3 for Moku:Lab and Moku:Go.
with MultiInstrument(MOKU_IP, num_slots=4, force_connect=True) as m:
# Set the instruments and upload GenInst bitstreams from your device
# to your Moku
bitstream = "path/to/geninst/bitstreams"
gi = m.set_instrument(1, GenInst, bitstream=bitstream)
osc = m.set_instrument(2, Oscilloscope)
# Configure the connections
connections = [
dict(source="Slot1OutA", destination="Slot2InA"),
dict(source="Slot1OutB", destination="Slot2InB"),
dict(source="Slot2OutA", destination="Slot1InA"),
dict(source="Slot2OutB", destination="Slot1InB"),
]
m.set_connections(connections=connections)
# Set Control Registers as per the GenInst design plan
# Setting a single control register
gi.set_control(1, 0b00)
# Setting multiple control registers
controls = [
{"idx": 0, "value": 32836},
{"idx": 1, "value": 450},
{"idx": 2, "value": 32},
{"idx": 3, "value": 2048},
{"idx": 4, "value": 2147450879},
]
gi.set_controls(controls)
# Configure the Oscilloscope to generate different waveforms
osc.generate_waveform(1, 'Sine', amplitude=1, frequency=1e3)
osc.generate_waveform(2, 'Sine', amplitude=0.1, frequency=500)
# Sync the phase between the waveforms
osc.sync_output_phase()
# Set the time span to cover four cycles of the waveforms
osc.set_timebase(-2e-3, 2e-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 = osc.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 = osc.get_data()
# Update the plot
line1.set_ydata(data['ch1']) # Streamed data from Gigabit Streamer in Slot 1 (blue)
line1.set_xdata(data['time'])
line2.set_ydata(data['ch2']) # Signal generated in Oscilloscope in loopback (orange)
line2.set_xdata(data['time'])
plt.pause(0.001)
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
# Gigabit Streamer
# gigabit_streamer_plotting.py
This example demonstrates how you can stream on a Moku in loopback, receiving and transmitting data using Moku Gigabit Streamer, using the Oscilloscope to generate and view the data in real-time.
#
# moku example: Gigabit Streamer
#
# This example demonstrates how you can stream on a Moku in loopback,
# receiving and transmitting data using Moku Gigabit Streamer, using
# the Oscilloscope to generate and view the data in real-time.
#
# Connect a SFP cable in loopback from SFP1 to SFP2, to allow
#
# | Slot 1 | Slot 2 | Slot 3 |
# | gs1 | osc | gs2 |
# | rx | gen and | tx |
# | from SFP1 | view signal | to SFP2 |
#
#
# (c) Liquid Instruments Pty. Ltd.
#
import matplotlib.pyplot as plt
from moku.instruments import GigabitStreamer, MultiInstrument, Oscilloscope
# Replace with your Moku's IP address.
MOKU_IP = '192.168.###.###'
# Connect to the Moku (force_connect will overtake an existing connection).
with MultiInstrument(MOKU_IP, force_connect=True, num_slots=3) as m:
# Set up Gigabit Streamer and Oscilloscope instruments
gs1 = m.set_instrument(1, GigabitStreamer) # Receiving Gigabit Streamer
osc = m.set_instrument(2, Oscilloscope) # Oscilloscope
gs2 = m.set_instrument(3, GigabitStreamer) # Transmitting Gigabit Streamer
# Set up connections between the instruments
# The Oscilloscope is connected to output to Gigabit Streamer in Slot 1 and read back
# from Gigabit Streamer in Slot 3. Anytime a Gigabit Streamer instrument is connected
# to Slot 1 it is transmitting and receiving data from SFP1.
# Anytime a Gigabit streamer instrument is connected to Slot 2 it is transmitting
# and receiving data from SFP2.
connections = [
dict(source="Slot1OutA", destination="Slot2InA"),
dict(source="Slot2OutA", destination="Slot2InB"),
dict(source="Slot2OutA", destination="Slot3InA"),
]
m.set_connections(connections)
# Configure the Oscilloscope to generate and view the signal in real-time
# Generate a 1 MHz sine wave, set the trigger and timebase to view signal
osc.generate_waveform(channel=1, type="Sine", amplitude=1, frequency=1e6, offset=0, phase=0)
osc.set_trigger(type='Edge', source='ChannelA', level=0)
osc.set_timebase(t1=-5e-6, t2=5e-6)
# Set up the receiving Gigabit Streamer instrument
#########################################################
# Configure the acquisition settings
gs1.enable_input(channel=1, enable=True)
gs1.enable_input(channel=2, enable=True)
gs1.set_acquisition(mode='Normal', sample_rate=156.25e6)
gs1.set_interpolation(mode='Linear')
# Configure the local and remote network settings
gs1.set_local_network(ip_address="10.10.1.1", port=5000)
# Get the MAC address of Gigabit Streamer 2 (connected to SFP2)
gs2_mac = gs2.set_local_network(ip_address="10.10.1.2", port=5000)["mac_address"]
gs1.set_remote_network(ip_address="10.10.1.2", port=5000, mac_address=gs2_mac)
gs1.set_outgoing_packets(mtu="1500bytes")
# Set up the transmitting Gigabit Streamer instrument
#########################################################
# Configure the acquisition settings
gs2.enable_input(channel=1, enable=True)
gs2.enable_input(channel=2, enable=False)
gs2.set_acquisition(mode='Normal', sample_rate=156.25e6)
gs2.set_interpolation(mode='Linear')
# Configure the local and remote network settings
gs2.set_local_network(ip_address="10.10.1.2", port=5000)
# Get the MAC address of Gigabit Streamer 1 (connected to SFP1)
gs1_mac = gs1.set_local_network(ip_address="10.10.1.1", port=5000)["mac_address"]
gs2.set_remote_network(ip_address="10.10.1.1", port=5000, mac_address=gs1_mac)
gs2.set_outgoing_packets(mtu="1500bytes")
# Enable outputs and start sending data
gs1.set_output(channel=1, enable=True, gain=0.0, offset=0.0)
gs1.set_output(channel=2, enable=False, gain=0.0, offset=0.0)
gs2.set_output(channel=1, enable=True, gain=0.0, offset=0.0)
gs2.set_output(channel=2, enable=False, gain=0.0, offset=0.0)
# Immediately start sending data for 10 seconds
gs1.start_sending(mode="Manual", duration=10)
gs2.start_sending(mode="Manual", duration=10)
# 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 = osc.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 = osc.get_data()
# Update the plot
line1.set_ydata(data['ch1']) # Streamed data from Gigabit Streamer in Slot 1 (blue)
line1.set_xdata(data['time'])
line2.set_ydata(data['ch2']) # Signal generated in Oscilloscope in loopback (orange)
line2.set_xdata(data['time'])
plt.pause(0.001)
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
116
117
118
# Gigabit Streamer+
# gigabit_streamer_plus_basic.py
This example demonstrates how to transmit and receive data using Moku Gigabit Streamer+ in single instrument mode.
# Gigabit Streamer+ Example
#
# This example demonstrates how to transmit and receive data using
# Moku Gigabit Streamer+ in single instrument mode.
#
# (c) Liquid Instruments Pty. Ltd.
from moku.instruments import GigabitStreamerPlus
# Replace with your Moku's IP address.
MOKU_IP = '192.168.###.###'
# Connect to the Moku (force_connect will overtake an existing connection).
with GigabitStreamerPlus(MOKU_IP, force_connect=True) as i:
# Set up the Gigabit Streamer+ inputs
i.enable_input(channel=1, enable=True)
i.enable_input(channel=2, enable=True)
i.enable_input(channel=3, enable=True)
i.enable_input(channel=4, enable=True)
# Acquisition / interpolation
i.set_acquisition(mode="Normal", sample_rate=1.25e9)
i.set_interpolation(mode="Linear")
# Analog frontend settings
i.set_frontend(channel=1, impedance="50Ohm", coupling="DC", gain="0dB")
i.set_frontend(channel=2, impedance="50Ohm", coupling="DC", gain="0dB")
i.set_frontend(channel=3, impedance="50Ohm", coupling="DC", gain="0dB")
i.set_frontend(channel=4, impedance="50Ohm", coupling="DC", gain="0dB")
# Configure the local and remote network settings
i.set_local_network(ip_address="10.10.1.1", port=5000)
# Find host or configure the host IP address, UDP port, and MAC address
i.set_remote_network(ip_address="192.168.XXX.XXX", port=5000, mac_address="A1:B2:C3:XX:XX:XX")
i.set_outgoing_packets(mtu="1500bytes")
# Enable outputs (channel, enable, gain, offset)
i.set_output(channel=1, enable=True, gain=0.0, offset=0.0)
i.set_output(channel=2, enable=True, gain=0.0, offset=0.0)
i.set_output(channel=3, enable=True, gain=0.0, offset=0.0)
i.set_output(channel=4, enable=True, gain=0.0, offset=0.0)
# Print a summary of the instrument configuration
print(i.summary())
# Immediately start sending data for 10 seconds
i.start_sending(mode="Manual", duration=10)
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
# 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) Liquid Instruments Pty. Ltd.
#
from moku.instruments import LaserLockBox
# Replace with your Moku's IP address.
MOKU_IP = '192.168.###.###'
# Connect to the Moku (force_connect will overtake an existing connection).
with LaserLockBox(MOKU_IP, force_connect=True) as i:
# Set Channel 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
# integrator 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
# integrator crossover frequency at 50 Hz
i.set_pid_by_frequency(2, -10, int_crossover=50)
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
# 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) Liquid Instruments Pty. Ltd.
#
import matplotlib.pyplot as plt
from moku.instruments import LaserLockBox
# Replace with your Moku's IP address.
MOKU_IP = '192.168.###.###'
# Connect to the Moku (force_connect will overtake an existing connection).
with LaserLockBox(MOKU_IP, force_connect=True) as i:
# Set Channel 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
# integrator 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
# integrator 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)
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
# 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) Liquid Instruments Pty. Ltd.
#
from moku.instruments import LockInAmp
# Replace with your Moku's IP address.
MOKU_IP = '192.168.###.###'
# Connect to the Moku (force_connect will overtake an existing connection).
with LockInAmp(MOKU_IP, force_connect=True) as i:
# Set Channel 1 and 2 to DC coupled, 1 MOhm impedance, and 400 mVpp range (on Moku:Pro)
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='6dB')
# 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)
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
# 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) Liquid Instruments Pty. Ltd.
#
import matplotlib.pyplot as plt
from moku.instruments import LockInAmp
# Replace with your Moku's IP address.
MOKU_IP = '192.168.###.###'
# Connect to the Moku (force_connect will overtake an existing connection).
with LockInAmp(MOKU_IP, force_connect=True) as i:
# Set Channel 1 to DC coupled, 1 MOhm impedance, and 400 mVpp range (on Moku:Pro)
i.set_frontend(1, coupling='DC', impedance='1MOhm', gain='0dB')
# Set Channel 2 to DC coupled, 1 MOhm impedance, and 4 Vpp range (on Moku:Pro)
i.set_frontend(2, coupling='DC', impedance='1MOhm', gain='-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='6dB')
# 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)
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
# 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) Liquid Instruments Pty. Ltd.
#
import matplotlib.pyplot as plt
from moku.instruments import LogicAnalyzer
# Replace with your Moku's IP address.
MOKU_IP = '192.168.###.###'
# Connect to the Moku (force_connect will overtake an existing connection).
with LogicAnalyzer(MOKU_IP, force_connect=True) as i:
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)
i.set_pin_mode(pin=1, state="PG1")
i.set_pin_mode(pin=2, state="PG1")
i.set_pin_mode(pin=3, state="PG1")
i.set_pin_mode(pin=4, state="PG1")
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)
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
# 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 "num_slots" to one supported by that hardware.
import matplotlib.pyplot as plt
from moku.instruments import MultiInstrument, Oscilloscope, WaveformGenerator
# Replace with your Moku's IP address.
MOKU_IP = '192.168.###.###'
# Connect to the Moku (force_connect will overtake an existing connection).
with MultiInstrument(MOKU_IP, num_slots=2, force_connect=True) as m:
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(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 = 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)
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
# mim_wg_sa.py
Multi-instrument 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 "num_slots" to one supported by that hardware.
import matplotlib.pyplot as plt
from moku.instruments import MultiInstrument, SpectrumAnalyzer, WaveformGenerator
# Replace with your Moku's IP address.
MOKU_IP = '192.168.###.###'
# Connect to the Moku (force_connect will overtake an existing connection).
with MultiInstrument(MOKU_IP, num_slots=2, force_connect=True) as m:
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(visible=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)
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
# mim_wg_rtm_osc.py
Multi-instrument Mode on a three-slot platform, deploying the Waveform Generator,
Real Time Math and Oscilloscope at once. Real Time Math applies a gain with an
output limit, and an offset, to the generated sine wave. Use num_slots=4
on Moku:Pro.
# Multi-instrument Waveform Generator, Real Time Math and Oscilloscope example
#
# This example demonstrates the Real Time Math (RTM) instrument in
# Multi-Instrument Mode. A Waveform Generator in slot 1 drives RTM in slot 2,
# and an Oscilloscope in slot 3 shows the two RTM outputs:
# - Output A: the signal amplified by 6 dB, with the output limited to +/-0.5 V
# - Output B: the signal with 0.25 V added to it
#
# (c) Liquid Instruments Pty. Ltd.
import matplotlib.pyplot as plt
from moku.instruments import MultiInstrument, Oscilloscope, RealTimeMath, WaveformGenerator
# Replace with your Moku's IP address.
MOKU_IP = '192.168.###.###'
# RTM only runs in Multi-Instrument Mode. This example uses three slots, so use
# 3 for Moku:Go, Moku:Lab and Moku:Delta, or 4 for Moku:Pro.
NUM_SLOTS = 3
# Connect to the Moku (force_connect will overtake an existing connection).
with MultiInstrument(MOKU_IP, num_slots=NUM_SLOTS, force_connect=True) as m:
wg = m.set_instrument(1, WaveformGenerator)
rtm = m.set_instrument(2, RealTimeMath)
osc = m.set_instrument(3, Oscilloscope)
# Waveform Generator -> RTM -> Oscilloscope
connections: list[MultiInstrument.Connection] = [
{"source": "Slot1OutA", "destination": "Slot2InA"},
{"source": "Slot2OutA", "destination": "Slot3InA"},
{"source": "Slot2OutB", "destination": "Slot3InB"},
]
m.set_connections(connections=connections)
# A 1 Vpp, 10 kHz sine wave
wg.generate_waveform(1, "Sine", amplitude=1, frequency=10e3)
# Each RTM output channel applies a function to the input signals.
# Output A: gain of 6 dB (about x2), limited to +/-0.5 V so the peaks are clipped
rtm.set_node(channel=1, column=1, input_a=1, function="Gain", gain=6)
rtm.set_output_limit(channel=1, enable=True, low_limit=-0.5, high_limit=0.5)
# Output B: add a 0.25 V offset to the signal
rtm.set_node(channel=2, column=1, input_a=1, function="Offset", offset=0.25)
# Print the RTM configuration
print(rtm.summary())
# View both outputs on the oscilloscope
osc.set_timebase(-0.5e-3, 0.5e-3)
data = osc.get_data()
plt.plot(data['time'], data['ch1'], label="RTM output A (gain, limited)")
plt.plot(data['time'], data['ch2'], label="RTM output B (offset)")
plt.grid(visible=True)
plt.xlabel("Time (s)")
plt.ylabel("Amplitude (V)")
plt.legend()
plt.show()
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
# Neural Network
# neuralnetwork_simplesine.py
This script demonstrates how to use the Neural Network instrument to generate a ramp wave and process it through the uploaded neural network, finally viewing the output in the oscilloscope. This uses the network generated in the Simple Sine wave example (opens new window)
#
# moku example: Neural Network
#
# This script demonstrates how to use the Neural Network instrument to generate
# a ramp wave and process it through the uploaded neural network, finally
# viewing the output in the oscilloscope. This uses the network generated
# in the Simple Sine wave example.
#
# (c) Liquid Instruments Pty. Ltd.
import matplotlib.pyplot as plt
from moku.instruments import MultiInstrument, NeuralNetwork, Oscilloscope, WaveformGenerator
# Replace with your Moku's IP address.
MOKU_IP = '192.168.###.###'
# Connect to the Moku (force_connect will overtake an existing connection).
with MultiInstrument(MOKU_IP, num_slots=4, force_connect=True) as m:
# Set up MiM configuration
wg = m.set_instrument(1, WaveformGenerator)
nn = m.set_instrument(2, NeuralNetwork)
osc = m.set_instrument(3, Oscilloscope)
connections = [
dict(source="Slot1OutA", destination="Slot2InA"),
dict(source="Slot1OutA", destination="Slot2InB"),
dict(source="Slot1OutB", destination="Slot2InC"),
dict(source="Slot1OutB", destination="Slot2InD"),
dict(source="Slot2OutA", destination="Slot3InA"),
]
print(m.set_connections(connections=connections))
# Generate ramp wave in Waveform Generator
wg.generate_waveform(channel=1, type='Ramp', amplitude=0.25, frequency=5e3, symmetry=100)
print(wg.summary())
# Load network into Neural Network and set inputs and outputs
nn.set_input(strict=False, channel=1, low_level=-1, high_level=1)
nn.set_input_sample_rate(sample_rate=305000)
nn.upload_network("/path/to/simple_sine_model.linn")
nn.set_output(strict=False, channel=1, enabled=True, low_level=-1, high_level=1)
print(nn.summary())
# Set up Oscilloscope for plotting
osc.set_timebase(-5e-3, 5e-3)
data = osc.get_data()
print(osc.summary())
# 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]])
(line,) = 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
line.set_ydata(data['ch1'])
line.set_xdata(data['time'])
plt.pause(0.001)
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
# 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) Liquid Instruments Pty. Ltd.
#
from moku.instruments import Oscilloscope
# Replace with your Moku's IP address.
MOKU_IP = '192.168.###.###'
# Connect to the Moku (force_connect will overtake an existing connection).
with Oscilloscope(MOKU_IP, force_connect=True) as i:
# 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'])
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# 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) Liquid Instruments Pty. Ltd.
#
import matplotlib.pyplot as plt
from moku.instruments import Oscilloscope
# Replace with your Moku's IP address.
MOKU_IP = '192.168.###.###'
# Connect to the Moku (force_connect will overtake an existing connection).
with Oscilloscope(MOKU_IP, force_connect=True) as i:
# 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(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)
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
# oscilloscope_deep_memory_mode.py
This example demonstrates how to acquire data using the deep memory mode in the Moku Oscilloscope.
## Example: Data Acquisition with Deep Memory Mode in the Moku Oscilloscope
#
# This example demonstrates how to acquire data using the deep memory mode in the Moku Oscilloscope.
#
# The 'save_high_res_buffer' command stores high-resolution channel buffer data in Moku's internal storage.
#
# Ensure that deep memory mode is enabled using the 'set_acquisition_mode' command before exporting high-res data.
#
# Logged data files can be retrieved from the following storage locations:
# - 'persist' for Moku:Go
# - 'tmp' for Moku:Lab
# - 'ssd' for Moku:Pro
# - 'ssd' for Moku:Delta
# Update the 'download' command accordingly to match the correct storage location.
#
# The parameters in the 'set_frontend' command should be configured to align with the specific hardware (Moku:Go, Moku:Lab, Moku:Pro, or Moku:Delta).
import os
import time
import matplotlib.pyplot as plt
import numpy as np
from moku.instruments import Oscilloscope
# Replace with your Moku's IP address.
MOKU_IP = '192.168.###.###'
NUM_FRAMES = 1 # This is the number of frames to be averaged
FILE_PATH = "C:/Users/XXXX/Downloads" # Please replace with your own FILE_PATH
# Connect to the Moku (force_connect will overtake an existing connection).
with Oscilloscope(MOKU_IP, force_connect=True) as i:
# Set the data source of Channel 1 to be Input 1
i.set_frontend(1, '50Ohm', 'DC', '400mVpp')
i.set_sources(
[
{"channel": 1, "source": "Input1"},
{"channel": 2, "source": "None"},
{"channel": 3, "source": "None"},
{"channel": 4, "source": "None"},
]
)
i.set_trigger(mode='Normal', type='Edge', source='Input1', level=0)
i.set_timebase(-5e-3, 20e-3)
i.set_acquisition_mode('DeepMemory')
print(i.get_samplerate())
for iter in range(NUM_FRAMES):
i.get_data(wait_reacquire=True, wait_complete=True)
response = i.save_high_res_buffer(comments="Triggered")
file_name = response["file_name"]
temp_filename = FILE_PATH + "/high_res_data-" + time.strftime('%d-%m-%Y-%H_%M_%S')
i.download("ssd", file_name, temp_filename + ".li")
os.system("mokucli convert --format=npy " + temp_filename + ".li")
file = np.load(temp_filename + ".npy")
data_ch1 = file['Channel A (V)']
if iter == 0:
ch1 = data_ch1
else:
ch1 = ch1 + data_ch1
# (Optional) Delete the downloaded and converted files
os.remove(temp_filename + ".npy")
os.remove(temp_filename + ".li")
os.remove(temp_filename + ".txt")
time_column = file['Time (s)']
# plot the average of all acquired high-res frames
plt.plot(time_column, ch1 / NUM_FRAMES)
plt.grid(visible=True)
# Configure labels and ranges for axes
ax = plt.gca()
ax.set_xlim((time_column[0], time_column[-1]))
ax.set_ylim((-1, 1))
ax.set_xlabel("Time (s)")
ax.set_ylabel("Voltage (V)")
plt.show()
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
# 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) Liquid Instruments Pty. Ltd.
#
from moku.instruments import Phasemeter
# Replace with your Moku's IP address.
MOKU_IP = '192.168.###.###'
# Connect to the Moku (force_connect will overtake an existing connection).
with Phasemeter(MOKU_IP, force_connect=True) as i:
# Set Channel 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, output_range='10Vpp')
i.generate_output(4, 'Phase', scaling=10, output_range='10Vpp')
# 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()
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
# phasemeter_plotting.py
This example demonstrates how you can configure the Phasemeter instrument to measure 2 independent signals and display the results in real-time.
#
# moku example: Plotting Phasemeter
#
# This example demonstrates how you can configure the Phasemeter instrument
# and collect live samples from it's output.
# The signal amplitude is calculated using these samples, and plotted for
# real-time viewing.
#
# (c) Liquid Instruments Pty. Ltd.
#
from time import time
import matplotlib.pyplot as plt
import numpy as np
from moku.instruments import Phasemeter
# Replace with your Moku's IP address.
MOKU_IP = '192.168.###.###'
# Connect to the Moku (force_connect will overtake an existing connection).
with Phasemeter(MOKU_IP, force_connect=True) as i:
# Set Channel 1 and 2 to DC coupled, 1 MOhm impedance, and 4Vpp range
i.set_frontend(1, coupling="DC", impedance="1MOhm", range="4Vpp")
i.set_frontend(2, coupling="DC", impedance="1MOhm", range="4Vpp")
# Configure output channel 1 to generate sine waves at 0.5Vpp, 5 MHz
i.generate_output(1, "Sine", amplitude=0.5, frequency=5e6)
# Configure output channel 2 to generate sine waves at 1Vpp, 10 MHz
i.generate_output(2, "Sine", amplitude=1, frequency=10e6)
# Get initial data frame to set plot bounds
data = i.get_data()
# Set plot bounds
plt.ion()
plt.show()
plt.grid(True)
plt.ylabel("Amplitude (Vrms)")
plt.xlabel("Time (s)")
plt.xlim((-20, 0))
(line1,) = plt.plot([])
(line2,) = plt.plot([])
timestamps = []
ydata1 = []
ydata2 = []
# Configure labels for axes
ax = plt.gca()
# This loop continuously updates the plot with new data
while True:
# Get new data
data = i.get_data()
# Update the x- to mimic the Moku App traces
# Append the current timestamp then normalize by the current time
# so that now is t = 0s
t_now = time()
timestamps += [t_now]
xdata = np.array(timestamps) - t_now
# Update the plot
ydata1 += [data["ch1"]["amplitude"]]
ydata2 += [data["ch2"]["amplitude"]]
line1.set_ydata(ydata1)
line2.set_ydata(ydata2)
line1.set_xdata(xdata)
line2.set_xdata(xdata)
ax.relim()
ax.autoscale_view()
plt.pause(0.001)
plt.draw()
# Ensure data is maintained to a reasonable length of 1000 points
# This will cover more than the 20 second x-axis limit
timestamps = timestamps[-1000:]
ydata1 = ydata1[-1000:]
ydata2 = ydata2[-1000:]
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
# phasemeter_streaming.py
This example demonstrates how you can configure the Phasemeter instrument to measure a signal, stream and display the results.
#
# moku example: Phasemeter networking streaming
#
# This example starts a 30-second network stream of Channel 1 Phasemeter data
# and processes it live. The contents of each data sample are printed out,
# along with the signal amplitude which may be calculated as A = sqrt(I^2 + Q^2).
#
# (c) Liquid Instruments Pty. Ltd.
#
import matplotlib.pyplot as plt
import numpy as np
from moku.instruments import Phasemeter
# Replace with your Moku's IP address.
MOKU_IP = '192.168.###.###'
# Connect to the Moku (force_connect will overtake an existing connection).
with Phasemeter(MOKU_IP, force_connect=True) as i:
try:
# Set channel 1 to DC coupled, 1 MOhm impedance, and 4Vpp range
i.set_frontend(1, coupling='DC', impedance='1MOhm', range='4Vpp')
# Set auto acquired frequency for channel 1
i.set_pm_loop(channel=1, auto_acquire=True, bandwidth='1kHz')
# Get the auto-acquired frequency for channel 1. get_data isn't
# available while streaming, so call it before streaming starts.
print(i.get_data()['ch1']['setpoint_frequency'])
# Set the acquisition rate to 149 Sa/s
# Stop any existing streaming session and start a new one for 30s
i.stop_streaming()
i.start_streaming(duration=30, acquisition_rate='149Sa/s')
# Set up the figure for plotting
plt.ion()
fig, axs = plt.subplots(3, 1, sharex=True)
plt.show()
for ax in axs:
ax.grid(True)
ax.set_xlim(0, 30)
(f_ax, a_ax, p_ax) = axs
f_ax.set_ylabel("Frequency (Hz)")
a_ax.set_ylabel("Amplitude (Vrms)")
p_ax.set_ylabel("Phase (cyc)")
p_ax.set_xlabel("Time (s)")
(line1,) = f_ax.plot([])
(line2,) = f_ax.plot([])
(line3,) = a_ax.plot([])
(line4,) = p_ax.plot([])
f_ax.legend(labels=("Frequency", "Set Frequency"), loc=1)
time_span = []
frequency = []
set_freq_ = []
amplitude = []
phase_cyc = []
# This loop continuously updates the plot with new data
while True:
# Get stream data
data = i.get_stream_data()
# Update the plot
time_span += data['time']
frequency += data['ch1_frequency']
set_freq_ += data['ch1_set_frequency']
amplitude += list(np.sqrt(np.array(data['ch1_i']) ** 2 + np.array(data['ch1_q']) ** 2))
phase_cyc += data['ch1_phase']
line1.set_data(time_span, frequency)
line2.set_data(time_span, set_freq_)
line3.set_data(time_span, amplitude)
line4.set_data(time_span, phase_cyc)
for ax in axs:
ax.relim()
ax.autoscale_view()
plt.pause(0.01)
except Exception as e:
if str(e) == "End of stream":
print("Streaming session complete!")
else:
i.stop_streaming()
raise
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
# 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) Liquid Instruments Pty. Ltd.
#
from moku.instruments import PIDController
# Replace with your Moku's IP address.
MOKU_IP = '192.168.###.###'
# Connect to the Moku (force_connect will overtake an existing connection).
with PIDController(MOKU_IP, force_connect=True) as i:
# 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)
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
# 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) Liquid Instruments Pty. Ltd.
#
import matplotlib.pyplot as plt
from moku.instruments import PIDController
# Replace with your Moku's IP address.
MOKU_IP = '192.168.###.###'
# Connect to the Moku (force_connect will overtake an existing connection).
with PIDController(MOKU_IP, force_connect=True) as i:
# 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) # +- 1ms
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(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)
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) Liquid Instruments Pty. Ltd.
#
from moku.instruments import Oscilloscope
# Replace with your Moku's IP address.
MOKU_IP = '192.168.###.###'
# Connect to the Moku (force_connect will overtake an existing connection).
# An instrument must be deployed to establish the connection with the
# Moku, in this example we will use the Oscilloscope.
with Oscilloscope(MOKU_IP, force_connect=True) as i:
# 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))
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# 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) Liquid Instruments Pty. Ltd.
#
from moku.instruments import SpectrumAnalyzer
# Replace with your Moku's IP address.
MOKU_IP = '192.168.###.###'
# Connect to the Moku (force_connect will overtake an existing connection).
with SpectrumAnalyzer(MOKU_IP, force_connect=True) as i:
# Deploy the Spectrum Analyzer to your Moku
# 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'])
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# 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) Liquid Instruments Pty. Ltd.
#
import logging
import matplotlib.pyplot as plt
from moku.instruments import SpectrumAnalyzer
# Replace with your Moku's IP address.
MOKU_IP = '192.168.###.###'
logging.basicConfig(format='%(asctime)s:%(name)s:%(levelname)s::%(message)s')
logging.getLogger('moku_client').setLevel(logging.INFO)
# Connect to the Moku (force_connect will overtake an existing connection).
with SpectrumAnalyzer(MOKU_IP, force_connect=True) as i:
# 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(visible=True)
plt.ylim([-120, 20])
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)
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
# Time and Frequency Analyzer
# timefrequencyanalyzer_basic.py
This example demonstrates how you can use the Time and Frequency Analyzer instrument to to retrieve and view the statistics of the intervals.
#
# moku example: Plotting Time and Frequency Analyzer
#
# This example demonstrates how you can configure the Time and Frequency Analyzer
# instrument, and view the statistics of the intervals.
#
# (c) Liquid Instruments Pty. Ltd.
#
from pprint import pprint
from moku.instruments import TimeFrequencyAnalyzer
# Replace with your Moku's IP address.
MOKU_IP = '192.168.###.###'
# Connect to the Moku (force_connect will overtake an existing connection).
with TimeFrequencyAnalyzer(MOKU_IP, force_connect=True) as i:
# Set the event detectors
# Set Event A to detect rising edge events on Input 1 at 0V
# Set Event B to detect rising edge events on Input 2 at 0V
i.set_event_detector(1, 'Input1', threshold=0, edge='Rising')
i.set_event_detector(2, 'Input2', threshold=0, edge='Rising')
# Set the interpolation to Linear
i.set_interpolation(mode='Linear')
# Set acquisition mode to a 100ms Window
i.set_acquisition_mode(mode='Windowed', window_length=100e-3)
# Use the first start event and close the interval at the end of the gate period (arbitrary as using windowed acquisition)
i.set_interval_policy(multiple_start_events='UseFirst', incomplete_intervals='Close')
# Set the interval analyzers
# Set Interval A to start at Event A and stop at Event A
# Set Interval B to start at Event B and stop at Event B
i.set_interval_analyzer(1, start_event_id=1, stop_event_id=1)
i.set_interval_analyzer(2, start_event_id=2, stop_event_id=2)
# Get data and explore statistics
data = i.get_data()
print('Interval 1:')
pprint(data['interval1']['statistics'])
print('Interval 2:')
pprint(data['interval2']['statistics'])
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
# timefrequencyanalyzer_plotting.py
This example demonstrates how you can configure the Time and Frequency Analyzer instrument and plot histogram data frames in real-time.
#
# moku example: Plotting Time and Frequency Analyzer
#
# This example demonstrates how you can configure the Time and Frequency Analyzer
# instrument, and view histogram data frames in real-time.
#
# (c) Liquid Instruments Pty. Ltd.
#
import matplotlib.pyplot as plt
import numpy as np
from moku.instruments import TimeFrequencyAnalyzer
# Replace with your Moku's IP address.
MOKU_IP = '192.168.###.###'
# Connect to the Moku (force_connect will overtake an existing connection).
with TimeFrequencyAnalyzer(MOKU_IP, force_connect=True) as i:
# Set the event detectors
# Set Event A to detect rising edge events on Input 1 at 0V
# Set Event B to detect rising edge events on Input 2 at 0V
i.set_event_detector(1, 'Input1', threshold=0, edge='Rising')
i.set_event_detector(2, 'Input2', threshold=0, edge='Rising')
# Set the interpolation to Linear
i.set_interpolation(mode='Linear')
# Set acquisition mode to a 100ms Window
i.set_acquisition_mode(mode='Windowed', window_length=100e-3)
# Use the first start event and close the interval at the end of the gate period (arbitrary as using windowed acquisition)
i.set_interval_policy(multiple_start_events='UseFirst', incomplete_intervals='Close')
# Set the histogram to 8ns span centred around 2us, with interval histogram type
i.set_histogram(start_time=1.996e-6, stop_time=2.004e-6, type='Interval')
# Set the interval analyzers
# Set Interval A to start at Event A and stop at Event A
# Set Interval B to start at Event B and stop at Event B
i.set_interval_analyzer(1, start_event_id=1, stop_event_id=1)
i.set_interval_analyzer(2, start_event_id=2, stop_event_id=2)
# 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
t0 = data['interval1']['histogram']['t0']
dt = data['interval1']['histogram']['dt']
length = 1024
x = np.linspace(start=t0, stop=t0 + dt * 1023, num=1024)
plt.ion()
plt.show()
plt.grid(visible=True)
plt.ylim([0, 600])
plt.xlim([1.996e-6, 2.004e-6])
line1 = plt.bar(
x, height=data['interval1']['histogram']['data'], width=dt, align='edge', alpha=0.8
)
line2 = plt.bar(
x, height=data['interval2']['histogram']['data'], width=dt, align='edge', alpha=0.8
)
# 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
height1 = data['interval1']['histogram']['data']
height2 = data['interval2']['histogram']['data']
for count1, rect1, count2, rect2 in zip(height1, line1.patches, height2, line2.patches):
rect1.set_height(count1)
rect2.set_height(count2)
plt.pause(0.001)
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
# 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) Liquid Instruments Pty. Ltd.
#
from moku.instruments import WaveformGenerator
# Replace with your Moku's IP address.
MOKU_IP = '192.168.###.###'
# Connect to the Moku (force_connect will overtake an existing connection).
with WaveformGenerator(MOKU_IP, force_connect=True) as i:
# 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)
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# 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) Liquid Instruments Pty. Ltd.
#
from moku.instruments import WaveformGenerator
# Replace with your Moku's IP address.
MOKU_IP = '192.168.###.###'
# Connect to the Moku (force_connect will overtake an existing connection).
with WaveformGenerator(MOKU_IP, force_connect=True) as i:
# 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 depth 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
)
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
# waveformgenerator_triggered.py
This example demonstrates how you can use the Waveform Generator instrument to generate a gated sine wave on Channel 1, and a swept frequency square wave on Channel 2.
#
# moku example: Waveform Generator Triggering
#
# This example demonstrates how you can use the Waveform Generator instrument
# to generate a gated sine wave on Channel 1, and a swept frequency square wave
# on Channel 2.
#
# (c) Liquid Instruments Pty. Ltd.
#
from moku.instruments import WaveformGenerator
# Replace with your Moku's IP address.
MOKU_IP = '192.168.###.###'
# Connect to the Moku (force_connect will overtake an existing connection).
with WaveformGenerator(MOKU_IP, force_connect=True) as i:
# Set sine wave to channel 1 and square wave to channel 2
i.generate_waveform(channel=1, type='Sine', amplitude=1, frequency=10)
i.generate_waveform(channel=2, type='Square', amplitude=1, frequency=500, duty=50)
# Activate burst trigger for output 1 and sweep trigger for output 2
i.set_burst_mode(
channel=1,
source='Internal',
mode='Gated',
burst_period=2,
trigger_level=0.5,
burst_duration=0.1,
)
i.set_sweep_mode(
channel=2, source='Internal', stop_frequency=10, sweep_time=2, trigger_level=0.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