How to get live output into python GUI?

Having problems ? let us know the details here
Post Reply
GenericDude
Newbie
Posts: 1
Joined: Tue Mar 05, 2024 8:15 am

How to get live output into python GUI?

Post by GenericDude »

I'm using picoscope 4224 and I want to operate it using only Python wrappers, because of compatibility reasons.

I need to have a live oscilloscope output in my GUI. For GUI I Choose pyqtgraph, because it's fast and powerful.

I wrote the code you can see below, and indeed I receive some live plotting, but not only it is slow (I've seen pyqtgraph being much faster with much more complex data). What is worse is that at some point, I just apparently can't squeze more data into the buffer - it gives me the following message:
File "C:\Filename\deleteme2.py", line 139, in streaming_callback
bufferCompleteA[nextSample:destEnd] = bufferAMax[startIndex:sourceEnd]
ValueError: could not broadcast input array from shape (197,) into shape (0,)
To always have streaming enabled I have set autostop to 0. How can I get rid of the ValueError, and how to make the program run faster?

Here is the entire python program:

Code: Select all

#
# Copyright (C) 2018-2022 Pico Technology Ltd. See LICENSE file for terms.
#
# PS4000 Series (A API) STREAMING MODE EXAMPLE
# This example demonstrates how to call the ps4000 driver API functions in order to open a device, setup 2 channels and collects streamed data (1 buffer).
# This data is then plotted as mV against time in ns.

import ctypes
import numpy as np
from picosdk.ps4000 import ps4000 as ps
import matplotlib.pyplot as plt
from picosdk.functions import adc2mV, assert_pico_ok
import time
import pyqtgraph as pg



pw = pg.plot()

# Create chandle and status ready for use
chandle = ctypes.c_int16()
status = {}

# Open PicoScope 4000 Series device
# Returns handle to chandle for use in future API functions
status["openunit"] = ps.ps4000OpenUnit(ctypes.byref(chandle))
assert_pico_ok(status["openunit"])


enabled = 1
disabled = 0
analogue_offset = 0.0

# Set up channel A
# handle = chandle
# channel = PS4000_CHANNEL_A = 0
# enabled = 1
# coupling type = PS4000_DC = 1
# range = PS4000_2V = 7
channel_range = ps.PS4000_RANGE['PS4000_2V']
status["setChA"] = ps.ps4000SetChannel(chandle,
                                        ps.PS4000_CHANNEL['PS4000_CHANNEL_A'],
                                        enabled,
                                        1,
                                        channel_range)
assert_pico_ok(status["setChA"])

# Set up channel B
# handle = chandle
# channel = PS4000_CHANNEL_B = 1
# enabled = 1
# coupling type = PS4000_DC = 1
# range = PS4000_2V = 7
status["setChB"] = ps.ps4000SetChannel(chandle,
                                        ps.PS4000_CHANNEL['PS4000_CHANNEL_B'],
                                        enabled,
                                        1,
                                        channel_range)
assert_pico_ok(status["setChB"])

# Size of capture
sizeOfOneBuffer = 500
numBuffersToCapture = 10

totalSamples = sizeOfOneBuffer * numBuffersToCapture

# Create buffers ready for assigning pointers for data collection
bufferAMax = np.zeros(shape=sizeOfOneBuffer, dtype=np.int16)
bufferBMax = np.zeros(shape=sizeOfOneBuffer, dtype=np.int16)

memory_segment = 0

# Set data buffer location for data collection from channel A
# handle = chandle
# source = PS4000_CHANNEL_A = 0
# pointer to buffer max = ctypes.byref(bufferAMax)
# pointer to buffer min = ctypes.byref(bufferAMin)
# buffer length = maxSamples
# segment index = 0
# ratio mode = PS4000_RATIO_MODE_NONE = 0
status["setDataBuffersA"] = ps.ps4000SetDataBuffers(chandle,
                                                     ps.PS4000_CHANNEL['PS4000_CHANNEL_A'],
                                                     bufferAMax.ctypes.data_as(ctypes.POINTER(ctypes.c_int16)),
                                                     None,
                                                     sizeOfOneBuffer)
assert_pico_ok(status["setDataBuffersA"])

# Set data buffer location for data collection from channel B
# handle = chandle
# source = PS4000_CHANNEL_B = 1
# pointer to buffer max = ctypes.byref(bufferBMax)
# pointer to buffer min = ctypes.byref(bufferBMin)
# buffer length = maxSamples
# segment index = 0
# ratio mode = PS4000_RATIO_MODE_NONE = 0
status["setDataBuffersB"] = ps.ps4000SetDataBuffers(chandle,
                                                     ps.PS4000_CHANNEL['PS4000_CHANNEL_B'],
                                                     bufferBMax.ctypes.data_as(ctypes.POINTER(ctypes.c_int16)),
                                                     None,
                                                     sizeOfOneBuffer)
assert_pico_ok(status["setDataBuffersB"])

# Begin streaming mode:
sampleInterval = ctypes.c_int32(250)
sampleUnits = ps.PS4000_TIME_UNITS['PS4000_US']
# We are not triggering:
maxPreTriggerSamples = 0
autoStopOn = 0
# No downsampling:
downsampleRatio = 1
status["runStreaming"] = ps.ps4000RunStreaming(chandle,
                                                ctypes.byref(sampleInterval),
                                                sampleUnits,
                                                maxPreTriggerSamples,
                                                totalSamples,
                                                autoStopOn,
                                                downsampleRatio,
                                                sizeOfOneBuffer)
assert_pico_ok(status["runStreaming"])

actualSampleInterval = sampleInterval.value
actualSampleIntervalNs = actualSampleInterval * 1000

print("Capturing at sample interval %s ns" % actualSampleIntervalNs)

# We need a big buffer, not registered with the driver, to keep our complete capture in.
bufferCompleteA = np.zeros(shape=totalSamples, dtype=np.int16)
bufferCompleteB = np.zeros(shape=totalSamples, dtype=np.int16)



nextSample = 0
autoStopOuter = False
wasCalledBack = False


def streaming_callback(handle, noOfSamples, startIndex, overflow, triggerAt, triggered, autoStop, param):
    global nextSample, autoStopOuter, wasCalledBack
    wasCalledBack = True
    destEnd = nextSample + noOfSamples
    sourceEnd = startIndex + noOfSamples
    bufferCompleteA[nextSample:destEnd] = bufferAMax[startIndex:sourceEnd]
    bufferCompleteB[nextSample:destEnd] = bufferBMax[startIndex:sourceEnd]
    nextSample += noOfSamples
    if autoStop:
        autoStopOuter = True


# Convert the python function into a C function pointer.
cFuncPtr = ps.StreamingReadyType(streaming_callback)

# Fetch data from the driver in a loop, copying it out of the registered buffers and into our complete one.
while True:
    wasCalledBack = False
    status["getStreamingLastestValues"] = ps.ps4000GetStreamingLatestValues(chandle, cFuncPtr, None)
    # Find maximum ADC count value
    # handle = chandle
    # pointer to value = ctypes.byref(maxADC)
    maxADC = ctypes.c_int16(32767)

    # Convert ADC counts data to mV
    adc2mVChAMax = adc2mV(bufferCompleteA, channel_range, maxADC)
    adc2mVChBMax = adc2mV(bufferCompleteB, channel_range, maxADC)

    # Create time data
    zeit = np.linspace(0, (totalSamples - 1) * actualSampleIntervalNs, totalSamples)

    pw.plot(zeit, adc2mVChAMax, clear=True)

    pg.QtGui.QGuiApplication.processEvents()
    if not wasCalledBack:
        # If we weren't called back by the driver, this means no data is ready. Sleep for a short while before trying
        # again.
        time.sleep(0.01)

print("Done grabbing values.")



# Stop the scope
# handle = chandle
status["stop"] = ps.ps4000Stop(chandle)
assert_pico_ok(status["stop"])

# Disconnect the scope
# handle = chandle
status["close"] = ps.ps4000CloseUnit(chandle)
assert_pico_ok(status["close"])

# Display status returns
print(status)

NeilH
PICO STAFF
PICO STAFF
Posts: 271
Joined: Tue Jul 18, 2017 8:28 am

Re: How to get live output into python GUI?

Post by NeilH »

Hi

To resolve the error message you're getting you could increase the size of the buffer that the data is copied into after collection to be significantly larger than you think it needs to be (so long as you have the RAM to accommodate this). The example is set to only collect a short time of streamed data and therefore has quite a small overview buffer which wouldn't be large enough if you've turned off the autoStop in the code to continuously capture.
Neil
Technical Support Engineer

Post Reply