Skip to content

Commit 8fdb10a

Browse files
author
neil.hamilton
committed
Add ps4000aExamples/ps4000aRapidBlockWaveformAveragingExample.py showing how to average together multiple buffers from a single rapid block capture
1 parent 64e8993 commit 8fdb10a

File tree

6 files changed

+567
-0
lines changed

6 files changed

+567
-0
lines changed

picosdk/PicoConnectProbes.py

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
#
2+
# Copyright (C) 2024 Pico Technology Ltd. See LICENSE file for terms.
3+
#
4+
"""
5+
This is a Python module defining the enumerations from the PicoConnectProbes.h C header
6+
file for use with various PicoScope oscilloscopes driver API functions.
7+
"""
8+
9+
from ctypes import *
10+
from picosdk.constants import make_enum
11+
from picosdk.library import Library
12+
13+
class PicoConnectProbeslib(Library):
14+
def __init__(self):
15+
super(PicoConnectProbeslib, self).__init__("picoConnectProbes")
16+
17+
18+
picoConnectProbes = PicoConnectProbeslib()
19+
20+
def _define_pico_probe_range_info():
21+
PICO_PROBE_NONE_NV = 0
22+
PICO_X1_PROBE_NV = 1
23+
PICO_X10_PROBE_NV = 10
24+
25+
return {k.upper(): v for k, v in locals().items() if k.startswith("PICO")}
26+
27+
picoConnectProbes.PICO_PROBE_RANGE_INFO = _define_pico_probe_range_info

picosdk/functionsExhibitions.py

Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
1+
#
2+
# Copyright (C) 2018 Pico Technology Ltd. See LICENSE file for terms.
3+
#
4+
5+
import numpy as np
6+
import openpyxl
7+
from math import floor, log2, log10
8+
9+
def dataImporter(name):
10+
11+
workbook = openpyxl.load_workbook(name, data_only = True)
12+
13+
sheet = workbook['filterParameters']
14+
15+
noOfChannels = sheet.cell(row = 2, column = 1).value
16+
bits = sheet.cell(row = 2, column = 2).value
17+
samplingRate = sheet.cell(row = 2, column = 3).value
18+
sampleLength = sheet.cell(row = 2, column = 4).value
19+
20+
return noOfChannels, bits, samplingRate, sampleLength
21+
22+
23+
def ps6000aTimebase(samplingRate):
24+
25+
sampleInterval = (1/samplingRate)/1000000 #s
26+
27+
breakPoint = 6.4/1000000000
28+
29+
if sampleInterval >= breakPoint:
30+
timebase = floor((sampleInterval * 156250000)+5)
31+
else:
32+
timebase = floor(log2(sampleInterval * 5000000000))
33+
34+
return timebase
35+
36+
def ps5000aTimebase(samplingRate):
37+
38+
sampleInterval = (1/samplingRate)/1000000 #s
39+
40+
breakPoint = 8/1000000000
41+
42+
if sampleInterval >= breakPoint:
43+
timebase = floor((sampleInterval * 125000000)+2)
44+
else:
45+
timebase = floor(log2(sampleInterval * 1000000000))
46+
47+
return timebase
48+
49+
def ps3000aTimebase(samplingRate):
50+
51+
sampleInterval = (1/samplingRate)/1000000 #s
52+
53+
breakPoint = 8/1000000000
54+
55+
if sampleInterval >= breakPoint:
56+
timebase = floor((sampleInterval * 125000000)+2)
57+
else:
58+
timebase = floor(log2(sampleInterval * 1000000000))
59+
60+
return timebase
61+
62+
def ps4000aTimebase(samplingRate):
63+
64+
timebase = floor((80/samplingRate)-1)
65+
66+
return timebase
67+
68+
def ps2000aTimebase(samplingRate):
69+
70+
sampleInterval = (1/samplingRate)/1000000 #s
71+
72+
breakPoint = 4/1000000000
73+
74+
if sampleInterval>= breakPoint:
75+
timebase = floor((sampleInterval*125000000)+2)
76+
else:
77+
timebase = floor(log2(sampleInterval * 1000000000))
78+
79+
return timebase
80+
81+
def ps2000Timebase(sampleRate):
82+
#assumes sample rate is in Hz
83+
#assumes sample interval in s
84+
85+
sampleInterval = (1/sampleRate)
86+
87+
timebase = floor(log10(sampleInterval*1000000000))
88+
89+
return timebase
90+
91+
92+
def BitEnumSelector(bits):
93+
94+
if bits <= 8:
95+
enum = 0
96+
elif bits <= 10:
97+
enum = 10
98+
else:
99+
enum = 1
100+
101+
return enum
102+
103+
def saveConfigFile(channels, bits, sampleRate,captureLength, maxAmplitude, segments):
104+
105+
configValues = [channels, bits, sampleRate, captureLength, maxAmplitude, segments]
106+
107+
# Save the list to a text file
108+
with open('configValues.txt', 'w') as file:
109+
# Write each element of the list on a new line
110+
for value in configValues:
111+
file.write(f"{value}\n")
112+
113+
return
114+
115+
def loadConfigValues():
116+
117+
restored_configValues = []
118+
119+
with open('configValues.txt', 'r') as file:
120+
for line in file:
121+
value = line.strip()
122+
# Convert to integer or float as necessary
123+
if '.' in value:
124+
restored_configValues.append(float(value))
125+
else:
126+
restored_configValues.append(int(value))
127+
128+
channels = restored_configValues[0]
129+
bits = restored_configValues[1]
130+
sampleRate = restored_configValues[2]
131+
captureLength = restored_configValues[3]
132+
maxAmplitude = restored_configValues[4]
133+
segments = restored_configValues[5]
134+
135+
return channels, bits, sampleRate, captureLength, maxAmplitude, segments

