Skip to content

Commit 129a46d

Browse files
committed
MP5000 Examples
Initial release
1 parent 6f66f45 commit 129a46d

File tree

76 files changed

+9764
-0
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

76 files changed

+9764
-0
lines changed

Examples/Modular_Precision_Test_System/Application_Examples/6_Ch_Parallel_Measurements/Parallel_Testing.py

Lines changed: 1130 additions & 0 deletions
Large diffs are not rendered by default.
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
# 6 Channel Parallel Measurements
2+
3+
This example follows the Synchronizing Parallel Testing with the MP5000 Series application note. Creates a dashboard in Python to display measured data.
4+
5+
## Required Modules
6+
3 x MSMU60-2
7+
8+
## Available Languages
9+
* Python
10+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,237 @@
1+
------------------------------------------------------------------------------------
2+
--- Function: setup_smu()
3+
--- Description: This function initializes each SMU with the settings appropriate
4+
--- to complete this test.
5+
------------------------------------------------------------------------------------
6+
function setup_smus()
7+
for slot_no=1, slot_count do
8+
for chan_no=1, 2 do
9+
local smu = slot[slot_no].smu[chan_no]
10+
-- Reset SMU
11+
smu.reset()
12+
smu.defbuffer1.clear()
13+
smu.defbuffer2.clear()
14+
-- Source settings
15+
smu.source.func = smu.FUNC_DC_VOLTAGE
16+
smu.source.limiti = ilimit
17+
smu.source.levelv = vlevel
18+
smu.source.autorangev = smu.OFF
19+
smu.source.rangev = vlevel
20+
--Measure settings
21+
smu.measure.autorangei = smu.OFF
22+
smu.measure.rangei = ilimit
23+
smu.measure.aperture = aperture
24+
smu.trigger.measure.i(smu.defbuffer1)
25+
end
26+
end
27+
end
28+
29+
------------------------------------------------------------------------------------
30+
--- Function: sync_measurements_trigger_timer()
31+
--- Description: This function performs measurements across multiple SMU channels,
32+
--- up to six, in parallel. This is done with the use of a trigger timer which
33+
--- allows for minimal drift in measurement timing.
34+
------------------------------------------------------------------------------------
35+
function sync_measurements_trigger_timer()
36+
37+
--local loopCt = 100 -- Used for fixed count scan
38+
-- Trigger timer allows easy syncronization
39+
local triggerTimer = trigger.timer[1]
40+
--triggerTimer.count = loopCt -- Used for fixed count scan
41+
triggerTimer.count = 0 -- Infinite timer events
42+
triggerTimer.delay = measure_interval
43+
triggerTimer.passthrough = false
44+
triggerTimer.stimulus = trigger.generator[1].EVENT_ID
45+
46+
-- Create identical trigger models for all channels
47+
for slot_no=1, slot_count do
48+
local triggerModel = slot[slot_no].trigger.model
49+
for chan_no=1, 2 do
50+
local tm_name = string.format("trigModel%d", chan_no)
51+
-- Create trigger model
52+
triggerModel.create(tm_name)
53+
triggerModel.addblock.source.output(tm_name, "output-on", chan_no, 1)
54+
triggerModel.addblock.wait(tm_name, "wait", trigger.timer[1].EVENT_ID) -- Wait for event from trigger timer
55+
triggerModel.addblock.measure(tm_name, "measure", chan_no, 1) -- Take a single measurement (not ideal for fast measurements)
56+
triggerModel.addblock.branch.event(tm_name, "abort", "output-off", trigger.generator[2].EVENT_ID) -- Check for abort event
57+
--triggerModel.addblock.branch.counter(tm_name, "branch", "wait", loopCt) -- Used for fixed count scan
58+
triggerModel.addblock.branch.always(tm_name, "branch", "wait") -- Loop back to wait
59+
triggerModel.addblock.source.output(tm_name, "output-off", chan_no, 0) -- Output off and end
60+
triggerModel.initiate(tm_name)
61+
end
62+
end
63+
delay(100e-3) -- Allow time for trigger models to build
64+
trigger.generator[1].assert() -- Begin the trigger timer
65+
end
66+
------------------------------------------------------------------------------------
67+
--- Function: sync_measurements_delay_constant()
68+
--- Description: This function performs measurements across multiple SMU channels,
69+
--- up to six, in parallel. Timing is achieved by making the first channel a master
70+
--- which uses a delay constant and notifys the other channels when to measure.
71+
--- This is less accurate than using a trigger timer and has a drift of roughly .5
72+
--- to .33 us per iteration.
73+
------------------------------------------------------------------------------------
74+
function sync_measurements_delay_constant()
75+
--local loopCt = 2000 -- Used for fixed count scan
76+
-- Create trigger models for every channel
77+
for slot_no=slot_count, 1, -1 do
78+
local triggerModel = slot[slot_no].trigger.model
79+
for chan_no=2, 1, -1 do
80+
local tm_name = string.format("trigModel%d", chan_no)
81+
-- Channel 1 of Slot 1 serves as master, notifying others when to take measurements
82+
if slot_no == 1 and chan_no == 1 then
83+
triggerModel.create(tm_name)
84+
triggerModel.addblock.source.output(tm_name, "output-on", chan_no, 1)
85+
triggerModel.addblock.notify(tm_name, "notify-slots", triggerModel.EVENT_NOTIFY1) -- Notify others to take a measurements
86+
triggerModel.addblock.measure(tm_name, "measure", chan_no, 1) -- Take single measurement (not ideal for fast measurements)
87+
triggerModel.addblock.branch.event(tm_name, "abort", "output-off", trigger.generator[2].EVENT_ID) -- Check for abort event
88+
triggerModel.addblock.delay.constant(tm_name, "delay-constant", measure_interval, "notify-slots") -- Delay for constant time (introduces error, not ideal)
89+
--triggerModel.addblock.branch.counter(tm_name, "branch", "notify-slots", loopCt) -- Used for fixed count scan
90+
triggerModel.addblock.branch.always(tm_name, "branch", "notify-slots") -- Loop to notificataion
91+
triggerModel.addblock.source.output(tm_name, "output-off", chan_no, 0) -- Turn output off and end test
92+
delay(100e-3)
93+
triggerModel.initiate(tm_name)
94+
-- All other channels wait for notification from master to measure
95+
else
96+
triggerModel.create(tm_name)
97+
triggerModel.addblock.source.output(tm_name, "output-on", chan_no, 1)
98+
triggerModel.addblock.wait(tm_name, "wait-main", slot[1].trigger.model.EVENT_NOTIFY1) -- Wait for notificaiton from master
99+
triggerModel.addblock.measure(tm_name, "measure", chan_no, 1) -- Take single measurement (not ideal for fast measurements)
100+
triggerModel.addblock.branch.event(tm_name, "abort", "output-off", trigger.generator[2].EVENT_ID) -- Check for abort event
101+
--triggerModel.addblock.branch.counter(tm_name, "branch", "wait-main", loopCt) -- Used for fixed count scan
102+
triggerModel.addblock.branch.always(tm_name, "branch", "wait-main") -- Loop to wait
103+
triggerModel.addblock.source.output(tm_name, "output-off", chan_no, 0) -- Turn output off and end test
104+
triggerModel.initiate(tm_name)
105+
end
106+
end
107+
end
108+
end
109+
110+
-- This function deletes the trigger models off each module
111+
function delete_trigger_models()
112+
for i=1, slot_count do
113+
slot[i].trigger.model.delete("trigModel1")
114+
slot[i].trigger.model.delete("trigModel2")
115+
end
116+
end
117+
-- This function aborts all trigger models
118+
function abort_trigger_models()
119+
trigger.generator[2].assert() -- Send event to abort trigger models
120+
delay(500e-3) -- Wait for all models to abort
121+
for i=1, slot_count do
122+
-- Turn outputs off
123+
slot[i].smu[1].source.output = 0
124+
slot[i].smu[2].source.output = 0
125+
end
126+
end
127+
128+
-- This function prints contents of reading buffers in a table format
129+
function print_reading_buffers()
130+
if slot_count == 1 then
131+
print("Time\t\t Ch1\t\t Ch2")
132+
for i=1, slot[1].smu[1].defbuffer1.n do
133+
print(slot[1].smu[1].defbuffer1.timestamps[i],
134+
vlevel/slot[1].smu[1].defbuffer1[i], vlevel/slot[1].smu[2].defbuffer1[i]
135+
)
136+
end
137+
elseif slot_count == 2 then
138+
print("Time\t\t Ch1\t\t Ch2\t\t Ch3\t\t Ch4")
139+
for i=1, slot[1].smu[1].defbuffer1.n do
140+
print(slot[1].smu[1].defbuffer1.timestamps[i],
141+
vlevel/slot[1].smu[1].defbuffer1[i], vlevel/slot[1].smu[2].defbuffer1[i],
142+
vlevel/slot[2].smu[1].defbuffer1[i], vlevel/slot[2].smu[2].defbuffer1[i]
143+
)
144+
end
145+
else
146+
print("Time\t\t Ch1\t\t Ch2\t\t Ch3\t\t Ch4\t\t Ch5\t\t Ch6")
147+
for i=1, slot[1].smu[1].defbuffer1.n do
148+
print(slot[1].smu[1].defbuffer1.timestamps[i],
149+
vlevel/slot[1].smu[1].defbuffer1[i], vlevel/slot[1].smu[2].defbuffer1[i],
150+
vlevel/slot[2].smu[1].defbuffer1[i], vlevel/slot[2].smu[2].defbuffer1[i],
151+
vlevel/slot[3].smu[1].defbuffer1[i], vlevel/slot[3].smu[2].defbuffer1[i]
152+
)
153+
end
154+
end
155+
end
156+
157+
-- This function exports all buffer data to a UBS drive
158+
function export_to_usb()
159+
local filename = "/usb1/exported_data.csv" -- Set file to be created, will overwrite if file exists
160+
local fptr, err = io.open(filename, "w") -- Define a file pointer
161+
if err == nil then -- Check for USB error
162+
-- Write buffer data to USB in csv for easy analysis
163+
if slot_count == 1 then
164+
fptr:write("Time, Ch1, Ch2\n")
165+
for i=1, slot[1].smu[1].defbuffer1.n do
166+
local writeString = string.format("%f, %f, %f",
167+
slot[1].smu[1].defbuffer1.timestamps[i],
168+
vlevel/slot[1].smu[1].defbuffer1[i], vlevel/slot[1].smu[2].defbuffer1[i]
169+
)
170+
fptr:write(writeString)
171+
end
172+
elseif slot_count == 2 then
173+
fptr:write("Time, Ch1, Ch2, Ch3, Ch4\n")
174+
for i=1, slot[1].smu[1].defbuffer1.n do
175+
local writeString = string.format("%f, %f, %f, %f, %f\n",
176+
slot[1].smu[1].defbuffer1.timestamps[i],
177+
vlevel/slot[1].smu[1].defbuffer1[i], vlevel/slot[1].smu[2].defbuffer1[i],
178+
vlevel/slot[2].smu[1].defbuffer1[i], vlevel/slot[2].smu[2].defbuffer1[i]
179+
)
180+
fptr:write(writeString)
181+
end
182+
else
183+
fptr:write("Time, Ch1, Ch2, Ch3, Ch4, Ch5, Ch6\n")
184+
for i=1, slot[1].smu[1].defbuffer1.n do
185+
local writeString = string.format("%f, %f, %f, %f, %f, %f, %f\n",
186+
slot[1].smu[1].defbuffer1.timestamps[i],
187+
vlevel/slot[1].smu[1].defbuffer1[i], vlevel/slot[1].smu[2].defbuffer1[i],
188+
vlevel/slot[2].smu[1].defbuffer1[i], vlevel/slot[2].smu[2].defbuffer1[i],
189+
vlevel/slot[3].smu[1].defbuffer1[i], vlevel/slot[3].smu[2].defbuffer1[i]
190+
)
191+
fptr:write(writeString)
192+
end
193+
end
194+
fptr:flush()
195+
fptr:close()
196+
else
197+
print("Error in Opening USB File")
198+
end
199+
end
200+
201+
------------------------------------------------------------------------------------
202+
--- THESE FUNCTIONS ARE INTENDED TO BE UTILIZED BY THE USER
203+
------------------------------------------------------------------------------------
204+
-- Start the test
205+
function start_scan()
206+
delete_trigger_models()
207+
setup_smus()
208+
sync_measurements_trigger_timer()
209+
--sync_measurements_delay_constant()
210+
end
211+
-- Pause to export data to USB
212+
function pause_export_resume()
213+
abort_trigger_models()
214+
delete_trigger_models()
215+
export_to_usb()
216+
setup_smus()
217+
sync_measurements_trigger_timer()
218+
--sync_measurements_delay_constant()
219+
end
220+
-- End the test
221+
function end_scan()
222+
abort_trigger_models()
223+
end
224+
225+
------------------------------------------------------------------------------------
226+
--- CHANGE SCAN PARAMETERS
227+
------------------------------------------------------------------------------------
228+
229+
slot_count = 1
230+
vlevel = 5
231+
ilimit = 100e-3
232+
measure_interval = 20e-3
233+
aperture = 10e-3
234+
235+
start_scan()
236+
--pause_export_resume()
237+
--end_scan()
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
# Exporting Parallel Measurements to USB Drive
2+
3+
This script performs long term datalogging for parallel resistance measurements. The test can be stopped by the user occasionally to export measurements to a USB drive.
4+
5+
There are two primary methods for parallel measurement provided in this script. The simpler and more accurate method utilizes a trigger timer. This sends an event to all channels notifying them to take a measurement. The second method uses delay constants. This is more complex and less accurate (.33us drift every iteration), however, it provides a look into how multiple trigger models can communicate and interact. This script is not designed for very fast measurements (<1ms), there are other methods that can be used to achieve such timing.
6+
7+
## Required Modules
8+
2 or 3 x MSMU60-2
9+
10+
## Available Languages
11+
* TSP
12+
13+
## Instructions
14+
1. Begin by connecting to the mainframe using the instrument panel found on the left side of the visual studio code interface or running the TSP: Connect function and entering the IP address or VISA resource screen.
15+
2. Update the scan parameters according to your device’s specifications.
16+
3. There are three functions designed for user use: “start_scan()”, “pause_export_resume()”, and “end_scan()”.
17+
* “start_scan()” will begin measuring across all channels according to your parameters.
18+
* “pause_export_resume()” will abort all measuring, export resistance data from buffers to a USB drive connected to the front panel, then continue measuring.
19+
* “end_scan()” will end the measurements without exporting to USB.
20+
4. Connect sensors/resistive loads to all channels. The script is designed to work with an even number of channels. If using an odd number of channels simply do not connect the final channel.
21+
5. When the script is run, it will begin measuring across all channels. Intermittently the user may want to export previous data to a USB. This can be done by sending “pause_export_resume()” to the mainframe through the TSP terminal.
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
# Application Examples
2+
3+
The examples in this directory work with the [MP5103 Mainframe and supported modules](https://www.tek.com/en/products/mp5000-series-modular-precision-test-system). These examples are application focused and may involve more than one module type or be convertible to any module type.
4+
5+
*Note: before running any example - verify slot and channel used.*
6+
7+
## Directory
8+
9+
### **[6 Channel Parallel Measurements](./6_Ch_Parallel_Measurements/)**
10+
This example follows the Synchronizing Parallel Testing with the MP5000 Series application note. Creates a dashboard in Python to display measured data.
11+
12+
### **[Exporting Parallel Measurements to USB](./Exporting_Parallel_Data_To_USB/)**
13+
This script performs long term datalogging for parallel resistance measurements. The test can be stopped by the user occaisionally to export measurements to a USB drive. .
14+
15+
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
-- Alais SMU
2+
local slot_no = 2
3+
local psu1 = slot[slot_no].psu[1]
4+
local psu2 = slot[slot_no].psu[2]
5+
-- Source settings
6+
local v_level = 20
7+
local i_level = 300e-3
8+
local i_limit = 350e-3
9+
-- Reset psu's
10+
psu1.reset()
11+
psu2.reset()
12+
-- Clear all buffers
13+
psu1.defbuffer1.clear()
14+
psu1.defbuffer2.clear()
15+
psu2.defbuffer1.clear()
16+
psu2.defbuffer2.clear()
17+
-- Setup buffers for trigger model measurements
18+
psu1.trigger.measure.iv(psu1.defbuffer1, psu1.defbuffer2)
19+
psu2.trigger.measure.iv(psu2.defbuffer1, psu2.defbuffer2)
20+
21+
-- Configure psu source settings
22+
-- To avoid channels sinking eachother one channel
23+
-- has a higher levelv and the other has a higher current limit
24+
psu1.source.levelv = v_level+100e-3
25+
psu2.source.levelv = v_level
26+
psu1.source.limiti = i_level/2
27+
psu2.source.limiti = i_level/2 + (i_limit-i_level)
28+
29+
-- Create a trigger model to turn channels on/off at same time
30+
local tm_name = "tm"
31+
local triggerModel = slot[slot_no].trigger.model
32+
triggerModel.create(tm_name)
33+
triggerModel.addblock.source.output(tm_name, "outputs-on", {1,2}, 1)
34+
triggerModel.addblock.delay.constant(tm_name, "delay1", 10e-3)
35+
triggerModel.addblock.measure(tm_name, "measure", {1,2}, 20)
36+
triggerModel.addblock.delay.constant(tm_name, "delay2", 10e-3)
37+
triggerModel.addblock.source.output(tm_name, "outputs-off", {1,2}, 0)
38+
39+
-- Initiate trigger model and delete
40+
triggerModel.initiate(tm_name)
41+
waitcomplete()
42+
triggerModel.delete(tm_name)
43+
44+
-- Display measurements to terminal
45+
print("V1\t\t I1\t\t V2\t\t I2")
46+
for i=1, psu1.defbuffer1.n do
47+
print(psu1.defbuffer2[i], psu1.defbuffer1[i], psu2.defbuffer2[i], psu2.defbuffer1[i])
48+
end
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
# Combining 2 PSU Channels in Parallel
2+
3+
Combines channel sourcing in parallel to increase current capabilities.
4+
5+
## Required Modules
6+
1 x MPSU50-2ST
7+
8+
## Available Languages
9+
* TSP
10+
11+
## Instructions
12+
1. Begin by connecting to the mainframe using the instrument panel found on the left side of the visual studio code interface or running the TSP: Connect function and entering the IP address.
13+
2. Connect CH1-LO to CH2-LO and CH1-HI to CH2-HI. Then connect the load to CH1.
14+
3. Configure the slot number, voltage source level, current level, and current limit as desired, located at the top of the script.
15+
* NOTE: To avoid one of the PSU’s sinking the other the source settings must be set carefully. One channel has a voltage level that is slightly higher than the target voltage and the other has a current slightly higher than target current. The source levels for both channels must fall under the power envelope for the module.
16+
4. Run Parallel _Combo.tsp and view the current/voltage readings from both channels.
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
# Combining 2 PSU Channels in Series
2+
3+
Combines channel sourcing in series to increase voltage capabilities.
4+
5+
## Required Modules
6+
1 x MPSU50-2ST
7+
8+
## Available Languages
9+
* TSP
10+
11+
## Instructions
12+
1. Begin by connecting to the mainframe using the instrument panel found on the left side of the visual studio code interface or running the TSP: Connect function and entering the IP address.
13+
2. Connect CH1-LO to CH2-HI. Then connect the load to CH1-HI and CH2-LO
14+
3. Configure the slot number, voltage source level, and current limit as desired, located at the top of the script.
15+
* NOTE: Each channel is set with a voltage level that is half the input voltage level and both channels are set with the current limit specified. These parameters must fall in the power envelope per channel of the module.
16+
4. Run Series_Combo.tsp and view the current/voltage readings from both channels.

0 commit comments

Comments
 (0)