Streaming from 5444D extremely slow

Post your C and C++ discussions here
Post Reply
justinis
Newbie
Posts: 0
Joined: Wed Oct 27, 2021 11:04 pm

Streaming from 5444D extremely slow

Post by justinis »

I'm trying to stream a couple seconds of data at 16bits, max sample rate (62.5 MS/s) from a 5444D. The code below is working, but it takes several minutes to collect just 0.3 seconds of data. What am I doing wrong? I am using the python wrappers for C.

Code: Select all

print('Connecting to scope')
	# Create chandle and status ready for use
	chandle = ctypes.c_int16()
	status = {}

	# Open PicoScope 5000 Series device

	# Resolution set to 12 Bit
	resolution =ps5.PS5000A_DEVICE_RESOLUTION["PS5000A_DR_16BIT"]

	# Returns handle to chandle for use in future API functions
	status["openunit"] = ps5.ps5000aOpenUnit(ctypes.byref(chandle), None, resolution)
	
	try:
		assert_pico_ok(status["openunit"])
	
	except: # PicoNotOkError:

		powerStatus = status["openunit"]

		if powerStatus == 286:
			status["changePowerSource"] = ps5.ps5000aChangePowerSource(chandle, powerStatus)
		elif powerStatus == 282:
			status["changePowerSource"] = ps5.ps5000aChangePowerSource(chandle, powerStatus)
		else:
			raise
		
		assert_pico_ok(status["changePowerSource"])

	enabled = 1
	disabled = 0
	analogue_offset = 0.0

	# Set up channel A
	# handle = chandle
	# channel = PS5000_CHANNEL_A = 0
	# enabled = 1
	# coupling type = PS5000_DC = 1
	# analogue offset = 0 V

	print('Setting scope chan A range to +/-' + str(SCOPE_RANGE_VOLTS[scopeRange]) + 'V')

	# there has got to be a better way
	channel_range = ps5.PS5000A_RANGE[list(ps5.PS5000A_RANGE)[scopeRange]]

	status["setChA"] = ps5.ps5000aSetChannel(chandle,
											ps5.PS5000A_CHANNEL['PS5000A_CHANNEL_A'],
											enabled,
											coupling,
											channel_range,
											analogue_offset)
	assert_pico_ok(status["setChA"])

	print('Disabling scope chan B')

	# Disable channel B
	status["disableChB"] = ps5.ps5000aSetChannel(chandle, 
										ps5.PS5000A_CHANNEL['PS5000A_CHANNEL_B'], 
										0, 
										1, 
										channel_range,
										analogue_offset)
	assert_pico_ok(status["disableChB"])

	''' Channels C and D are automatically disabled if on USB power
	# Disable channel C
	status["disableChC"] = ps5.ps5000aSetChannel(chandle, 
										ps5.PS5000A_CHANNEL['PS5000A_CHANNEL_C'], 
										0, 
										1, 
										channel_range,
										analogue_offset)
	assert_pico_ok(status["disableChC"])

	# Disable channel D
	status["disableChD"] = ps5.ps5000aSetChannel(chandle, 
										ps5.PS5000A_CHANNEL['PS5000A_CHANNEL_D'], 
										0, 
										1, 
										channel_range,
										analogue_offset)
	assert_pico_ok(status["disableChD"])
	'''

	print('Configuring data buffers')

	# Size of capture
	totalSamples = sizeOfOneBuffer * numBuffersToCapture

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

	memory_segment = 0

	# Set data buffer location for data collection from channel A
	# handle = chandle
	# source = PS5000A_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 = PS5000A_RATIO_MODE_NONE = 0
	status["setDataBuffersA"] = ps5.ps5000aSetDataBuffers(chandle,
														ps5.PS5000A_CHANNEL['PS5000A_CHANNEL_A'],
														bufferAMax.ctypes.data_as(ctypes.POINTER(ctypes.c_int16)),
														None,
														sizeOfOneBuffer,
														memory_segment,
														ps5.PS5000A_RATIO_MODE['PS5000A_RATIO_MODE_NONE'])
	assert_pico_ok(status["setDataBuffersA"])

	# Begin streaming mode:
	sampleInterval = ctypes.c_int32(SAMPLE_PER_NS)
	#sampleInterval = ctypes.c_int32(100)
	sampleUnits = ps5.PS5000A_TIME_UNITS['PS5000A_US']
	#sampleUnits = ps.PS4000_TIME_UNITS['PS4000_NS']
	# We are not triggering:
	maxPreTriggerSamples = 0
	autoStopOn = 0
	# No downsampling:
	downsampleRatio = 1
	status["runStreaming"] = ps5.ps5000aRunStreaming(chandle,
													ctypes.byref(sampleInterval),
													sampleUnits,
													maxPreTriggerSamples,
													totalSamples,
													autoStopOn,
													downsampleRatio,
													ps5.PS5000A_RATIO_MODE['PS5000A_RATIO_MODE_NONE'],
													sizeOfOneBuffer)
	assert_pico_ok(status["runStreaming"])

	print('Capturing at sample interval '+ str(SAMPLE_PER_NS) + 'ns from preamp ' + preName)

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

	# after putting everything in a function, the program would fail on the line "destEnd = nextSample + noOfSamples" saying nextSample was not defined
	# I could tell nextSample was unbound, and the line below these comments fixed that
	# TBH I don't really understand the problem and why this fixed it
	global nextSample 
	
	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]
		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 nextSample < totalSamples and not autoStopOuter:
		wasCalledBack = False
		status["getStreamingLastestValues"] = ps5.ps5000aGetStreamingLatestValues(chandle, cFuncPtr, None)
		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("Capture complete")