picosdk/ps2000.py

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
from picosdk.library import Library
1111
from picosdk.errors import ArgumentOutOfRangeError
1212
from picosdk.constants import make_enum
13+
from picosdk.ctypes_wrapper import C_CALLBACK_FUNCTION_FACTORY
1314

1415

1516
class Ps2000lib(Library):
@@ -74,6 +75,16 @@ def __init__(self):
7475

7576
ps2000.MAX_MEMORY = 32e3
7677

78+
ps2000.PS2000_TIME_UNITS = make_enum([
79+
'PS2000_FS',
80+
'PS2000_PS',
81+
'PS2000_NS',
82+
'PS2000_US',
83+
'PS2000_MS',
84+
'PS2000_S',
85+
'PS2000_MAX_TIME_UNITS',
86+
])
87+
7788
doc = """ int16_t ps2000_open_unit
7889
(
7990
void
@@ -412,3 +423,26 @@ def __init__(self):
412423
ps2000.PICO_INFO = {k: v for k, v in ps2000.PICO_INFO.items() if v <= 0x00000005}
413424
ps2000.PICO_INFO["PICO_ERROR_CODE"] = 0x00000006
414425
ps2000.PICO_INFO["PICO_KERNEL_DRIVER_VERSION"] = 0x00000007
426+
427+
428+
doc = """ void *my_get_overview_buffers
429+
(
430+
int16_t **overviewBuffers
431+
int16_t overflow,
432+
uint32_t triggerAt,
433+
int16_t triggered,
434+
int16_t autoStop,
435+
uint32_t nValues
436+
);
437+
define a python function which accepts the correct arguments, and pass it to the constructor of this type.
438+
"""
439+
440+
ps2000.GetOverviewBuffersType = C_CALLBACK_FUNCTION_FACTORY(None,
441+
c_void_p,
442+
c_int16,
443+
c_uint32,
444+
c_int16,
445+
c_int16,
446+
c_uint32)
447+
448+
ps2000.GetOverviewBuffersType.__doc__ = doc

picosdk/psospaBlockExample.py

Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
#
2+
# Copyright (C) 2024 Pico Technology Ltd. See LICENSE file for terms.
3+
#
4+
# PSOSPA BLOCK MODE EXAMPLE
5+
# This example opens a psospa driver device, sets up two channels and a trigger then collects a block of data.
6+
# This data is then plotted as mV against time in ns.
7+
8+
import ctypes
9+
import numpy as np
10+
from picosdk.psospa import psospa as ps
11+
from picosdk.PicoDeviceEnums import picoEnum as enums
12+
from picosdk.PicoDeviceStructs import picoStruct as structs
13+
# from picosdk.PicoConnectProbes import picoConnectProbes as probes
14+
import matplotlib.pyplot as plt
15+
from picosdk.functions import adc2mVV2, mV2adcV2, assert_pico_ok
16+
17+
# Create chandle and status ready for use
18+
chandle = ctypes.c_int16()
19+
status = {}
20+
21+
# Open a psospa driver device
22+
# returns handle for future API functions
23+
resolution = enums.PICO_DEVICE_RESOLUTION["PICO_DR_8BIT"]
24+
status["openUnit"] = ps.psospaOpenUnit(ctypes.byref(chandle), None, resolution, None)
25+
assert_pico_ok(status["openUnit"])
26+
27+
# Set channel A on
28+
# handle = chandle
29+
channelA = enums.PICO_CHANNEL["PICO_CHANNEL_A"]
30+
coupling = enums.PICO_COUPLING["PICO_DC"]
31+
rangeMax = 2000000000 #nV
32+
rangeMin = -rangeMax #nV
33+
rangeType = 0 #probes.PICO_PROBE_RANGE_INFO["PICO_PROBE_NONE_NV"]
34+
analogueOffset = 0
35+
bandwidth = enums.PICO_BANDWIDTH_LIMITER["PICO_BW_FULL"]
36+
status["setChannelA"] = ps.psospaSetChannelOn(chandle, channelA, coupling, rangeMin, rangeMax, rangeType, analogueOffset, bandwidth)
37+
assert_pico_ok(status["setChannelA"])
38+
39+
# set channel B-D off
40+
for x in range (1, 3, 1):
41+
channel = x
42+
status["setChannel",x] = ps.psospaSetChannelOff(chandle,channel)
43+
assert_pico_ok(status["setChannel",x])
44+
45+
# get max ADC value
46+
# handle = chandle
47+
minADC = ctypes.c_int16()
48+
maxADC = ctypes.c_int16()
49+
status["getAdcLimits"] = ps.psospaGetAdcLimits(chandle, resolution, ctypes.byref(minADC), ctypes.byref(maxADC))
50+
assert_pico_ok(status["getAdcLimits"])
51+
52+
# Set simple trigger on channel A, 1 V rising with 1 s autotrigger
53+
# handle = chandle
54+
# enable = 1
55+
source = channelA
56+
# threshold = 100 mV
57+
direction = enums.PICO_THRESHOLD_DIRECTION["PICO_RISING"]
58+
# delay = 0 s
59+
# autoTriggerMicroSeconds = 1000000 us
60+
status["setSimpleTrigger"] = ps.psospaSetSimpleTrigger(chandle, 1, source, mV2adcV2(100,rangeMax,maxADC), direction, 0, 1000000)
61+
assert_pico_ok(status["setSimpleTrigger"])
62+
63+
# Get fastest available timebase
64+
# handle = chandle
65+
enabledChannelFlags = enums.PICO_CHANNEL_FLAGS["PICO_CHANNEL_A_FLAGS"]
66+
timebase = ctypes.c_uint32(0)
67+
timeInterval = ctypes.c_double(0)
68+
# resolution = resolution
69+
status["getMinimumTimebaseStateless"] = ps.psospaGetMinimumTimebaseStateless(chandle, enabledChannelFlags, ctypes.byref(timebase), ctypes.byref(timeInterval), resolution)
70+
print("timebase = ", timebase.value)
71+
print("sample interval =", timeInterval.value, "s")
72+
73+
# Set number of samples to be collected
74+
noOfPreTriggerSamples = 500000
75+
noOfPostTriggerSamples = 1000000
76+
nSamples = noOfPostTriggerSamples + noOfPreTriggerSamples
77+
78+
# Create buffers
79+
bufferAMax = (ctypes.c_int16 * nSamples)()
80+
bufferAMin = (ctypes.c_int16 * nSamples)() # used for downsampling which isn't in the scope of this example
81+
82+
# Set data buffers
83+
# handle = chandle
84+
# channel = channelA
85+
# bufferMax = bufferAMax
86+
# bufferMin = bufferAMin
87+
# nSamples = nSamples
88+
dataType = enums.PICO_DATA_TYPE["PICO_INT16_T"]
89+
waveform = 0
90+
downSampleMode = enums.PICO_RATIO_MODE["PICO_RATIO_MODE_RAW"]
91+
clear = enums.PICO_ACTION["PICO_CLEAR_ALL"]
92+
add = enums.PICO_ACTION["PICO_ADD"]
93+
action = clear|add # PICO_ACTION["PICO_CLEAR_WAVEFORM_CLEAR_ALL"] | PICO_ACTION["PICO_ADD"]
94+
status["setDataBuffers"] = ps.psospaSetDataBuffers(chandle, channelA, ctypes.byref(bufferAMax), ctypes.byref(bufferAMin), nSamples, dataType, waveform, downSampleMode, action)
95+
assert_pico_ok(status["setDataBuffers"])
96+
97+
# Run block capture
98+
# handle = chandle
99+
# timebase = timebase
100+
timeIndisposedMs = ctypes.c_double(0)
101+
# segmentIndex = 0
102+
# lpReady = None Using IsReady rather than a callback
103+
# pParameter = None
104+
status["runBlock"] = ps.psospaRunBlock(chandle, noOfPreTriggerSamples, noOfPostTriggerSamples, timebase, ctypes.byref(timeIndisposedMs), 0, None, None)
105+
assert_pico_ok(status["runBlock"])
106+
107+
# Check for data collection to finish using psospaIsReady
108+
ready = ctypes.c_int16(0)
109+
check = ctypes.c_int16(0)
110+
while ready.value == check.value:
111+
status["isReady"] = ps.psospaIsReady(chandle, ctypes.byref(ready))
112+
113+
# Get data from scope
114+
# handle = chandle
115+
# startIndex = 0
116+
noOfSamples = ctypes.c_uint64(nSamples)
117+
# downSampleRatio = 1
118+
# segmentIndex = 0
119+
overflow = ctypes.c_int16(0)
120+
status["getValues"] = ps.psospaGetValues(chandle, 0, ctypes.byref(noOfSamples), 1, downSampleMode, 0, ctypes.byref(overflow))
121+
assert_pico_ok(status["getValues"])
122+
123+
124+
125+
# # convert ADC counts data to mV
126+
adc2mVChAMax = adc2mVV2(bufferAMax, rangeMax, maxADC)
127+
128+
# Create time data
129+
time = np.linspace(0, (nSamples -1) * timeInterval.value * 1000000000, nSamples)
130+
131+
# plot data from channel A and B
132+
plt.plot(time, bufferAMax[:])
133+
plt.xlabel('Time (ns)')
134+
plt.ylabel('Voltage (mV)')
135+
plt.show()
136+
137+
# Close the psospa driver device
138+
status["closeUnit"] = ps.psospaCloseUnit(chandle)
139+
assert_pico_ok(status["closeUnit"])
140+
141+
print(status)

0 commit comments

Comments
 (0)