High speed streaming/triggering on 6000a series SDK

Having problems ? let us know the details here
Post Reply
dbsmith
Newbie
Posts: 1
Joined: Mon Oct 04, 2021 4:06 am

High speed streaming/triggering on 6000a series SDK

Post by dbsmith »

I am trying to adapt the Picoscope 6424E in Streaming mode for use as a detector in an optical coherence tomography (OCT) imaging application. I am running the ps6000a series SDK in a 64 bit java development environment using JNA to access the dll library. The Picoscope is connected via USB 3.0.

On channel A, I have a pseudo-repeating signal with a 50us cycle. I want to interrogate this signal in batches of 50us duration with a ~4ns sample interval. Importantly, I don't need to capture every single batch, but am ok with just capturing every few. E.g., I'm ok dropping data so long as I get an uninterrupted cycle every 250-300us (1:4 or 1:6 cycles). Ideally, I'd like to capture a sample every 3.2ns so I can get at least 10k samples per cycle, but I'll make due with a 6.4ns interval to grab 7.8k samples if necessary. It's not obvious looking at the data where the "beginning" of each batch is, so I rely on a second channel to trigger.

On channel B, I have a trigger signal, with the falling edge aligned to the beginning of each cycle of channel A.

On channel C, I have another signal used for an unrelated purpose. Importantly, I don't need to interrogate that signal NEARLY as frequently, I just want a single value corresponding to each channel B trigger.

As an output, I need to produce a batch of 7-10k samples from channel A (40-50us in duration), and a single sample from channel C, every 250-300us aligned with the trigger from channel B. I don't care what channel B data contains apart from its triggering functionality (1V threshold, falling edge). I understand that streaming mode doesn't operate with repeated triggering, and that I have to parse the streaming data myself to identify and batch off the trigger. The issue that I'm running into is that while I only need ~35MS/s across these burst windows (~10k samples every 250-300us), the requirement to download ALL the data rather than post-trigger bursts, coupled with having to download the trigger data, exceeds the USB 3.0 capabilities by about 3X.

I THINK that the solution is to just stream the data as fast as I can, expect that waiting for full buffers via polling ps6000aGetStreamingLatestValues will introduce latency, and that a full iteration will still occur every ~300us. I'm running into some trouble understanding how the ps6000a Streaming API works with multiple channels, and if it's possible to downSample different channels at different rates. E.g., run channels A/B raw and decimate channel C at 10k:1.

Here is my pseudocode:

