Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
151 changes: 151 additions & 0 deletions src/nidcpower/nidcpower_delayed_backplane_triggering.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
#!/usr/bin/env python3

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Recommendation: whitespace in the beginning can be removed.

"""
NI-DCPower SMU Delayed Backplane Triggering

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Recommendation: should end with period as per flake.


This example demonstrates how to configure two NI-DCPower SMUs such that:
1. SMU1 generates a Source Complete Event.
2. The Source Complete Event is delayed using source_delay.
3. SMU2 waits for this event as a digital edge trigger.
4. The trigger is automatically routed through the PXI backplane.
5. Both SMUs perform sourcing and measurement operations.

HOW TO RUN:
-----------
i. From terminal (with default values):
python nidcpower_delayed_backplane_triggering.py

ii. From terminal (with custom values):
python nidcpower_delayed_backplane_triggering.py -n1 "PXI1Slot1" -n2 "PXI1Slot3" -sd 50e-6 -vl1 1.0 -vl2 1.0 -of "DC_VOLTAGE" -mc 1 -et 6

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Check the abbreviation defined and used in CLI, they are different . Need a check.


iii. To simulate without hardware:
python nidcpower_delayed_backplane_triggering.py -op "Simulate=1, DriverSetup=Model:4139; BoardType:PXIe"

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since there are two modules involved, need some changes to include models that can be simulated together. Check on this.


"""

import argparse # For parsing command-line arguments
import nidcpower # NI-DCPower instrument driver

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Recommendation: try to re-arrange the order , put import sys before nidcpower, add one line spacing (between grouping) after grouping (argparse, sys) and then dcpower

import sys # For accessing command-line arguments via sys.argv
"""
Args:
smu1_resource_name (str): Resource name of the triggering SMU.
smu2_resource_name (str): Resource name of the triggered SMU.
source_delay (float): Delay in seconds before SMU1 generates the Source Complete Event.
voltage_smu1 (float): Voltage level for SMU1.
voltage_smu2 (float): Voltage level for SMU2.
output_function (str): Output function (DC_VOLTAGE or DC_CURRENT).
measurement_count (int): Number of measurements to fetch.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Action needed : Do not use 'measurement_count' as an argument, if through CLI it is passed , the Fetch measurement maybe inconsistent/fail, since only first element is fetched. Suggestion would be to use default as 1 , without considering it in argslist.

event_timeout (float): Timeout in seconds for waiting for trigger event.
options (str): Driver option string. Can be used to enable simulation.
Returns:
tuple: (smu1_measurement, smu2_measurement)
"""

def example(smu1_resource_name, smu2_resource_name, source_delay, voltage_smu1, voltage_smu2, output_function, measurement_count, event_timeout, options):


Comment on lines +28 to +45
with nidcpower.Session(resource_name=smu1_resource_name,options=options) as smu1, nidcpower.Session(resource_name=smu2_resource_name,options=options) as smu2:

#Configure SMU1 to generate a Source Complete Event after a delay, and configure SMU2 to wait for that event as a trigger.
smu1.source_mode = nidcpower.SourceMode.SINGLE_POINT #setting source mode to single point for SMU1
smu1.output_function = getattr(nidcpower.OutputFunction, output_function) #setting output function for SMU1
smu1.voltage_level = voltage_smu1

smu1.measure_when = (nidcpower.MeasureWhen.AUTOMATICALLY_AFTER_SOURCE_COMPLETE) #setting measure when to automatically after source complete for SMU1
smu1.source_trigger_type = nidcpower.TriggerType.NONE

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Recommendation : comment on why Trigger is kept None for SMU1 , can be briefed for understanding.


#Delay Source Complete Event generation
smu1.source_delay = source_delay


#Configure SMU2 to wait for SMU1's Source Complete Event as a trigger.
smu2.source_mode = nidcpower.SourceMode.SINGLE_POINT #setting source mode to single point for SMU2
smu2.output_function = getattr(nidcpower.OutputFunction, output_function) #setting output function for SMU2
smu2.voltage_level = voltage_smu2

