However when requesting a datarate of 50 and collecting 50 samples the effective datarate is 42.4.
And confusingly when requesting a datarate of 25 and collecting 50 samples the effective datarate is 25.5.
Examples of two runs, first at a datarate of 125 and second at 50. I only included the first and last three entries in each runs log output.
Updated version of encoder_1047.py with additional metrics included at end.
NOTE: I did try upgrading the firmware for the encoder from 200 to 301 -- no change in the results.
datarate=125
Code: Select all
% python3 encoder_1047.py --datarate=125 --samples=125 --channel=0
Press Enter to Start Test
Channel: 0 of 1047 4-channel high-speed encoder: 'PhidgetEncoder', 125 samples at 125 samples/s
sample PositionChange Position Encoder Interval System Interval
1 0 0 3.78 18.0
2 0 0 7.63 7.9
3 0 0 7.63 8.1
...
123 0 0 8.90 8.0
124 0 0 7.63 8.0
125 0 0 7.63 8.0
Channel: 0 of 1047 4-channel high-speed encoder: 'PhidgetEncoder', 125 samples at 125 samples/s
duration (system): 1.013
duration (encoder): 0.995
requested data rate: 125
effective data rate: 125.6
Code: Select all
% python3 encoder_1047.py --datarate=50 --samples=50 --channel=0
Press Enter to Start Test
Channel: 0 of 1047 4-channel high-speed encoder: 'PhidgetEncoder', 50 samples at 50 samples/s
sample PositionChange Position Encoder Interval System Interval
1 0 0 3.78 19.0
2 0 0 24.13 23.8
3 0 0 24.15 24.2
...
48 0 0 24.16 24.0
49 0 0 24.14 24.0
50 0 0 24.14 24.0
Channel: 0 of 1047 4-channel high-speed encoder: 'PhidgetEncoder', 50 samples at 50 samples/s
duration (system): 1.198
duration (encoder): 1.180
requested data rate: 50
effective data rate: 42.4
Code: Select all
from Phidget22.PhidgetException import *
from Phidget22.Phidget import *
from Phidget22.Devices.Encoder import *
import argparse
import time
import json
# connect phidget 1047 high-speed 4-channel encoder to usb on computer
# When True this program uses ENC1000_0 encoder connected to VINT
# Useful for development/testing without encoder_1047 available
use_encoder_ENC1000 = False
encoder_channel = 0
datarate = 125
max_samples = 2 * datarate
encoder_pulley_hubport = 0
#
# Parse optional command line arguments
#
parser = argparse.ArgumentParser(
description='test communication with Phidget 1047 4-channel high-speed encoder')
parser.add_argument('--enc1000', default=False, action=argparse.BooleanOptionalAction,
help=f"use ENC1000_0 encoder connected to VINT hub, default: {False}")
parser.add_argument('--channel', type=int, default=encoder_channel,
help=f"encoder channel (0-3), default: {encoder_channel}")
parser.add_argument('--datarate', type=int, default=datarate,
help=f"encoder data rate (1-125), default: {datarate}")
parser.add_argument('--samples', type=int, default=max_samples,
help=f"encoder samples to collect, default: {max_samples}")
args = parser.parse_args()
encoder_channel = args.channel
datarate = args.datarate
max_samples = args.samples
use_encoder_ENC1000 = args.enc1000
if use_encoder_ENC1000:
datarate = min(50, datarate)
else:
datarate = min(125, datarate)
encoder_counts_per_revolution = 2000
encoderPosition = 0
#
# Load saved vint and encoder_1047 serial numbers
#
# example json: phidget-serial-numbers.json
#
# {
# "vint": 538832,
# "encoder_1047": 538833
# }
#
try:
filename = "phidget-serial-numbers.json"
sample_filename = "phidget-serial-numbers-sample.json"
serial_numbers = json.load(open(filename))
vint_serial_number = serial_numbers['vint']
encoder_1047_serial_number = serial_numbers['encoder_1047']
except FileNotFoundError:
print(f"""
***
*** Required file: '{filename}' not found
*** Copy file: '{sample_filename}' to '{filename}'
***
*** cp {sample_filename} {filename}'
***
*** and update the serial numbers for the vint hub and 1047 encoder
***
""")
raise
except json.decoder.JSONDecodeError:
print(f"""
*** JSON decoding error in file: '{filename}'
""")
raise
sample_count = 0
start_time_sys = 0
end_time_sys = 0
previous_time_sys = 0
duration = 0
duration_sys = 0
log = ""
about = ""
# log formatting
col_width = 18
header_str = f"\n{'sample':<{col_width}}{'PositionChange':<{col_width}}{'Position':<{col_width}}{'Encoder Interval':<{col_width}}{'System Interval':<{col_width}}\n"
def onPositionChange(self, positionChange, timeChange, indexTriggered):
global previous_time_sys, duration
global log, sample_count, encoderPosition
sample_count += 1
if sample_count <= max_samples:
timeChange += 0.00001
interval = timeChange / 1000
duration += interval
encoderPositionChangePerSecond = 1 / interval * positionChange
rps = encoderPositionChangePerSecond / encoder_counts_per_revolution
encoderPosition += positionChange
rotation = encoderPosition / encoder_counts_per_revolution
encoderPosition = self.getPosition()
current_time_sys = time.time()
interval_sys = (current_time_sys - previous_time_sys)
interval_ms_sys = interval_sys * 1000
previous_time_sys = current_time_sys
log += f"{sample_count:<{col_width}}{positionChange:<{col_width}.0f}{encoderPosition:<{col_width}}{timeChange:<{col_width}.2f}{interval_ms_sys:<{col_width}.1f}\n"
def main():
global log, about, start_time_sys, end_time_sys, previous_time_sys, duration, duration_sys
log = header_str
about = ""
try:
input("\nPress Enter to Start Test\n")
except (Exception, KeyboardInterrupt):
pass
en0 = Encoder()
if use_encoder_ENC1000:
en0.setDeviceSerialNumber(vint_serial_number)
en0.openWaitForAttachment(5000)
encoder_classname = en0.getDeviceClassName()
en0.setHubPort(encoder_pulley_hubport)
en0.setDataRate(datarate)
about += f"Using VINT ENC1000_0 encoder: '{encoder_classname}'"
else:
en0.setDeviceSerialNumber(encoder_1047_serial_number)
en0.setChannel(encoder_channel)
en0.openWaitForAttachment(5000)
encoder_classname = en0.getDeviceClassName()
en0.setDataRate(datarate)
about += f"Channel: {encoder_channel} of 1047 4-channel high-speed encoder: '{encoder_classname}'"
about += f", {max_samples} samples at {datarate} samples/s"
print(about)
en0.setOnPositionChangeHandler(onPositionChange)
start_time_sys = time.time()
previous_time_sys = start_time_sys
duration = 0
while sample_count < max_samples:
pass
en0.close()
end_time_sys = time.time()
duration_sys = end_time_sys - start_time_sys
main()
print(f"{log}")
print(about)
effective_datarate = 1 / (duration / max_samples)
print(f"""
duration (system): {duration_sys:.3f}
duration (encoder): {duration:.3f}
requested data rate: {datarate}
effective data rate: {effective_datarate:.1f}
""")