Trigger Arming Time

Just about everything about Red Pitaya
Post Reply
gregoryk
Posts: 5
Joined: Tue Apr 05, 2016 6:40 pm

Trigger Arming Time

Post by gregoryk » Tue Jun 07, 2016 12:03 am

Hi,

I was hoping to get a few tips on how I can improve my current data acquisition system. I started with the single buffer acquisition system http://redpitaya.com/examples-new/singl ... r-acquire/ (using the C-api). I was wondering how long it takes to restart the acquisition system after it has been triggered? (Reasoning: I would like to trigger on events that are 5 ms apart and not have the chance of missing an event).

Code: Select all

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

#include <math.h>

#include <time.h>
//for clock_gettime

#include "redpitaya/rp.h"

struct timespec program_start;

#define BILLION 1000000000ULL

struct timespec timer_start()
{
	//CLOCK_REALTIME
	//CLOCK_MONOTONIC
	//CLOCK_PROCESS_CPUTIME_ID
	//CLOCK_THREAD_CPUTIME_ID
	//CLOCK_MONOTONIC_RAW (not subject to NTP adjustments)
	struct timespec start_time;
	clock_gettime(CLOCK_MONOTONIC_RAW, &start_time);
	return start_time;
}

unsigned long long int timer_end_ns(struct timespec start_time)
{
	struct timespec end_time;
	clock_gettime(CLOCK_MONOTONIC_RAW, &end_time);
	unsigned long long int diff_in_sec = end_time.tv_sec - start_time.tv_sec;
	unsigned long long int diff_ns     = end_time.tv_nsec - start_time.tv_nsec;
	return diff_in_sec * BILLION + diff_ns;
}

int main(int argc, char * argv[])
{
	program_start = timer_start();
	if ( rp_Init() != RP_OK )
	{
		fprintf(stderr, "%s\n", "Red Pitaya API initialization failed\n");
		return EXIT_FAILURE;
	}

	rp_AcqReset();
	rp_AcqSetDecimation(1);
	const float trigger_threshold = 0.05;
	rp_AcqSetTriggerLevel(trigger_threshold);
	//Trig level is set in Volts
	rp_AcqSetTriggerDelay(0);
	rp_AcqStart();
	usleep(135);//sleep for 135 uS (so buffer can be populated)

	rp_AcqSetTriggerSrc(RP_TRIG_SRC_CHA_PE);
	rp_acq_trig_state_t state = RP_TRIG_STATE_WAITING;

	unsigned int trigger_count = 0;

	printf("New Acquisition\n");
	start = timer_start();
	struct timespec last;
	while(trigger_count < 100)//currently an arbitrary limit (this will change)
	{
		if (trigger_count == 0)
		{
			last = timer_start();
		}

		rp_AcqGetTriggerState(&state);
		if (state == RP_TRIG_STATE_TRIGGERED)
		{
			rp_AcqSetTriggerSrc(RP_TRIG_SRC_DISABLED);//as a precaution
			rp_AcqGetOldestDataV(RP_CH_1, &buffer_size, buff);
			if (trigger_count == 0)
			{
				//** output ** 
				//** CLIPPED ** 
			}
			int i;
			for ( i = 0; i < buffer_size; ++i)
			{
				//** do something with the buffer **
				//** CLIPPED ** 
			}
			printf("TSLP[%u]: %llu\n", trigger_count, timer_end_ns(last)/1000 );
			last = timer_start();
			++trigger_count;
			usleep(1);
			state = RP_TRIG_STATE_WAITING;
			rp_AcqSetTriggerSrc(RP_TRIG_SRC_CHA_PE);
			rp_AcqStart();
			usleep(135);
		}
	}
	// Output details from all trigger events;
	// .. CLIPPED ..
	free(buff);
	rp_Release();
	return EXIT_SUCCESS;
}
Cheers,

Greg
edit: Added signature :D

Nils Roos
Posts: 1441
Joined: Sat Jun 07, 2014 12:49 pm
Location: Königswinter

Re: Trigger Arming Time

Post by Nils Roos » Thu Jun 09, 2016 8:10 pm

Hi Greg,

how soon you can start the next acquisition after a trigger event is depending on the number of pre-trigger samples you want to record. If you don't need the samples from before a trigger event, you can reactivate the trigger immediately after you fetched the recorded samples.

Here's a bit of less good news for you though:
rp_AcqGetOldestDataV() takes ~8ms to read 16384 samples. The bulk of that time is spent getting the data from the FPGA, so there is no way (in the RP api) to speed up the process significantly, short of reading fewer samples.

