Skip to content

Commit e9c8f5d

Browse files
author
neil.hamilton
committed
Add ps3000aExamples/ps3000aStreamingExample.py
1 parent 4920ab4 commit e9c8f5d

File tree

2 files changed

+210
-0
lines changed

2 files changed

+210
-0
lines changed

picosdk/ps3000a.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
"""
99

1010
from ctypes import *
11+
from picosdk.ctypes_wrapper import C_CALLBACK_FUNCTION_FACTORY
1112
from picosdk.library import Library
1213
from picosdk.constants import make_enum
1314

Lines changed: 209 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,209 @@
1+
#
2+
# Copyright (C) 2018-2020 Pico Technology Ltd. See LICENSE file for terms.
3+
#
4+
# PS3000 Series (A API) STREAMING MODE EXAMPLE
5+
# This example demonstrates how to call the ps3000a driver API functions in order to open a device, setup 2 channels and collects streamed data (1 buffer).
6+
# This data is then plotted as mV against time in ns.
7+
8+
import ctypes
9+
import numpy as np
10+
from picosdk.ps3000a import ps3000a as ps
11+
import matplotlib.pyplot as plt
12+
from picosdk.functions import adc2mV, assert_pico_ok
13+
import time
14+
15+
# Create chandle and status ready for use
16+
chandle = ctypes.c_int16()
17+
status = {}
18+
19+
# Open PicoScope 5000 Series device
20+
status["openunit"] = ps.ps3000aOpenUnit(ctypes.byref(chandle), None)
21+
22+
try:
23+
assert_pico_ok(status["openunit"])
24+
except: # PicoNotOkError:
25+
26+
powerStatus = status["openunit"]
27+
28+
if powerStatus == 286:
29+
status["changePowerSource"] = ps.ps3000aChangePowerSource(chandle, powerStatus)
30+
elif powerStatus == 282:
31+
status["changePowerSource"] = ps.ps3000aChangePowerSource(chandle, powerStatus)
32+
else:
33+
raise
34+
35+
assert_pico_ok(status["changePowerSource"])
36+
37+
38+
enabled = 1
39+
disabled = 0
40+
analogue_offset = 0.0
41+
42+
# Set up channel A
43+
# handle = chandle
44+
# channel = PS3000A_CHANNEL_A = 0
45+
# enabled = 1
46+
# coupling type = PS3000A_DC = 1
47+
# range = PS3000A_2V = 7
48+
# analogue offset = 0 V
49+
channel_range = ps.PS3000A_RANGE['PS3000A_2V']
50+
status["setChA"] = ps.ps3000aSetChannel(chandle,
51+
ps.PS3000A_CHANNEL['PS3000A_CHANNEL_A'],
52+
enabled,
53+
ps.PS3000A_COUPLING['PS3000A_DC'],
54+
channel_range,
55+
analogue_offset)
56+
assert_pico_ok(status["setChA"])
57+
58+
# Set up channel B
59+
# handle = chandle
60+
# channel = PS3000A_CHANNEL_B = 1
61+
# enabled = 1
62+
# coupling type = PS3000A_DC = 1
63+
# range = PS3000A_2V = 7
64+
# analogue offset = 0 V
65+
status["setChB"] = ps.ps3000aSetChannel(chandle,
66+
ps.PS3000A_CHANNEL['PS3000A_CHANNEL_B'],
67+
enabled,
68+
ps.PS3000A_COUPLING['PS3000A_DC'],
69+
channel_range,
70+
analogue_offset)
71+
assert_pico_ok(status["setChB"])
72+
73+
# Size of capture
74+
sizeOfOneBuffer = 500
75+
numBuffersToCapture = 10
76+
77+
totalSamples = sizeOfOneBuffer * numBuffersToCapture
78+
79+
# Create buffers ready for assigning pointers for data collection
80+
bufferAMax = np.zeros(shape=sizeOfOneBuffer, dtype=np.int16)
81+
bufferBMax = np.zeros(shape=sizeOfOneBuffer, dtype=np.int16)
82+
83+
memory_segment = 0
84+
85+
# Set data buffer location for data collection from channel A
86+
# handle = chandle
87+
# source = PS3000A_CHANNEL_A = 0
88+
# pointer to buffer max = ctypes.byref(bufferAMax)
89+
# pointer to buffer min = ctypes.byref(bufferAMin)
90+
# buffer length = maxSamples
91+
# segment index = 0
92+
# ratio mode = PS3000A_RATIO_MODE_NONE = 0
93+
status["setDataBuffersA"] = ps.ps3000aSetDataBuffers(chandle,
94+
ps.PS3000A_CHANNEL['PS3000A_CHANNEL_A'],
95+
bufferAMax.ctypes.data_as(ctypes.POINTER(ctypes.c_int16)),
96+
None,
97+
sizeOfOneBuffer,
98+
memory_segment,
99+
ps.PS3000A_RATIO_MODE['PS3000A_RATIO_MODE_NONE'])
100+
assert_pico_ok(status["setDataBuffersA"])
101+
102+
# Set data buffer location for data collection from channel B
103+
# handle = chandle
104+
# source = PS3000A_CHANNEL_B = 1
105+
# pointer to buffer max = ctypes.byref(bufferBMax)
106+
# pointer to buffer min = ctypes.byref(bufferBMin)
107+
# buffer length = maxSamples
108+
# segment index = 0
109+
# ratio mode = PS3000A_RATIO_MODE_NONE = 0
110+
status["setDataBuffersB"] = ps.ps3000aSetDataBuffers(chandle,
111+
ps.PS3000A_CHANNEL['PS3000A_CHANNEL_B'],
112+
bufferBMax.ctypes.data_as(ctypes.POINTER(ctypes.c_int16)),
113+
None,
114+
sizeOfOneBuffer,
115+
memory_segment,
116+
ps.PS3000A_RATIO_MODE['PS3000A_RATIO_MODE_NONE'])
117+
assert_pico_ok(status["setDataBuffersB"])
118+
119+
# Begin streaming mode:
120+
sampleInterval = ctypes.c_int32(250)
121+
sampleUnits = ps.PS3000A_TIME_UNITS['PS3000A_US']
122+
# We are not triggering:
123+
maxPreTriggerSamples = 0
124+
autoStopOn = 1
125+
# No downsampling:
126+
downsampleRatio = 1
127+
status["runStreaming"] = ps.ps3000aRunStreaming(chandle,
128+
ctypes.byref(sampleInterval),
129+
sampleUnits,
130+
maxPreTriggerSamples,
131+
totalSamples,
132+
autoStopOn,
133+
downsampleRatio,
134+
ps.PS3000A_RATIO_MODE['PS3000A_RATIO_MODE_NONE'],
135+
sizeOfOneBuffer)
136+
assert_pico_ok(status["runStreaming"])
137+
138+
actualSampleInterval = sampleInterval.value
139+
actualSampleIntervalNs = actualSampleInterval * 1000
140+
141+
print("Capturing at sample interval %s ns" % actualSampleIntervalNs)
142+
143+
# We need a big buffer, not registered with the driver, to keep our complete capture in.
144+
bufferCompleteA = np.zeros(shape=totalSamples, dtype=np.int16)
145+
bufferCompleteB = np.zeros(shape=totalSamples, dtype=np.int16)
146+
nextSample = 0
147+
autoStopOuter = False
148+
wasCalledBack = False
149+
150+
151+
def streaming_callback(handle, noOfSamples, startIndex, overflow, triggerAt, triggered, autoStop, param):
152+
global nextSample, autoStopOuter, wasCalledBack
153+
wasCalledBack = True
154+
destEnd = nextSample + noOfSamples
155+
sourceEnd = startIndex + noOfSamples
156+
bufferCompleteA[nextSample:destEnd] = bufferAMax[startIndex:sourceEnd]
157+
bufferCompleteB[nextSample:destEnd] = bufferBMax[startIndex:sourceEnd]
158+
nextSample += noOfSamples
159+
if autoStop:
160+
autoStopOuter = True
161+
162+
163+
# Convert the python function into a C function pointer.
164+
cFuncPtr = ps.StreamingReadyType(streaming_callback)
165+
166+
# Fetch data from the driver in a loop, copying it out of the registered buffers and into our complete one.
167+
while nextSample < totalSamples and not autoStopOuter:
168+
wasCalledBack = False
169+
status["getStreamingLastestValues"] = ps.ps3000aGetStreamingLatestValues(chandle, cFuncPtr, None)
170+
if not wasCalledBack:
171+
# If we weren't called back by the driver, this means no data is ready. Sleep for a short while before trying
172+
# again.
173+
time.sleep(0.01)
174+
175+
print("Done grabbing values.")
176+
177+
# Find maximum ADC count value
178+
# handle = chandle
179+
# pointer to value = ctypes.byref(maxADC)
180+
maxADC = ctypes.c_int16()
181+
status["maximumValue"] = ps.ps3000aMaximumValue(chandle, ctypes.byref(maxADC))
182+
assert_pico_ok(status["maximumValue"])
183+
184+
# Convert ADC counts data to mV
185+
adc2mVChAMax = adc2mV(bufferCompleteA, channel_range, maxADC)
186+
adc2mVChBMax = adc2mV(bufferCompleteB, channel_range, maxADC)
187+
188+
# Create time data
189+
time = np.linspace(0, (totalSamples) * actualSampleIntervalNs, totalSamples)
190+
191+
# Plot data from channel A and B
192+
plt.plot(time, adc2mVChAMax[:])
193+
plt.plot(time, adc2mVChBMax[:])
194+
plt.xlabel('Time (ns)')
195+
plt.ylabel('Voltage (mV)')
196+
plt.show()
197+
198+
# Stop the scope
199+
# handle = chandle
200+
status["stop"] = ps.ps3000aStop(chandle)
201+
assert_pico_ok(status["stop"])
202+
203+
# Disconnect the scope
204+
# handle = chandle
205+
status["close"] = ps.ps3000aCloseUnit(chandle)
206+
assert_pico_ok(status["close"])
207+
208+
# Display status returns
209+
print(status)

0 commit comments

Comments
 (0)