justinis
Newbie
Posts: 0
Joined: Wed Oct 27, 2021 11:04 pm

Re: Streaming from 5444D extremely slow

Post by justinis »

I tried changing the code to block mode, because I realized I am limited to 15.625 MS/s in streaming mode, according to the programmer's guide. Now the code hangs on ps5.ps5000aGetValues if I try to capture more than 200,000 samples (sizeOfOneBuffer = 200000, numBuffersToCapture = 1, SAMPLE_PER_NS = 16). What gives?

Code: Select all

	print('Connecting to scope')
	# Create chandle and status ready for use
	chandle = ctypes.c_int16()
	status = {}

	# Open 5000 series PicoScope
	# Resolution set to 16 Bit
	resolution =ps5.PS5000A_DEVICE_RESOLUTION["PS5000A_DR_16BIT"]
	# Returns handle to chandle for use in future API functions
	status["openunit"] = ps5.ps5000aOpenUnit(ctypes.byref(chandle), None, resolution)

	try:
		assert_pico_ok(status["openunit"])
	except: # PicoNotOkError:

		powerStatus = status["openunit"]

		if powerStatus == 286:
			status["changePowerSource"] = ps5.ps5000aChangePowerSource(chandle, powerStatus)
		elif powerStatus == 282:
			status["changePowerSource"] = ps5.ps5000aChangePowerSource(chandle, powerStatus)
		else:
			raise

		assert_pico_ok(status["changePowerSource"])

	print('Setting scope chan A range to +/-' + str(SCOPE_RANGE_VOLTS[scopeRange]) + 'V')

	# Set up channel A
	# handle = chandle
	channel = ps5.PS5000A_CHANNEL["PS5000A_CHANNEL_A"]
	# enabled = 1
	coupling_type = coupling
	# there has got to be a better way
	chARange = ps5.PS5000A_RANGE[list(ps5.PS5000A_RANGE)[scopeRange]]
	# analogue offset = 0 V
	status["setChA"] = ps5.ps5000aSetChannel(chandle, channel, 1, coupling_type, chARange, 0)
	assert_pico_ok(status["setChA"])

	print('Disabling scope chan B')

	# Disable up channel B
	# handle = chandle
	channel = ps5.PS5000A_CHANNEL["PS5000A_CHANNEL_B"]
	# enabled = 1
	# coupling_type = ps.PS5000A_COUPLING["PS5000A_DC"]
	chBRange = ps5.PS5000A_RANGE["PS5000A_2V"]
	# analogue offset = 0 V
	status["setChB"] = ps5.ps5000aSetChannel(chandle, channel, 0, coupling_type, chBRange, 0)
	assert_pico_ok(status["setChB"])

	# find maximum ADC count value
	# handle = chandle
	# pointer to value = ctypes.byref(maxADC)
	maxADC = ctypes.c_int16()
	status["maximumValue"] = ps5.ps5000aMaximumValue(chandle, ctypes.byref(maxADC))
	assert_pico_ok(status["maximumValue"])

	# Set up single trigger
	# handle = chandle
	# enabled = 1
	source = ps5.PS5000A_CHANNEL["PS5000A_CHANNEL_A"]
	threshold = int(mV2adc(500,chARange, maxADC))
	# direction = PS5000A_RISING = 2
	# delay = 0 s
	# auto Trigger = 1000 ms
	status["trigger"] = ps5.ps5000aSetSimpleTrigger(chandle, 1, source, threshold, 2, 0, 1000)
	assert_pico_ok(status["trigger"])

	# Set number of pre and post trigger samples to be collected
	preTriggerSamples = 0
	postTriggerSamples = sizeOfOneBuffer * numBuffersToCapture
	maxSamples = preTriggerSamples + postTriggerSamples

	# Get timebase information
	# Warning: When using this example it may not be possible to access all Timebases as all channels are enabled by default when opening the scope.  
	# To access these Timebases, set any unused analogue channels to off.
	# handle = chandle
	timebase = int(SAMPLE_PER_NS * 0.0625 + 3)
	# noSamples = maxSamples
	# pointer to timeIntervalNanoseconds = ctypes.byref(timeIntervalns)
	# pointer to maxSamples = ctypes.byref(returnedMaxSamples)
	# segment index = 0
	timeIntervalns = ctypes.c_float()
	returnedMaxSamples = ctypes.c_int32()
	status["getTimebase2"] = ps5.ps5000aGetTimebase2(chandle, timebase, maxSamples, ctypes.byref(timeIntervalns), ctypes.byref(returnedMaxSamples), 0)
	assert_pico_ok(status["getTimebase2"])

	print('Capturing at sample interval '+ str(SAMPLE_PER_NS) + 'ns from preamp ' + preName)

	# Run block capture
	# handle = chandle
	# number of pre-trigger samples = preTriggerSamples
	# number of post-trigger samples = PostTriggerSamples
	# timebase = 8 = 80 ns (see Programmer's guide for mre information on timebases)
	# time indisposed ms = None (not needed in the example)
	# segment index = 0
	# lpReady = None (using ps5000aIsReady rather than ps5000aBlockReady)
	# pParameter = None
	status["runBlock"] = ps5.ps5000aRunBlock(chandle, preTriggerSamples, postTriggerSamples, timebase, None, 0, None, None)
	assert_pico_ok(status["runBlock"])

	# Check for data collection to finish using ps5000aIsReady
	ready = ctypes.c_int16(0)
	check = ctypes.c_int16(0)
	while ready.value == check.value:
		status["isReady"] = ps5.ps5000aIsReady(chandle, ctypes.byref(ready))
	
	print('Configuring data buffers')

	# Create buffers ready for assigning pointers for data collection
	bufferAMax = (ctypes.c_int16 * maxSamples)()
	bufferAMin = (ctypes.c_int16 * maxSamples)() # used for downsampling which isn't in the scope of this example

	# Set data buffer location for data collection from channel A
	# handle = chandle
	source = ps5.PS5000A_CHANNEL["PS5000A_CHANNEL_A"]
	# pointer to buffer max = ctypes.byref(bufferAMax)
	# pointer to buffer min = ctypes.byref(bufferAMin)
	# buffer length = maxSamples
	# segment index = 0
	# ratio mode = PS5000A_RATIO_MODE_NONE = 0
	status["setDataBuffersA"] = ps5.ps5000aSetDataBuffers(chandle, source, ctypes.byref(bufferAMax), ctypes.byref(bufferAMin), maxSamples, 0, 0)
	assert_pico_ok(status["setDataBuffersA"])

	# create overflow loaction
	overflow = ctypes.c_int16()
	# create converted type maxSamples
	cmaxSamples = ctypes.c_int32(maxSamples)

	print("Moving data from scope to buffers")

	# Retried data from scope to buffers assigned above
	# handle = chandle
	# start index = 0
	# pointer to number of samples = ctypes.byref(cmaxSamples)
	# downsample ratio = 0
	# downsample ratio mode = PS5000A_RATIO_MODE_NONE
	# pointer to overflow = ctypes.byref(overflow))
	status["getValues"] = ps5.ps5000aGetValues(chandle, 0, ctypes.byref(cmaxSamples), 0, 0, 0, ctypes.byref(overflow))
	assert_pico_ok(status["getValues"])

	print("Capture complete")

justinis
Newbie
Posts: 0
Joined: Wed Oct 27, 2021 11:04 pm

Re: Streaming from 5444D extremely slow

Post by justinis »

I confirmed my 5444D connection is USB 3.0

justinis
Newbie
Posts: 0
Joined: Wed Oct 27, 2021 11:04 pm

Re: Streaming from 5444D extremely slow

Post by justinis »

I have fixed the problem with the block code. For some reason, the picoscope hangs when transferring large amounts of data if I have it plugged into my Anker USB hub. If I plug the scope directly into my laptop, it works. I did not go back to check if this is what was affecting the streaming code as well.

Post Reply