gregoryk
Posts: 5
Joined: Tue Apr 05, 2016 6:40 pm

Re: Trigger Arming Time

Post by gregoryk » Fri Jun 10, 2016 7:51 pm

Thanks.

I'll update the code and do some testing. If I get something that meets my specifications I'll post it.

Are there details about the scaling of the speed of the data transfer can occur for smaller samples (for example 8192, 4096)?

Cheers,

Greg

Nils Roos
Posts: 1441
Joined: Sat Jun 07, 2014 12:49 pm
Location: Königswinter

Re: Trigger Arming Time

Post by Nils Roos » Fri Jun 10, 2016 7:57 pm

It is pretty much a linear relation, half the number of samples, half the time.

Nils Roos
Posts: 1441
Joined: Sat Jun 07, 2014 12:49 pm
Location: Königswinter

Re: Trigger Arming Time

Post by Nils Roos » Fri Jun 10, 2016 8:22 pm

Seems I was wrong about the transfer being the most significant factor in the duration of the rp_Get...Data... functions:

Some more measurements showed that reading the raw samples takes only half the time. They are only compensated for DC offset, as opposed to the additional gain calibration that is applied during the voltage functions.

gregoryk
Posts: 5
Joined: Tue Apr 05, 2016 6:40 pm

Re: Trigger Arming Time

Post by gregoryk » Wed Jun 29, 2016 2:33 am

