Using Keithley 4200A Lpt Libruary - Seg_arb

Hi

I’ve been trying to implement the Keithley 4200 Lib that you have all developed into some scripts i can use for some measurements. (see below)

I’ve managed to get simple scripts working both single and dual channel but python is just to slow to run some and custom waveforms are required. I’ve been trying to run the Seg_arb function collecting data at specific sections.

Using examples in the LPT manual i can get it to work up until the point i need to take data and it just doesn’t let me and fails every time. (when you set measurement type too any value other than 0) see below:

num_segments = 7
sequence_number = 1   

    seg_start_v = [0, 1, 1, 1.5, 1.5, 0, 0]

    seg_stop_v = [1, 1, 1.5, 1.5, 0, 0, 0]

    # Times

    seg_times = [50e-9, 100e-9, 20e-9, 150e-9, 50e-9, 500e-9, 130e-9]  # 10µs, 1µs, 10µs

    # Trigger (first segment = 1)

    seg_trig_out = [1, 1, 1, 0, 0, 0, 0]

    # SSR Control (1 = output enabled)

    ssr_ctrl = [1, 1, 1, 1, 1, 1, 0]

    # Measurement - try enabling spot mean (type=1) in specific segments

    meas_type = [0, 0, 0, 0, 0, 0, 0]  # Measure in segments 1 and 3

    meas_start = [0, 25e-9, 0, 50e-9, 0, 0, 0]  # Start 25ns into segment

    meas_stop = [0, 75e-9, 0, 100e-9, 0, 0, 0]   # Stop 75ns into segment
when anything other than 0 is used within meas_type  i get the following error: 

