I need to be able to set short delays (2 and 10 microseconds) and measure sub millisecond elapse times.
(I need these facilities to read an ultrasonic distance sensor attached to a Raspberry Pi.)
I have some libraries with suitable code for use with ⎕NA, but I am unable to used them as they require 64 bit integers.
Anybody got any ideas how I can set short delays and measure times of around 0.1 milliseconds(equating to about 5 inches).
Thanks
Ray
Setting and measuring very short times
Forum rules
This forum is for general chit-chat, not necessarily APL-related. However, it's not for spam or for offensive or illegal comments.
This forum is for general chit-chat, not necessarily APL-related. However, it's not for spam or for offensive or illegal comments.
Setting and measuring very short times
Ray Cannon
Please excuse any smelling pisstakes.
Please excuse any smelling pisstakes.
Re: Setting and measuring very short times
ti is a timer operator and mn just formats quantities in iso.
{⍵}/ is a trivial sequential (mustn't be parallel) operation that dyalog doesn't recognise as an "idiom" so it trawls through the entire argument returning its rightmost element at every turn.
Notice that it's time is more or less linear down to around 10 microseconds.
If you calibrate it on your machine and set it running for a suitable length argument it might do for your delays.
ti above repeats the timed function many times over a second and returns the mean. No good for your purposes.
How about this?
Here we're setting a timer in another thread and killing it after a set period. {#.what+←1} seems to take a bit over 4 microseconds in my machine with this version of Dyalog
If you set the timer going at the send and kill it on receipt of your signal #.what should indicate the time after suitable calibration.
z←⍳1e7 ⋄ ⊢z←'s'mn{⍵}/ti z
2.01s
z←⍳1e6 ⋄ ⊢z←'s'mn{⍵}/ti z
203.75ms
z←⍳1e5 ⋄ ⊢z←'s'mn{⍵}/ti z
20.78125ms
z←⍳1e4 ⋄ ⊢z←'s'mn{⍵}/ti z
2.109375ms
z←⍳1e3 ⋄ ⊢z←'s'mn{⍵}/ti z
203.857421875µs
z←⍳1e2 ⋄ ⊢z←'s'mn{⍵}/ti z
17.7001953125µs
z←⍳1e1 ⋄ ⊢z←'s'mn{⍵}/ti z
4.5013427734375µs
{⍵}/ is a trivial sequential (mustn't be parallel) operation that dyalog doesn't recognise as an "idiom" so it trawls through the entire argument returning its rightmost element at every turn.
Notice that it's time is more or less linear down to around 10 microseconds.
If you calibrate it on your machine and set it running for a suitable length argument it might do for your delays.
ti above repeats the timed function many times over a second and returns the mean. No good for your purposes.
How about this?
#.what←0 ⋄ z←{#.what+←1}/&⍳1e7 ⋄ ⎕dl 1 ⋄ ⎕tkill z ⋄ 's'mn 1÷#.what
4.1114025638706µs
#.what←0 ⋄ z←{#.what+←1}/&⍳1e7 ⋄ ⎕dl 2 ⋄ ⎕tkill z ⋄ 's'mn 2÷#.what
4.238033382989µs
#.what←0 ⋄ z←{#.what+←1}/&⍳1e7 ⋄ ⎕dl 4 ⋄ ⎕tkill z ⋄ 's'mn 4÷#.what
4.3078659478274µs
#.what←0 ⋄ z←{#.what+←1}/&⍳1e7 ⋄ ⎕dl 8 ⋄ ⎕tkill z ⋄ 's'mn 8÷#.what
4.3079424997375µs
#.what←0 ⋄ z←{#.what+←1}/&⍳1e7 ⋄ ⎕dl 16 ⋄ ⎕tkill z ⋄ 's'mn 16÷#.what
4.2610954264331µs
Here we're setting a timer in another thread and killing it after a set period. {#.what+←1} seems to take a bit over 4 microseconds in my machine with this version of Dyalog
If you set the timer going at the send and kill it on receipt of your signal #.what should indicate the time after suitable calibration.
-
- Posts: 43
- Joined: Wed May 13, 2009 12:36 pm
Re: Setting and measuring very short times
⎕NA can use 64 bit ints on a 32 bit interpreter. I8 or U8 work.
On both 32 and 64 bit versions you have to be careful if you want full 64 bit precision. APL will transfer the data as decimal floating point. Decimal floating point has a precision of 34 decimal digits which is more than the 20 of an unsigned 64 bit integer. If the value of ⎕FR you are using is 645 then any arithmetic will revert to double. This only has a precision of 53 bits.
⎕DL takes non integer values. The value passed to the operating system is in microseconds. ⎕AI reports elapsed time in millisecs which is a bit coarser than you require. You could ⎕NA to the gettimeofday() function which is what ⎕AI and ⎕DL are using. That gets values in microseconds.
Whilst you can talk to the operating system in terms of microseconds the underlying system tick time may not be that fine.
On both 32 and 64 bit versions you have to be careful if you want full 64 bit precision. APL will transfer the data as decimal floating point. Decimal floating point has a precision of 34 decimal digits which is more than the 20 of an unsigned 64 bit integer. If the value of ⎕FR you are using is 645 then any arithmetic will revert to double. This only has a precision of 53 bits.
⎕DL takes non integer values. The value passed to the operating system is in microseconds. ⎕AI reports elapsed time in millisecs which is a bit coarser than you require. You could ⎕NA to the gettimeofday() function which is what ⎕AI and ⎕DL are using. That gets values in microseconds.
Whilst you can talk to the operating system in terms of microseconds the underlying system tick time may not be that fine.
Re: Setting and measuring very short times
When the result of the function being called by ⎕NA, using U8 fails on the Raspberry Pi
⎕NA ('U8 ',GPIO_PATH,'|bcm2835_st_read')
DOMAIN ERROR: Bad parameter specification: ⎕NA error at U8 /home/pi/bcm2835-1.35......|bcm2835_st_read - result specification too wide for this version of APL
⎕NA ('U8 ',GPIO_PATH,'|bcm2835_st_read')
DOMAIN ERROR: Bad parameter specification: ⎕NA error at U8 /home/pi/bcm2835-1.35......|bcm2835_st_read - result specification too wide for this version of APL
Ray Cannon
Please excuse any smelling pisstakes.
Please excuse any smelling pisstakes.
Re: Setting and measuring very short times
I have now got gettimeofday working, returning a time in seconds and microseconds with the ⎕NA call
⎕NA'libc.so.6|gettimeofday ={U U} =P'
secs micro←⊃ gettimeofday (0 0) 0
This seems to do the trick.
Thanks
Ray
⎕NA'libc.so.6|gettimeofday ={U U} =P'
secs micro←⊃ gettimeofday (0 0) 0
This seems to do the trick.
Thanks
Ray
Ray Cannon
Please excuse any smelling pisstakes.
Please excuse any smelling pisstakes.
-
- Posts: 101
- Joined: Mon Sep 19, 2011 6:43 pm
Re: Setting and measuring very short times
Old topic, but as i didn't see it b4...
Could be a bit better written, but it's among the very first pieces i had to deal with, to follow frame time delta. The computers "frequency" is not the Ghz's your CPU has, but some fixed share of it, in my box eg.
QueryPerformanceFrequency 0
3233232 0
#.del
10000 15.94467672 (ignore this first row)
100000 0.006695158281
1000000 0.0518137888
100000 0.007399407157
1000000 0.05041611613
10000 0.00399816654
1000000 0.04696136869
100000 0.006892174765
100000 0.006980012569
1000 0.002700084621
Works well in all Win CPU's. But i do measure milliseconds only, frame times, so i have not much idea about the accuracy. Serves a 3D app well, movement is smooth enuff (i use an accumulated avg of 10 last frame times).
Would be cool if APL exposed the QueryPerformance API, since the interpreter uses it anyway?
I-beam, whatever. One single function. Would return seconds since most recent call to the same.
Could be a bit better written, but it's among the very first pieces i had to deal with, to follow frame time delta. The computers "frequency" is not the Ghz's your CPU has, but some fixed share of it, in my box eg.
QueryPerformanceFrequency 0
3233232 0
Code: Select all
:With #.SYS
⎕NA'Kernel32|QueryPerformanceCounter >{U4 U4}'
⎕NA'Kernel32|QueryPerformanceFrequency >{U4 U4}'
Freq←QueryPerformanceFrequency 0 ⍝ 2 element vector
Freq←Freq[1]+Freq[2]×4294967296 ⍝ Pre-modified for the equation below
Freq1 Freq2←1 4294967296÷Freq
#.SYS.T0←qp←QueryPerformanceCounter 0 ⍝ Nullify clock - T0 is now qounter origin, throughout the session
#.SYS.T←#.SYS.Tp←(Freq1×qp[1]-T0[1])+Freq2×qp[2]-T0[2] ⍝ First T
Time←{
qp←QueryPerformanceCounter 0
#.SYS.T←(Freq1×qp[1]-T0[1])+Freq2×qp[2]-T0[2] ⍝ T is counter, with system origin T0
#.SYS.(T∆←T-Tp) ⍝ T∆ is frame time (using accumulator Tp)
#.SYS.(Tp←T)
#.SYS.(T_←SyncDelta+T) ⍝ T_ is "elapsed time now"
}
:End
Code: Select all
del;a;s
:For s :In ⍳10
a←10*?6
{}{⍵÷⍵×2}a?a
#.SYS.Time 0
a,#.SYS.T∆
:End
#.del
10000 15.94467672 (ignore this first row)
100000 0.006695158281
1000000 0.0518137888
100000 0.007399407157
1000000 0.05041611613
10000 0.00399816654
1000000 0.04696136869
100000 0.006892174765
100000 0.006980012569
1000 0.002700084621
Works well in all Win CPU's. But i do measure milliseconds only, frame times, so i have not much idea about the accuracy. Serves a 3D app well, movement is smooth enuff (i use an accumulated avg of 10 last frame times).
Would be cool if APL exposed the QueryPerformance API, since the interpreter uses it anyway?
I-beam, whatever. One single function. Would return seconds since most recent call to the same.