Code: Select all

	//Open my scope and get handle
	short handle = ps6000aOpenUnit();

	//Set channels
	ps6000aSetChannelOn(handle, PICO_CHANNEL.PICO_CHANNEL_A, PICO_COUPLING.PICO_DC, PICO_CONNECT_PROBE_RANGE.PICO_2V, 0.0, PICO_BANDWIDTH_LIMITER.PICO_BW_FULL);
	ps6000aSetChannelOn(handle, PICO_CHANNEL.PICO_CHANNEL_B, PICO_COUPLING.PICO_DC, PICO_CONNECT_PROBE_RANGE.PICO_5V, 0.0, PICO_BANDWIDTH_LIMITER.PICO_BW_FULL);
	ps6000aSetChannelOn(handle, PICO_CHANNEL.PICO_CHANNEL_C, PICO_COUPLING.PICO_DC, PICO_CONNECT_PROBE_RANGE.PICO_5V, 0.0, PICO_BANDWIDTH_LIMITER.PICO_BW_FULL);
	
	//Set buffers first time
	//nSamples = 20480. Desired batch length of 10240, 2x ensures a full capture post trigger
	//Buffer length = 20480. PICO_INT8_T data type, 2*nSamples
	PICO_POINTER bufferA = new PICO_POINTER(20480);
	PICO_POINTER bufferB = new PICO_POINTER(20480);
	PICO_POINTER bufferC = new PICO_POINTER(20480);
	ps6000aSetDataBuffer(handle, PICO_CHANNEL.PICO_CHANNEL_A, bufferA, 20480, PICO_DATA_TYPE.PICO_INT8_T, 0L, PICO_RATIO_MODE.PICO_RATIO_MODE_RAW, PICO_ACTION.PICO_ADD);
	ps6000aSetDataBuffer(handle, PICO_CHANNEL.PICO_CHANNEL_B, bufferB, 20480, PICO_DATA_TYPE.PICO_INT8_T, 0L, PICO_RATIO_MODE.PICO_RATIO_MODE_RAW, PICO_ACTION.PICO_ADD);
	ps6000aSetDataBuffer(handle, PICO_CHANNEL.PICO_CHANNEL_C, bufferC, 20480, PICO_DATA_TYPE.PICO_INT8_T, 0L, PICO_RATIO_MODE.PICO_RATIO_MODE_RAW, PICO_ACTION.PICO_ADD);

	//Start streaming mode
	Integer interval = 3.2;
	ps6000aRunStreaming(handle, interval, PICO_TIME_UNITS.PICO_NS, 0L, 0L, (short)0, 1L, PICO_RATIO_MODE_RAW);
	long nStreamingDataInfos = 1L;
	PICO_STREAMING_DATA_INFO[] dataInfos = [{
		PICO_CHANNEL.PICO_CHANNEL_A, PICO_RATIO_MODE.PICO_RATIO_MODE_RAW, PICO_DATA_TYPE.PICO_INT8_T, 0, 0L, 0, (short)0
	}];
	PICO_STREAMING_DATA_TRIGGER_INFO triggerInfos = [{
		0L, (short)0, (short)0
	}]

	//Loop until aborted from external source
	while(!stop) {
		//Wait for buffers to fill
		do {
			PICO_STATUS status = ps6000aGetStreamingLatestValues(handle,dataInfos,nStreamingDataInfos,triggerInfos);
		} while(status != PICO_STATUS.PICO_WAITING_FOR_DATA_BUFFERS)

		//find trigger index in bufferB, grab subsets from bufferA/bufferC, pass to external thread/queue for handling
		handleData(bufferA,bufferB,bufferC) 
		
		//Refresh buffers
		PICO_POINTER bufferA = new PICO_POINTER(20480);
		PICO_POINTER bufferB = new PICO_POINTER(20480);
		PICO_POINTER bufferC = new PICO_POINTER(20480);
		ps6000aSetDataBuffer(handle, PICO_CHANNEL.PICO_CHANNEL_A, bufferA, 20480, PICO_DATA_TYPE.PICO_INT8_T, 0L, PICO_RATIO_MODE.PICO_RATIO_MODE_RAW, PICO_ACTION.PICO_ADD);
		ps6000aSetDataBuffer(handle, PICO_CHANNEL.PICO_CHANNEL_B, bufferB, 20480, PICO_DATA_TYPE.PICO_INT8_T, 0L, PICO_RATIO_MODE.PICO_RATIO_MODE_RAW, PICO_ACTION.PICO_ADD);
		ps6000aSetDataBuffer(handle, PICO_CHANNEL.PICO_CHANNEL_C, bufferC, 20480, PICO_DATA_TYPE.PICO_INT8_T, 0L, PICO_RATIO_MODE.PICO_RATIO_MODE_RAW, PICO_ACTION.PICO_ADD);
	}
	
	//Close
	ps6000aStop(handle);
	ps6000aCloseUnit(handle);

Questions:
1. At this sampling rate, is there any other way to collect multiple triggered bursts of streaming data other than to download and parse the trigger manually?
2. Is it possible to introduce different down-sample ratios per channel at the buffer level in any way? Specifically I'm trying to reduce the load across the USB.
3. I'm confused about the structs in the ps6000aGetStreamingLatestValues calls. Specifically, am I passing any data TO the method when I first call it, or do I just initialize the memory without populating the fields within each PICO_STREAMING_DATA_INFO? And what exactly does the nStreamingDataInfos flag DO, other than defining the length of the struct. How do you decide the value, do I have to set up nStreamingDataInfos based on the number of channels, the number of memory segments......?
4. Running this code for a until the buffer fills a few times seems to run ok, but if I try to run it for 10k+ buffer fills, I eventually get a PICO_DEVICE_MEMORY_OVERFLOW status from ps6000aGetStreamingLatestValues. I thought that adding new buffers via PICO_ACTION.PICO_ADD is supposed to prevent that? Any variation of a PICO_ACTION.*CLEAR* after I start the run throws an error at me. How do I tell the picoscope to clean its own buffers during the run?

Thanks,
David

Post Reply