[ERROR] seg_arb_sequence failed: Server-side processing failed with K4200Error(‘Illegal value for parameter #%d.’)

I thought maybe it was due to having to define some peramiters before hand but I am also following a c example that works and dosnt have this but still cannot seemingly get it to work correctly, any idea why?

Any help would be greatly appreciated, current script below:

Craig

import sys
from pathlib import Path
import time

# Add project root to path
sys.path.insert(0, str(Path(__file__).resolve().parents[3]))
from ProxyClass import Proxy


def test_simple_segarb():
    """Minimal segment ARB test."""
    
    # Connect
    print("Connecting to PMU...")
    lpt = Proxy("192.168.0.10", 8888, "lpt")
    param = Proxy("192.168.0.10", 8888, "param")
    
    lpt.initialize()
    lpt.tstsel(1)
    lpt.devint()
    card_id = lpt.getinstid("PMU1")
    
    print(f"[OK] Connected, card_id = {card_id}\n")
    
    # Configuration
    channel = 1
    v_range = 10.0
    i_range = 0.0002  # Try 0.2A range instead of 0.01A (both are valid for 10V range)
    load_resistance = 1000.0
    
    try:
        print("Configuring RPM...")
        lpt.rpm_config(card_id, channel, param.KI_RPM_PATHWAY, param.KI_RPM_PULSE)
        print()
    except Exception as e:
        print(f"{e}")
    
    try:
        print("Initializing Segment ARB mode...")
        # Try using param.PULSE_MODE_SARB instead of hardcoded 2
        try:
            PULSE_MODE_SARB = param.PULSE_MODE_SARB
            print(f"      Using param.PULSE_MODE_SARB = {PULSE_MODE_SARB}")
        except:
            PULSE_MODE_SARB = 2
            print(f"      Using hardcoded PULSE_MODE_SARB = {PULSE_MODE_SARB}")
        
        lpt.pg2_init(card_id, PULSE_MODE_SARB)
        print()
    except Exception as e:
        print(f"{e}")
        return
    
    try:
        print("Setting limit mode to return actual values...")
        lpt.setmode(card_id, param.KI_LIM_MODE, param.KI_VALUE)
        print()
    except Exception as e:
        print(f"      [ERROR] setmode failed: {e}")
        return
    
    try:
        print(f"Setting load resistance = {load_resistance} Ohm...")
        lpt.pulse_load(card_id, 1, float(load_resistance))
        print("OK Channel 1")
        lpt.pulse_load(card_id, 2, float(load_resistance))
        print("OK Channel 2")
    except Exception as e:
        print(f"pulse_load failed: {e}")
        return
    
    # CRITICAL: Must set PMU ranges when using RPM mode to avoid SSR error!
    try:
        print(f"Setting PMU ranges for Channel {channel}: V={v_range}V, I={i_range}A...")
        # Use PULSE_MEAS_FIXED (=2) for fixed ranges
        lpt.pulse_ranges(card_id, channel,
                         v_src_range=float(v_range),
                         v_range_type=2,  # param.PULSE_MEAS_FIXED
                         v_range=float(v_range),
                         i_range_type=2,  # param.PULSE_MEAS_FIXED
                         i_range=float(i_range))
        print("PMU ranges set")
    except Exception as e:
        print(f"pulse_ranges failed: {e}")
        print(f"Parameters: card_id={card_id}, channel={channel}, v_range={v_range}, i_range={i_range}")
        return
    
    try:
        print(f"Setting sample rate = 10 MSa/s...")
        sample_rate = 10e6
        lpt.pulse_sample_rate(card_id, int(sample_rate))
        print()
    except Exception as e:
        print(f"pulse_sample_rate failed: {e}")
        return
    
    try:
        print(f"Setting burst count = 1...")
        lpt.pulse_burst_count(card_id, channel, 1)
        print()
    except Exception as e:
        print(f"pulse_burst_count failed: {e}")
        return
    
    # # Configure measurement (spot mean for Segment ARB)
    # try:
    #     print(f"Configuring spot mean measurement...")
    #     lpt.pulse_meas_sm(
    #         card_id, channel,
    #         acquire_type=0,           # 0 = per-period (PULSE_MEAS_SMEAN_PER)
    #         acquire_meas_v_ampl=1,    # Measure voltage amplitude
    #         acquire_meas_v_base=0,    # Don't measure base
    #         acquire_meas_i_ampl=1,    # Measure current amplitude  
    #         acquire_meas_i_base=0,    # Don't measure base
    #         acquire_time_stamp=1,     # Capture timestamps
    #         llecomp=0                 # No load-line compensation
    #     )
    #     print("Spot mean configured")
    # except Exception as e:
    #     print(f"pulse_meas_sm failed: {e}")
    #     # Continue anyway - might not be needed
    
    # # Configure measurement timing window
    # try:
    #     print(f"Configuring measurement timing...")
    #     lpt.pulse_meas_timing(
    #         card_id, channel,
    #         0.1,  # Start at 10% into segment
    #         0.9,  # Stop at 90% into segment
    #         1     # Number of pulses
    #     )
    #     print("Measurement timing configured")
    # except Exception as e:
    #     print(f"pulse_meas_timing failed: {e}")
    #     # Continue anyway
    
    # Define simple 3-segment waveform
    print("\n Defining segment ARB sequence...")
    
    
    num_segments = 7
    sequence_number = 1
    
    
    seg_start_v = [0, 1, 1, 1.5, 1.5, 0, 0]
    seg_stop_v = [1, 1, 1.5, 1.5, 0, 0, 0]
    
    # Times
    seg_times = [50e-9, 100e-9, 20e-9, 150e-9, 50e-9, 500e-9, 130e-9]  # 10µs, 1µs, 10µs
    
    # Trigger (first segment = 1)
    seg_trig_out = [1, 1, 1, 0, 0, 0, 0]
    
    # SSR Control (1 = output enabled)
    ssr_ctrl = [1, 1, 1, 1, 1, 1, 0]
    
    # Measurement
    meas_type = [0, 2, 0, 0, 0, 0, 0] 
    meas_start = [0, 25e-9, 0, 50e-9, 0, 0, 0]  # Start 25ns into segment
    meas_stop = [0, 75e-9, 0, 100e-9, 0, 0, 0]   # Stop 75ns into segment

    
    print(f"      Voltages: {seg_start_v}")
    print(f"      Times: {seg_times}")
    print(f"      Trig out: {seg_trig_out}")
    print(f"      SSR ctrl: {ssr_ctrl}")
    print(f"      Meas type: {meas_type}")
    
    try:
        lpt.seg_arb_sequence(
            card_id,
            channel,
            sequence_number,
            num_segments,
            seg_start_v,
            seg_stop_v,
            seg_times,
            seg_trig_out,
            ssr_ctrl,
            meas_type,
            meas_start,
            meas_stop
        )
        print("      [OK] seg_arb_sequence succeeded!")
        print()
    except Exception as e:
        print(f" seg_arb_sequence failed: {e}")
        print(f"Debug info:")
        print(f"card_id = {card_id}")
        print(f"channel = {channel}")
        print(f"sequence_number = {sequence_number}")
        print(f"num_segments = {num_segments}")
        print(f"seg_start_v = {seg_start_v}")
        print(f"seg_stop_v = {seg_stop_v}")
        print(f"seg_times = {seg_times}")
        return
    
    try:
        print("Programming waveform...")
        seq_list = [1]
        loop_count = [1.0]  # Use float for loop count
        lpt.seg_arb_waveform(card_id, channel, 1, seq_list, loop_count)
        print("      [OK] seg_arb_waveform succeeded!")
    except Exception as e:
        print(f"seg_arb_waveform failed: {e}")
        return
    
    # Execute
    print("Executing waveform...")
    try:
        lpt.pulse_output(card_id, channel, 1)
        print("Output enabled")
        
        lpt.pulse_exec(param.PULSE_MODE_SIMPLE)
        print("Pulse executing...")
        
        # Wait for completion
        while True:
            status, elapsed = lpt.pulse_exec_status()
            if status != param.PMU_TEST_STATUS_RUNNING:
                break
            time.sleep(0.01)
        
        print("Execution complete!")
        
    except Exception as e:
        print(f"Execution failed: {e}")
    


    print()
    print(" returning waveform data...")
    # time start for data is 10e-6+1e-6 = 11e-6
    # time end for data is 11e-6 + 50e-6 = 61e-6
    # sample rate is 10e6
    # so we need to fetch data from 11e-6 to 61e-6

    # still to do 

    total_time = sum(seg_times)
    expected_samples = int(total_time * sample_rate)

    print("total_time: ", total_time)
    print("expected_samples: ", expected_samples)

    buf_size = lpt.pulse_chan_status(card_id, channel)
    print("buf_size: ", buf_size)

    v_data, i_data, ts_data, st_data = lpt.pulse_fetch(card_id, channel,0,10)
    print("v_data: ", v_data)
    print("i_data: ", i_data)


    print("clean_up...")
    # Cleanup
    try:
        lpt.pulse_output(card_id, channel, 0)
        print("      Output disabled")
    except:
        pass

if __name__ == "__main__":
    test_simple_segarb()


Hello Craig,

The pulse mode control for the lptlib.dll is a tricky topic. I recall encountering a similar error message while working on it, but unfortunately, I could not find which parameter solved it in our case. I can share our minimum working example, which correctly creates a segmented arbitrary waveform (which was tested with a connected oscilloscope):

# This script is a minimum working example for generating a segmented arbitrary waveform with Keithley 4200-SCS device
# and fetching the results from the device. The problem arises when trying to read out the buffer after a measurement.

import time

# The pylptlib package is a python wrapper for the lptlib.dll.
from pylptlib import lpt, param


def minimum_working_example():
    lpt = Proxy(192.168.0.1, 8888, "lpt")
    param = Proxy(192.168.0.1, 8888, "param")
    
    # Initialization
    lpt.initialize()
    lpt.tstsel(1)
    lpt.devint()
    card_id = lpt.getinstid("PMU1")

    gate = 1
    drain = 2
    sample_rate = 200e6

    lpt.pg2_init(card_id, param.PULSE_MODE_SARB)

    for channel in [gate, drain]:
        lpt.pulse_load(card_id, channel, 50)
        lpt.pulse_ranges(
            card_id,
            channel,
            10,
            param.PULSE_MEAS_FIXED,
            10,
            param.PULSE_MEAS_FIXED,
            0.2,
        )
        lpt.pulse_burst_count(card_id, channel, 1)
        lpt.pulse_output(card_id, channel, 1)

    lpt.pulse_sample_rate(card_id, sample_rate)

    # Define a simple 'rectangle' sequence for both channels and create a waveform
    for channel in [gate, drain]:
        lpt.seg_arb_sequence(
            instr_id=card_id,
            chan=channel,
            seq_num=1,
            num_segments=3,
            start_v=[0, 1, 1],
            stop_v=[1, 1, 0],
            time=[1e-7, 1e-6, 1e-7],
            trig=[1, 1, 1],
            ssr=[1, 1, 1],
            meas_type=[0, 1, 0],
            meas_start=[0, 0, 0],
            meas_stop=[0, 1e-6, 0],
        )

        lpt.seg_arb_waveform(
            instr_id=card_id,
            chan=channel,
            num_seq=3,
            seq=[1, 1, 1],
            seq_loop_count=[1, 1, 1],
        )

    # Start pulse generation
    # Working pulse generation has been confirmed by an external oscilloscope
    lpt.pulse_exec(0)

    # Wait for test to finish - as described in the manual
    # This works as expected
    while True:
        time.sleep(1)
        status, elapsed_time = lpt.pulse_exec_status()

        if status != param.PMU_TEST_STATUS_RUNNING:
            break
        if elapsed_time > 60:
            lpt.dev_abort()

    results = []
    for channel in [1, 2]:
        # The problem arises here: buffer_size is always empty
        buffer_size = lpt.pulse_chan_status(card_id, channel)
        print(f"Buffer size for channel {channel}: {buffer_size}")

        # Hence the following line will always return an empty list
        result = lpt.pulse_fetch(card_id, channel, 0, 9)
        results.append(result)
        print(f"Results for channel {channel}: {result}")


if __name__ == "__main__":
    minimum_working_example()

That said, we did run into an issue with retrieving the data. No matter which commands we choose, the buffer_sizeretrieved after the measurement was always 0. We have been in contact with the Tektronix support and they have confirmed that it is an issue with the lptlib.dll rather than our Python implementation (pylptlib). Unfortunately, the priority given to the issue wasn’t high enough for an immediate fix.

Feel free to test our minimum working example and let us know if you are able to retrieve the data. If it doesn’t work, you might consider reaching out to your Tektronix support contact to demonstrate that there is a higher demand for a solution. You can CC contact@sweep-me.net in your request if you’d like to tag us.

Best,

Franz

1 Like

Hi Franz

Thanks very much for the quick responce, im glad someone else has had the same issue. Like you i was able to send a pulse using seg arb however i was unable too measure either. It all seemingly works well untill you try to measure.

I will give your code a look at tomorrow and see if there is any differences and let you know how it goes.

Craig

2 Likes

So i tested today and got the same issue with your code. Ill drop them an email in the coming week with a request for support thankyou very much for your help

1 Like