Usage Guide#

This guide provides examples of how to use the Saleae MSO API for common tasks.

Initiating an analog capture#

The following will boot up the Logic MSO, initiate a capture, and save the resulting data to a directory you specify.

from pathlib import Path
import numpy as np
from saleae import mso_api

mso = mso_api.MSO()

capture_config = mso_api.CaptureConfig(
    enabled_channels=[mso_api.AnalogChannel(channel=0, name="clock")],
    analog_settings=mso_api.AnalogSettings(sample_rate=100e6),
    capture_settings=mso_api.TimedCapture(capture_length_seconds=0.1),
)

save_dir = Path('my-capture')
capture = mso.capture(capture_config, save_dir)
avg_voltage = np.mean(capture.analog_data["clock"].voltages)
print(f"Captured into {save_dir} avg voltage: {avg_voltage:.3f} V")
Captured into my-capture avg voltage: 0.063 V

Initiating a mixed-signal capture#

from pathlib import Path
from saleae import mso_api

mso = mso_api.MSO()

capture_config = mso_api.CaptureConfig(
    enabled_channels=[
        mso_api.AnalogChannel(channel=0, name="clock"),
        mso_api.DigitalChannel(port=0, channel=0, name="MOSI", threshold_volts=1.6),
    ],
    analog_settings=mso_api.AnalogSettings(sample_rate=100e6),
    capture_settings=mso_api.TimedCapture(capture_length_seconds=0.1),
)

save_dir = Path('my-capture')
capture = mso.capture(capture_config, save_dir)

Loading a previously saved (or exported) capture#

The Logic2 software can export analog waveforms in a binary format using File > Export Data (not save!)

To load a capture from a directory containing those binary export files, use the following:

from pathlib import Path

from saleae import mso_api

# Specify the directory containing the capture files
cap_dir = Path("../tests/data/capture1")

# Load the capture
cap = mso_api.Capture.from_dir(cap_dir)

# Print information about the capture
print(f"Channels: {cap.analog_channel_names}")
print(f"Sample rate: {cap.analog_sample_rate} Hz")
print(f"Duration: {cap.analog_stop_time - cap.analog_start_time:.6f} seconds")
Channels: ['CH0_volts', 'CH1_volts']
Sample rate: 11764705.0 Hz
Duration: 0.000060 seconds

Working with Triggers#

You can define triggers to identify specific events in your captures:

from saleae.mso_api import EdgeTrigger, EdgeTriggerDirection

# Create a trigger for rising edges on channel 1 (channel_index 0) at 0V
trigger = EdgeTrigger(
    channel_index=0,
    threshold_volts=0,
    direction=EdgeTriggerDirection.RISING
)

# Create a trigger for falling edges on the "clock" channel at 1.65V with a 1ms holdoff
trigger_with_holdoff = EdgeTrigger(
    channel_name="clock",
    threshold_volts=1.65,
    direction=EdgeTriggerDirection.FALLING,
    holdoff_seconds=0.001
)

Applying Synthetic Triggers#

If you have a long capture that you need to split into multiples, use split_capture()

from pathlib import Path

from saleae import mso_api
from saleae.mso_api.synthetic_trigger import split_capture

# Load a capture
cap_dir = Path(r"C:\Users\clark\OneDrive\Documents\01-projects\api-first-user\01-data")
cap = mso_api.Capture.from_dir(cap_dir)

# Set up a new trigger to split on
trigger = mso_api.EdgeTrigger(channel_index=0, threshold_volts=0, direction=EdgeTriggerDirection.RISING)

# Split the capture
caps = split_capture(cap, trigger, pre_trigger_seconds=-6e-6, post_trigger_seconds=56e-6)
print(f"Number of triggered segments: {len(caps)}")
# Output: Number of triggered segments: 13810
Number of triggered segments: 13810

Processing Triggered Segments#

Once you have split a capture into triggered segments, you can process each segment:

# Process each triggered segment
for i, segment in enumerate(caps[:5]):  # Process just the first 5 segments as an example
    print(f"Segment {i}:")
    print(f"  Duration: {segment.analog_stop_time - segment.analog_start_time:.9f} seconds")
    print(f"  Samples: {segment.num_analog_samples}")
    
    # You can perform analysis on each segment
    for ch_name, ch_data in segment.analog_data.items():
        print(f"    {ch_name} min: {ch_data.voltages.min():.3f}V, max: {ch_data.voltages.max():.3f}V")
Segment 0:
  Duration: 0.000050000 seconds
  Samples: 5000
    CH0_volts min: -0.517V, max: 0.509V
    CH1_volts min: -2.021V, max: 2.043V
    CH2_volts min: -0.033V, max: 0.041V
    CH3_volts min: -0.027V, max: 0.037V
Segment 1:
  Duration: 0.000050000 seconds
  Samples: 5000
    CH0_volts min: -0.524V, max: 0.510V
    CH1_volts min: -2.021V, max: 2.043V
    CH2_volts min: -0.027V, max: 0.041V
    CH3_volts min: -0.024V, max: 0.037V
Segment 2:
  Duration: 0.000050000 seconds
  Samples: 5000
    CH0_volts min: -0.520V, max: 0.509V
    CH1_volts min: -2.027V, max: 2.032V
    CH2_volts min: -0.033V, max: 0.041V
    CH3_volts min: -0.030V, max: 0.034V
Segment 3:
  Duration: 0.000050000 seconds
  Samples: 5000
    CH0_volts min: -0.508V, max: 0.509V
    CH1_volts min: -2.015V, max: 2.035V
    CH2_volts min: -0.036V, max: 0.044V
    CH3_volts min: -0.027V, max: 0.046V
Segment 4:
  Duration: 0.000050000 seconds
  Samples: 5000
    CH0_volts min: -0.507V, max: 0.508V
    CH1_volts min: -2.033V, max: 2.029V
    CH2_volts min: -0.033V, max: 0.041V
    CH3_volts min: -0.030V, max: 0.037V