Precise Cycle Times for Reading the Position and Counts

Below you find a script that uses a timer and a counter to make precise measurements of the cycle times (reading position and counts). Figure 14.1 and 14.2 show the results for local and remote access. 'Remote' means that the python script runs on a PC with a different TangoDB.

#!/usr/bin/env python
import sys, time, math
import PyTango
import matplotlib
matplotlib.use( 'TkAgg')
import matplotlib.pyplot as plt
import numpy as np

#
# this script assumes that 
#   - the counter channel is fed with a 1 MHz clock
#   - the counter is gated by the timer
# 
# this script executes 10000 cycles 
#   - read the counter
#   - calculate the difference with the old counter reading
#     the counter reading gives us a precise time base
#   - read the position
#   
# results
#   - total time
#   - average cycle time
#   - maximum cycle time
#   - standard deviation
#
# conclusion:
#   - the cycle time is consistent with the other examples
#     which execute single reads of the position and the counts
#   - the maximum cycle time is a bit larger for the remote access 
#     and also the standard deviation
#
try:
    proxyMotor = PyTango.DeviceProxy( "haso107d1:10000/p09/motor/d1.65")
    proxyCounter = PyTango.DeviceProxy( "haso107d1:10000/p09/counter/d1.32")
    proxyTimer = PyTango.DeviceProxy( "haso107d1:10000/p09/dgg2/d1.01")
except PyTango.DevFailed as e:
    PyTango.Except.print_exception(e)
    sys.exit()

proxyCounter.Reset()
proxyTimer.Stop()
proxyTimer.SampleTime = 1000
proxyTimer.Start()

nMax = 2000.
x = np.arange( 0.0, nMax, 1)
y = np.zeros( nMax)
n = 10000.
countsOld = 0.
diffMax = 0.
sum = 0.
sumq = 0.
time_start = time.time()
for i in range(int(n)):
    counts = float(proxyCounter.Counts)
    diff = counts - countsOld
    if diff < nMax:
        y[int(diff)] += 1
    else:
        y[int(nMax - 1)] += 1

    sum += diff
    sumq += diff*diff
    if diff > diffMax: 
        diffMax = diff
    countsOld = counts
    pos = proxyMotor.Position
time_diff = time.time() - time_start
s = math.sqrt( (sumq - sum*sum/n)/(n-1))

print( " %d cycles (Position, Counts) take %g sec" % ( int(n), time_diff))
print( " Cycle time:")
print( "  average %g msec "  % (sum/n/1000.))
print( "  max     %g msec" % (diffMax/1000.))
print( "  std-dev %g msec" % ( s/1000.))

#
# from local host:
# 10000 cycles (Position, Counts) take 4.71505 sec
# Cycle time:
#  average 0.471522 msec 
#  max     2.433 msec
#  std-dev 0.0736271 msec
#
# from remote host: 
# 10000 cycles (Position, Counts) take 8.7081 sec
# Cycle time:
#  average 0.870914 msec 
#  max     96.073 msec
#  std-dev 0.956201 msec

plt.plot( x, y, 'r')
plt.ylabel( 'Frequency')
plt.xlabel( 'Cycle time in micro-secs, local access')
plt.show()

Figure 14.1: Tango I/O Cycle Time, Local Access
\includegraphics[width=14.8cm]{speedLocal.ps}

Figure 14.2: Tango I/O Cycle Time, Remote Access
\includegraphics[width=14.8cm]{speedRemote.ps}