smu2.measure_when = (nidcpower.MeasureWhen.AUTOMATICALLY_AFTER_SOURCE_COMPLETE) #setting measure when to automatically after source complete for SMU2
smu2.source_trigger_type = (nidcpower.TriggerType.DIGITAL_EDGE) #setting source trigger type to digital edge for SMU2

# Use SMU1 Source Complete Event as trigger source
smu2.digital_edge_source_trigger_input_terminal = (f"/{smu1.io_resource_descriptor}/Engine0/SourceCompleteEvent") #setting digital edge source trigger input terminal to SMU1's Source Complete Event for SMU2

# Commit
smu1.commit()
smu2.commit()

# Initiate
smu2.initiate()

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Recommendation : Reason for Initiating the SMU2 prior to SMU1, can be mentioned for better understanding.

smu1.initiate()

# Wait for triggered operation to complete
smu2.wait_for_event(event_id=nidcpower.Event.SOURCE_COMPLETE, timeout=event_timeout)

# Fetch Measurements
smu1_measurement = smu1.fetch_multiple(count=measurement_count)[0]
smu2_measurement = smu2.fetch_multiple(count=measurement_count)[0]

print("SMU1 Measurement:")
print(smu1_measurement)

print("\nSMU2 Measurement:")
print(smu2_measurement)

return smu1_measurement, smu2_measurement
Comment on lines +83 to +92

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Recommendation : Check if there is a need to use return statement here, as measurement results are printed to console in 'example' function .


def _main(argsv):

parser = argparse.ArgumentParser(description="NI-DCPower Delayed Backplane Trigger Example")

parser.add_argument("-n1", "--smu1-resource-name", default="PXI1Slot1", help="Triggering SMU resource name")
parser.add_argument("-n2", "--smu2-resource-name", default="PXI1Slot2", help="Triggered SMU resource name")
parser.add_argument("-d", "--source-delay", type=float, default=50e-6, help="Source Complete Event delay (seconds)")

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

change the abbreviation for 'source delay' to 'sd' as per list maintained.

parser.add_argument("-v1", "--voltage-smu1", type=float, default=1.0, help="Voltage level for SMU1")
parser.add_argument("-v2", "--voltage-smu2", type=float, default=1.0, help="Voltage level for SMU2")
parser.add_argument("-of", "--output-function", default="DC_VOLTAGE", help="Output function (DC_VOLTAGE or DC_CURRENT)")
parser.add_argument("-mc", "--measurement-count", type=int, default=1, help="Number of measurements to fetch")
parser.add_argument("-t", "--event-timeout", type=float, default=6, help="Timeout in seconds for trigger event")
parser.add_argument("-op", "--options", default="", help="Driver option string")

args = parser.parse_args(argsv)

example(
smu1_resource_name= args.smu1_resource_name,
Comment thread
Upatel-NI marked this conversation as resolved.
smu2_resource_name= args.smu2_resource_name,
source_delay= args.source_delay,
voltage_smu1= args.voltage_smu1,
voltage_smu2= args.voltage_smu2,
output_function= args.output_function,
measurement_count= args.measurement_count,
event_timeout= args.event_timeout,
options= args.options)
Comment on lines +103 to +119


def main():
#Entry point — passes real CLI args to _main().
_main(sys.argv[1:])


def test_example():
#Simulated hardware test —runs example() using NI-DCPower simulation.
example(
smu1_resource_name="PXI1Slot2",
smu2_resource_name="PXI1Slot3",
source_delay=50e-6,
voltage_smu1=1.0,
voltage_smu2=1.0,
output_function="DC_VOLTAGE",
measurement_count=1,
event_timeout=6,
options="Simulate=1,DriverSetup=Model:4139;BoardType:PXIe")

def test_main():
#Simulated CLI test —runs _main() with simulate option string.

cmd_line = ["-op","Simulate=1,DriverSetup=Model:4139;BoardType:PXIe"]
_main(cmd_line)

# ------------------------------------------------------------
# Script execution starts here
# ------------------------------------------------------------

if __name__ == '__main__':
main()