Thanks. I've updated my code to transfer a smaller buffer and enabled triggering to occur immediately after the buffer transfer has occurred.
(1) I want to make sure I get the rising edge of the triggered samples, so for the smaller buffer transfer (lets say 4096 measurements) - I would need to set the offset such that the trigger point occurs in the transfer window. So the correct way to do this is have the trigger delay be (if I'm still using GetOldest):

Code: Select all

rp_AcqSetTriggerDelay(8192 - buffer_size/2);//guess I could just do buffer_size>>1 instead of the divide;
//or:
rp_AcqSetTriggerDelay(6144);
This means that I acquire 8192 + 6144 samples after the trigger. Finally this means that the following call:

Code: Select all

rp_AcqGetOldestDataV(RP_CH_1, &buffer_size, buff);
will grab the 'oldest' samples in the buffer which should include the raising edge of the waveform. ASCII art diagram:

Code: Select all

|--------/-------------------------------|
|--------^--------|----------------------|
           (a)                         (b)
Right now I want to acquire a buffer for (a);

The alternate I guess would be the following:

Code: Select all

uint32_t pos = 8192;
rp_AcqGetWritePointerAtTrig(&pos);
rp_AcqGetDataPosV(RP_CH_1, pos - 2048, pos+2048, buff, buffer_size);
//or rp_AcqGetDataPosRaw
(2) If I want to measure the time between the rising edge and the falling edge, I guess I would do the following:

Code: Select all

struct timespec rising_edge;
int fount_re =0;
rp_acq_trig_state_t state = RP_TRIG_STATE_WAITING;
rp_AcqSetTriggerSrc(RP_TRIG_SRC_CHA_PE);
rp_AcqStart();
usleep(135);//sleep for 135 uS (so buffer can be populated)
while(true)
{
      rp_AcqGetTriggerState(&state);
      if (state == RP_TRIG_STATE_TRIGGERED && found_re == 0)
      {
           state = RP_TRIG_STATE_WAITING;
           rising_edge = timer_start();
           found_re = 1;
           rp_AcqSetTriggerSrc(RP_TRIG_SRC_CHA_NE);
           rp_AcqStart();
           usleep(135);
      }
     if (state == RP_TRIG_STATE_TRIGGERED && found_re != 0)
    {
         printf("Time estimate between rising and falling edges = %llu\n", timer_end_ns(rising_edge)/1000);
         break;
    }
}

Nils Roos
Posts: 1441
Joined: Sat Jun 07, 2014 12:49 pm
Location: Königswinter

Re: Trigger Arming Time

Post by Nils Roos » Wed Jun 29, 2016 3:05 pm

(1) In order to get 4096 samples centered around the trigger, you could also do

Code: Select all

rp_AcqSetTriggerDelay(-6144);
...
uint32_t size = 4096;
rp_AcqGetLatestDataV(RP_CH_1, &size, buffer);
(2) You don't need the usleep() if all you want to do is measure the pulsewidth. It is only useful to make sure a sufficient amount of pre-trigger samples has been recorded before activating the trigger. With your sequence of rp_AcqStart() after rp_AcqSetTriggerSrc(), it is completely useless.

gregoryk
Posts: 5
Joined: Tue Apr 05, 2016 6:40 pm

Re: Trigger Arming Time

Post by gregoryk » Thu Jun 30, 2016 7:14 pm

Thanks for all the help. I'll post an updated piece of code in the next few days (after running some tests).

I think the code that I suggested will have an issue, in the case that returned write pointer is at a lower buffer position, i.e. if pos < 2048 (because then it will be an 'underflow').

Code: Select all

uint32_t pos = 8192;
rp_AcqGetWritePointerAtTrig(&pos);
rp_AcqGetDataPosV(RP_CH_1, pos - 2048, pos + 2048, buff, buffer_size);

gregoryk
Posts: 5
Joined: Tue Apr 05, 2016 6:40 pm

Re: Trigger Arming Time

Post by gregoryk » Wed Sep 14, 2016 6:21 am

Here is an rough updated version (in case people are interested). I've found that there sometimes are cases where the trigger fails to either be re-armed or be activated (and the code will stall waiting for the Red Pitaya - for example if I set: number_of_pulses to be larger than 30 it might happen 1 in 5 times). Any ideas on how to deal with this issue?

Code: Select all

	//..snip..
	//timer_start returns: struct timespec
	//timer_end returns the difference in time (scale is ns)
	uint32_t buffer_size = 2048;
	DEBUG_FULLt_DETAILS("CREATING buffers");
	float * time = (float *)malloc(buffer_size * sizeof(float));
	float * buff = (float *)malloc(buffer_size * sizeof(float));//was used for debugging

	unsigned int j;
	for (j=0 ; j<buffer_size ; j++)
	{
		buff[j]=0.0;
		time[j]=0.008 * j;
	}
	rp_AcqReset();
	rp_AcqSetDecimation(1);
	const float trigger_threshold = 0.150;
	rp_AcqSetTriggerLevel(trigger_threshold);
	rp_AcqSetTriggerDelay(-7168);//getting the 2048 oldest values (want the trigger point to be roughly in the middle
	start = timer_start();//start of 'just prior to acq'
So after setting it up, starting the acquire (and only interested in the first 'n' pulses - in this case 10);

Code: Select all

	rp_AcqStart();

	usleep(132);
	rp_AcqSetTriggerSrc(RP_TRIG_SRC_CHA_PE);
	rp_acq_trig_state_t state = RP_TRIG_STATE_WAITING;

	unsigned int trigger_count = 0;
	const unsigned int number_of_pulses = 10;
	while(trigger_count < number_of_pulses)
	{
		if (trigger_count == 0)
		{
			last = timer_start();
		}

		rp_AcqGetTriggerState(&state);
		if (state == RP_TRIG_STATE_TRIGGERED)
		{
			rp_AcqSetTriggerSrc(RP_TRIG_SRC_DISABLED);//as a precaution
			state = RP_TRIG_STATE_WAITING;

			struct timespec before = timer_start();
			rp_AcqGetOldestDataV(RP_CH_1, &buffer_size, buff);
			long time_elapsed = timer_end(before)/1000;
			printf("%ld (us)\n", time_elapsed);

			rp_AcqSetTriggerSrc(RP_TRIG_SRC_CHA_PE);
			unsigned int samples_overthreshold = 0;

			calc_time = timer_start();
			float integral_a = 0.;
			unsigned int i;
			for ( i = 0; i < buffer_size; ++i)
			{
				integral_a += buff[i];
				if (buff[i] > trigger_threshold)
				{
					//printf("%d\n",i);
					++samples_overthreshold;
				}

				if (i <= 1 )
				{
					printf("%f\n", buff[i]);//checking the values @ i=0 or i=1
				}
			}
			total_integral += integral_a;
			printf("pulse integral =  %f\n", integral_a);
			printf("Calculation takes:  %ld (us) \n", timer_end(calc_time)/1000 );
			printf("overthreshold = %u\n", samples_overthreshold );
			printf("total_integral      = %f\n", total_integral);
			printf("TSLP[%u]: %llu\n", trigger_count, timer_end_ns(last)/1000 );//TIME SINCE LAST PULSE
			last = timer_start();
			++trigger_count;
			usleep(150);//wait about 150us (due to measurement signal not decaying monotonically - don't want to trigger again)
			// THIS is DUE to ---^----- my experimental setup
			rp_AcqStart();
			usleep(132);//probably not needed
	}

Post Reply
jadalnie klasyczne ekskluzywne meble wypoczynkowe do salonu ekskluzywne meble tapicerowane ekskluzywne meble do sypialni ekskluzywne meble włoskie

Who is online

Users browsing this forum: No registered users and 124 guests