diff options
author | Mike Lockwood <lockwood@google.com> | 2013-08-28 09:44:17 -0700 |
---|---|---|
committer | Mike Lockwood <lockwood@google.com> | 2013-08-28 09:44:17 -0700 |
commit | 9f6a119c8aa276432ece4fe2118bd8a3c9b1067e (patch) | |
tree | 1391656f9ad624aa99d4c7d2880d38121801a424 /tools/orientationplot | |
parent | 647b6f5ed276bf93d95e5801e5e8af2802ef5fbb (diff) | |
download | frameworks_base-9f6a119c8aa276432ece4fe2118bd8a3c9b1067e.zip frameworks_base-9f6a119c8aa276432ece4fe2118bd8a3c9b1067e.tar.gz frameworks_base-9f6a119c8aa276432ece4fe2118bd8a3c9b1067e.tar.bz2 |
Move frameworks/base/tools/ to frameworks/tools/
Change-Id: I3ffafdab27cc4aca256c3a5806b630795b75d5c8
Diffstat (limited to 'tools/orientationplot')
-rw-r--r-- | tools/orientationplot/README.txt | 87 | ||||
-rwxr-xr-x | tools/orientationplot/orientationplot.py | 457 |
2 files changed, 0 insertions, 544 deletions
diff --git a/tools/orientationplot/README.txt b/tools/orientationplot/README.txt deleted file mode 100644 index d53f65e..0000000 --- a/tools/orientationplot/README.txt +++ /dev/null @@ -1,87 +0,0 @@ -This directory contains a simple python script for visualizing -the behavior of the WindowOrientationListener. - - -PREREQUISITES -------------- - -1. Python 2.6 -2. numpy -3. matplotlib - - -USAGE ------ - -The tool works by scaping the debug log output from WindowOrientationListener -for interesting data and then plotting it. - -1. Plug in the device. Ensure that it is the only device plugged in - since this script is of very little brain and will get confused otherwise. - -2. Enable the Window Orientation Listener debugging data log. - adb shell setprop debug.orientation.log true - adb shell stop - adb shell start - -3. Run "orientationplot.py". - - -WHAT IT ALL MEANS ------------------ - -The tool displays several time series graphs that plot the output of the -WindowOrientationListener. Here you can see the raw accelerometer data, -filtered accelerometer data, measured tilt and orientation angle, confidence -intervals for the proposed orientation and accelerometer latency. - -Things to look for: - -1. Ensure the filtering is not too aggressive. If the filter cut-off frequency is - less than about 1Hz, then the filtered accelorometer data becomes too smooth - and the latency for orientation detection goes up. One way to observe this - is by holding the device vertically in one orientation then sharply turning - it 90 degrees to a different orientation. Compared the rapid changes in the - raw accelerometer data with the smoothed out filtered data. If the filtering - is too aggressive, the filter response may lag by hundreds of milliseconds. - -2. Ensure that there is an appropriate gap between adjacent orientation angles - for hysteresis. Try holding the device in one orientation and slowly turning - it 90 degrees. Note that the confidence intervals will all drop to 0 at some - point in between the two orientations; that is the gap. The gap should be - observed between all adjacent pairs of orientations when turning the device - in either direction. - - Next try holding the device in one orientation and rapidly turning it end - over end to a midpoint about 45 degrees between two opposing orientations. - There should be no gap observed initially. The algorithm should pick one - of the orientations and settle into it (since it is obviously quite - different from the original orientation of the device). However, once it - settles, the confidence values should start trending to 0 again because - the measured orientation angle is now within the gap between the new - orientation and the adjacent orientation. - - In other words, the hysteresis gap applies only when the measured orientation - angle (say, 45 degrees) is between the current orientation's ideal angle - (say, 0 degrees) and an adjacent orientation's ideal angle (say, 90 degrees). - -3. Accelerometer jitter. The accelerometer latency graph displays the interval - between sensor events as reported by the SensorEvent.timestamp field. It - should be a fairly constant 60ms. If the latency jumps around wildly or - greatly exceeds 60ms then there is a problem with the accelerometer or the - sensor manager. - -4. The orientation angle is not measured when the tilt is too close to 90 or -90 - degrees (refer to MAX_TILT constant). Consequently, you should expect there - to be no data. Likewise, all dependent calculations are suppressed in this case - so there will be no orientation proposal either. - -5. Each orientation has its own bound on allowable tilt angles. It's a good idea to - verify that these limits are being enforced by gradually varying the tilt of - the device until it is inside/outside the limit for each orientation. - -6. Orientation changes should be significantly harder when the device is held - overhead. People reading on tablets in bed often have their head turned - a little to the side, or they hold the device loosely so its orientation - can be a bit unusual. The tilt is a good indicator of whether the device is - overhead. diff --git a/tools/orientationplot/orientationplot.py b/tools/orientationplot/orientationplot.py deleted file mode 100755 index 6fc3922..0000000 --- a/tools/orientationplot/orientationplot.py +++ /dev/null @@ -1,457 +0,0 @@ -#!/usr/bin/env python2.6 -# -# Copyright (C) 2011 The Android Open Source Project -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -# -# Plots debug log output from WindowOrientationListener. -# See README.txt for details. -# - -import numpy as np -import matplotlib.pyplot as plot -import subprocess -import re -import fcntl -import os -import errno -import bisect -from datetime import datetime, timedelta - -# Parameters. -timespan = 15 # seconds total span shown -scrolljump = 5 # seconds jump when scrolling -timeticks = 1 # seconds between each time tick - -# Non-blocking stream wrapper. -class NonBlockingStream: - def __init__(self, stream): - fcntl.fcntl(stream, fcntl.F_SETFL, os.O_NONBLOCK) - self.stream = stream - self.buffer = '' - self.pos = 0 - - def readline(self): - while True: - index = self.buffer.find('\n', self.pos) - if index != -1: - result = self.buffer[self.pos:index] - self.pos = index + 1 - return result - - self.buffer = self.buffer[self.pos:] - self.pos = 0 - try: - chunk = os.read(self.stream.fileno(), 4096) - except OSError, e: - if e.errno == errno.EAGAIN: - return None - raise e - if len(chunk) == 0: - if len(self.buffer) == 0: - raise(EOFError) - else: - result = self.buffer - self.buffer = '' - self.pos = 0 - return result - self.buffer += chunk - -# Plotter -class Plotter: - def __init__(self, adbout): - self.adbout = adbout - - self.fig = plot.figure(1) - self.fig.suptitle('Window Orientation Listener', fontsize=12) - self.fig.set_dpi(96) - self.fig.set_size_inches(16, 12, forward=True) - - self.raw_acceleration_x = self._make_timeseries() - self.raw_acceleration_y = self._make_timeseries() - self.raw_acceleration_z = self._make_timeseries() - self.raw_acceleration_magnitude = self._make_timeseries() - self.raw_acceleration_axes = self._add_timeseries_axes( - 1, 'Raw Acceleration', 'm/s^2', [-20, 20], - yticks=range(-15, 16, 5)) - self.raw_acceleration_line_x = self._add_timeseries_line( - self.raw_acceleration_axes, 'x', 'red') - self.raw_acceleration_line_y = self._add_timeseries_line( - self.raw_acceleration_axes, 'y', 'green') - self.raw_acceleration_line_z = self._add_timeseries_line( - self.raw_acceleration_axes, 'z', 'blue') - self.raw_acceleration_line_magnitude = self._add_timeseries_line( - self.raw_acceleration_axes, 'magnitude', 'orange', linewidth=2) - self._add_timeseries_legend(self.raw_acceleration_axes) - - shared_axis = self.raw_acceleration_axes - - self.filtered_acceleration_x = self._make_timeseries() - self.filtered_acceleration_y = self._make_timeseries() - self.filtered_acceleration_z = self._make_timeseries() - self.filtered_acceleration_magnitude = self._make_timeseries() - self.filtered_acceleration_axes = self._add_timeseries_axes( - 2, 'Filtered Acceleration', 'm/s^2', [-20, 20], - sharex=shared_axis, - yticks=range(-15, 16, 5)) - self.filtered_acceleration_line_x = self._add_timeseries_line( - self.filtered_acceleration_axes, 'x', 'red') - self.filtered_acceleration_line_y = self._add_timeseries_line( - self.filtered_acceleration_axes, 'y', 'green') - self.filtered_acceleration_line_z = self._add_timeseries_line( - self.filtered_acceleration_axes, 'z', 'blue') - self.filtered_acceleration_line_magnitude = self._add_timeseries_line( - self.filtered_acceleration_axes, 'magnitude', 'orange', linewidth=2) - self._add_timeseries_legend(self.filtered_acceleration_axes) - - self.tilt_angle = self._make_timeseries() - self.tilt_angle_axes = self._add_timeseries_axes( - 3, 'Tilt Angle', 'degrees', [-105, 105], - sharex=shared_axis, - yticks=range(-90, 91, 30)) - self.tilt_angle_line = self._add_timeseries_line( - self.tilt_angle_axes, 'tilt', 'black') - self._add_timeseries_legend(self.tilt_angle_axes) - - self.orientation_angle = self._make_timeseries() - self.orientation_angle_axes = self._add_timeseries_axes( - 4, 'Orientation Angle', 'degrees', [-25, 375], - sharex=shared_axis, - yticks=range(0, 361, 45)) - self.orientation_angle_line = self._add_timeseries_line( - self.orientation_angle_axes, 'orientation', 'black') - self._add_timeseries_legend(self.orientation_angle_axes) - - self.current_rotation = self._make_timeseries() - self.proposed_rotation = self._make_timeseries() - self.predicted_rotation = self._make_timeseries() - self.orientation_axes = self._add_timeseries_axes( - 5, 'Current / Proposed Orientation', 'rotation', [-1, 4], - sharex=shared_axis, - yticks=range(0, 4)) - self.current_rotation_line = self._add_timeseries_line( - self.orientation_axes, 'current', 'black', linewidth=2) - self.predicted_rotation_line = self._add_timeseries_line( - self.orientation_axes, 'predicted', 'purple', linewidth=3) - self.proposed_rotation_line = self._add_timeseries_line( - self.orientation_axes, 'proposed', 'green', linewidth=3) - self._add_timeseries_legend(self.orientation_axes) - - self.time_until_settled = self._make_timeseries() - self.time_until_flat_delay_expired = self._make_timeseries() - self.time_until_swing_delay_expired = self._make_timeseries() - self.time_until_acceleration_delay_expired = self._make_timeseries() - self.stability_axes = self._add_timeseries_axes( - 6, 'Proposal Stability', 'ms', [-10, 600], - sharex=shared_axis, - yticks=range(0, 600, 100)) - self.time_until_settled_line = self._add_timeseries_line( - self.stability_axes, 'time until settled', 'black', linewidth=2) - self.time_until_flat_delay_expired_line = self._add_timeseries_line( - self.stability_axes, 'time until flat delay expired', 'green') - self.time_until_swing_delay_expired_line = self._add_timeseries_line( - self.stability_axes, 'time until swing delay expired', 'blue') - self.time_until_acceleration_delay_expired_line = self._add_timeseries_line( - self.stability_axes, 'time until acceleration delay expired', 'red') - self._add_timeseries_legend(self.stability_axes) - - self.sample_latency = self._make_timeseries() - self.sample_latency_axes = self._add_timeseries_axes( - 7, 'Accelerometer Sampling Latency', 'ms', [-10, 500], - sharex=shared_axis, - yticks=range(0, 500, 100)) - self.sample_latency_line = self._add_timeseries_line( - self.sample_latency_axes, 'latency', 'black') - self._add_timeseries_legend(self.sample_latency_axes) - - self.fig.canvas.mpl_connect('button_press_event', self._on_click) - self.paused = False - - self.timer = self.fig.canvas.new_timer(interval=100) - self.timer.add_callback(lambda: self.update()) - self.timer.start() - - self.timebase = None - self._reset_parse_state() - - # Handle a click event to pause or restart the timer. - def _on_click(self, ev): - if not self.paused: - self.paused = True - self.timer.stop() - else: - self.paused = False - self.timer.start() - - # Initialize a time series. - def _make_timeseries(self): - return [[], []] - - # Add a subplot to the figure for a time series. - def _add_timeseries_axes(self, index, title, ylabel, ylim, yticks, sharex=None): - num_graphs = 7 - height = 0.9 / num_graphs - top = 0.95 - height * index - axes = self.fig.add_axes([0.1, top, 0.8, height], - xscale='linear', - xlim=[0, timespan], - ylabel=ylabel, - yscale='linear', - ylim=ylim, - sharex=sharex) - axes.text(0.02, 0.02, title, transform=axes.transAxes, fontsize=10, fontweight='bold') - axes.set_xlabel('time (s)', fontsize=10, fontweight='bold') - axes.set_ylabel(ylabel, fontsize=10, fontweight='bold') - axes.set_xticks(range(0, timespan + 1, timeticks)) - axes.set_yticks(yticks) - axes.grid(True) - - for label in axes.get_xticklabels(): - label.set_fontsize(9) - for label in axes.get_yticklabels(): - label.set_fontsize(9) - - return axes - - # Add a line to the axes for a time series. - def _add_timeseries_line(self, axes, label, color, linewidth=1): - return axes.plot([], label=label, color=color, linewidth=linewidth)[0] - - # Add a legend to a time series. - def _add_timeseries_legend(self, axes): - axes.legend( - loc='upper left', - bbox_to_anchor=(1.01, 1), - borderpad=0.1, - borderaxespad=0.1, - prop={'size': 10}) - - # Resets the parse state. - def _reset_parse_state(self): - self.parse_raw_acceleration_x = None - self.parse_raw_acceleration_y = None - self.parse_raw_acceleration_z = None - self.parse_raw_acceleration_magnitude = None - self.parse_filtered_acceleration_x = None - self.parse_filtered_acceleration_y = None - self.parse_filtered_acceleration_z = None - self.parse_filtered_acceleration_magnitude = None - self.parse_tilt_angle = None - self.parse_orientation_angle = None - self.parse_current_rotation = None - self.parse_proposed_rotation = None - self.parse_predicted_rotation = None - self.parse_time_until_settled = None - self.parse_time_until_flat_delay_expired = None - self.parse_time_until_swing_delay_expired = None - self.parse_time_until_acceleration_delay_expired = None - self.parse_sample_latency = None - - # Update samples. - def update(self): - timeindex = 0 - while True: - try: - line = self.adbout.readline() - except EOFError: - plot.close() - return - if line is None: - break - print line - - try: - timestamp = self._parse_timestamp(line) - except ValueError, e: - continue - if self.timebase is None: - self.timebase = timestamp - delta = timestamp - self.timebase - timeindex = delta.seconds + delta.microseconds * 0.000001 - - if line.find('Raw acceleration vector:') != -1: - self.parse_raw_acceleration_x = self._get_following_number(line, 'x=') - self.parse_raw_acceleration_y = self._get_following_number(line, 'y=') - self.parse_raw_acceleration_z = self._get_following_number(line, 'z=') - self.parse_raw_acceleration_magnitude = self._get_following_number(line, 'magnitude=') - - if line.find('Filtered acceleration vector:') != -1: - self.parse_filtered_acceleration_x = self._get_following_number(line, 'x=') - self.parse_filtered_acceleration_y = self._get_following_number(line, 'y=') - self.parse_filtered_acceleration_z = self._get_following_number(line, 'z=') - self.parse_filtered_acceleration_magnitude = self._get_following_number(line, 'magnitude=') - - if line.find('tiltAngle=') != -1: - self.parse_tilt_angle = self._get_following_number(line, 'tiltAngle=') - - if line.find('orientationAngle=') != -1: - self.parse_orientation_angle = self._get_following_number(line, 'orientationAngle=') - - if line.find('Result:') != -1: - self.parse_current_rotation = self._get_following_number(line, 'currentRotation=') - self.parse_proposed_rotation = self._get_following_number(line, 'proposedRotation=') - self.parse_predicted_rotation = self._get_following_number(line, 'predictedRotation=') - self.parse_sample_latency = self._get_following_number(line, 'timeDeltaMS=') - self.parse_time_until_settled = self._get_following_number(line, 'timeUntilSettledMS=') - self.parse_time_until_flat_delay_expired = self._get_following_number(line, 'timeUntilFlatDelayExpiredMS=') - self.parse_time_until_swing_delay_expired = self._get_following_number(line, 'timeUntilSwingDelayExpiredMS=') - self.parse_time_until_acceleration_delay_expired = self._get_following_number(line, 'timeUntilAccelerationDelayExpiredMS=') - - self._append(self.raw_acceleration_x, timeindex, self.parse_raw_acceleration_x) - self._append(self.raw_acceleration_y, timeindex, self.parse_raw_acceleration_y) - self._append(self.raw_acceleration_z, timeindex, self.parse_raw_acceleration_z) - self._append(self.raw_acceleration_magnitude, timeindex, self.parse_raw_acceleration_magnitude) - self._append(self.filtered_acceleration_x, timeindex, self.parse_filtered_acceleration_x) - self._append(self.filtered_acceleration_y, timeindex, self.parse_filtered_acceleration_y) - self._append(self.filtered_acceleration_z, timeindex, self.parse_filtered_acceleration_z) - self._append(self.filtered_acceleration_magnitude, timeindex, self.parse_filtered_acceleration_magnitude) - self._append(self.tilt_angle, timeindex, self.parse_tilt_angle) - self._append(self.orientation_angle, timeindex, self.parse_orientation_angle) - self._append(self.current_rotation, timeindex, self.parse_current_rotation) - if self.parse_proposed_rotation >= 0: - self._append(self.proposed_rotation, timeindex, self.parse_proposed_rotation) - else: - self._append(self.proposed_rotation, timeindex, None) - if self.parse_predicted_rotation >= 0: - self._append(self.predicted_rotation, timeindex, self.parse_predicted_rotation) - else: - self._append(self.predicted_rotation, timeindex, None) - self._append(self.time_until_settled, timeindex, self.parse_time_until_settled) - self._append(self.time_until_flat_delay_expired, timeindex, self.parse_time_until_flat_delay_expired) - self._append(self.time_until_swing_delay_expired, timeindex, self.parse_time_until_swing_delay_expired) - self._append(self.time_until_acceleration_delay_expired, timeindex, self.parse_time_until_acceleration_delay_expired) - self._append(self.sample_latency, timeindex, self.parse_sample_latency) - self._reset_parse_state() - - # Scroll the plots. - if timeindex > timespan: - bottom = int(timeindex) - timespan + scrolljump - self.timebase += timedelta(seconds=bottom) - self._scroll(self.raw_acceleration_x, bottom) - self._scroll(self.raw_acceleration_y, bottom) - self._scroll(self.raw_acceleration_z, bottom) - self._scroll(self.raw_acceleration_magnitude, bottom) - self._scroll(self.filtered_acceleration_x, bottom) - self._scroll(self.filtered_acceleration_y, bottom) - self._scroll(self.filtered_acceleration_z, bottom) - self._scroll(self.filtered_acceleration_magnitude, bottom) - self._scroll(self.tilt_angle, bottom) - self._scroll(self.orientation_angle, bottom) - self._scroll(self.current_rotation, bottom) - self._scroll(self.proposed_rotation, bottom) - self._scroll(self.predicted_rotation, bottom) - self._scroll(self.time_until_settled, bottom) - self._scroll(self.time_until_flat_delay_expired, bottom) - self._scroll(self.time_until_swing_delay_expired, bottom) - self._scroll(self.time_until_acceleration_delay_expired, bottom) - self._scroll(self.sample_latency, bottom) - - # Redraw the plots. - self.raw_acceleration_line_x.set_data(self.raw_acceleration_x) - self.raw_acceleration_line_y.set_data(self.raw_acceleration_y) - self.raw_acceleration_line_z.set_data(self.raw_acceleration_z) - self.raw_acceleration_line_magnitude.set_data(self.raw_acceleration_magnitude) - self.filtered_acceleration_line_x.set_data(self.filtered_acceleration_x) - self.filtered_acceleration_line_y.set_data(self.filtered_acceleration_y) - self.filtered_acceleration_line_z.set_data(self.filtered_acceleration_z) - self.filtered_acceleration_line_magnitude.set_data(self.filtered_acceleration_magnitude) - self.tilt_angle_line.set_data(self.tilt_angle) - self.orientation_angle_line.set_data(self.orientation_angle) - self.current_rotation_line.set_data(self.current_rotation) - self.proposed_rotation_line.set_data(self.proposed_rotation) - self.predicted_rotation_line.set_data(self.predicted_rotation) - self.time_until_settled_line.set_data(self.time_until_settled) - self.time_until_flat_delay_expired_line.set_data(self.time_until_flat_delay_expired) - self.time_until_swing_delay_expired_line.set_data(self.time_until_swing_delay_expired) - self.time_until_acceleration_delay_expired_line.set_data(self.time_until_acceleration_delay_expired) - self.sample_latency_line.set_data(self.sample_latency) - - self.fig.canvas.draw_idle() - - # Scroll a time series. - def _scroll(self, timeseries, bottom): - bottom_index = bisect.bisect_left(timeseries[0], bottom) - del timeseries[0][:bottom_index] - del timeseries[1][:bottom_index] - for i, timeindex in enumerate(timeseries[0]): - timeseries[0][i] = timeindex - bottom - - # Extract a word following the specified prefix. - def _get_following_word(self, line, prefix): - prefix_index = line.find(prefix) - if prefix_index == -1: - return None - start_index = prefix_index + len(prefix) - delim_index = line.find(',', start_index) - if delim_index == -1: - return line[start_index:] - else: - return line[start_index:delim_index] - - # Extract a number following the specified prefix. - def _get_following_number(self, line, prefix): - word = self._get_following_word(line, prefix) - if word is None: - return None - return float(word) - - # Extract an array of numbers following the specified prefix. - def _get_following_array_of_numbers(self, line, prefix): - prefix_index = line.find(prefix + '[') - if prefix_index == -1: - return None - start_index = prefix_index + len(prefix) + 1 - delim_index = line.find(']', start_index) - if delim_index == -1: - return None - - result = [] - while start_index < delim_index: - comma_index = line.find(', ', start_index, delim_index) - if comma_index == -1: - result.append(float(line[start_index:delim_index])) - break; - result.append(float(line[start_index:comma_index])) - start_index = comma_index + 2 - return result - - # Add a value to a time series. - def _append(self, timeseries, timeindex, number): - timeseries[0].append(timeindex) - timeseries[1].append(number) - - # Parse the logcat timestamp. - # Timestamp has the form '01-21 20:42:42.930' - def _parse_timestamp(self, line): - return datetime.strptime(line[0:18], '%m-%d %H:%M:%S.%f') - -# Notice -print "Window Orientation Listener plotting tool" -print "-----------------------------------------\n" -print "Please turn on the Window Orientation Listener logging in Development Settings." - -# Start adb. -print "Starting adb logcat.\n" - -adb = subprocess.Popen(['adb', 'logcat', '-s', '-v', 'time', 'WindowOrientationListener:V'], - stdout=subprocess.PIPE) -adbout = NonBlockingStream(adb.stdout) - -# Prepare plotter. -plotter = Plotter(adbout) -plotter.update() - -# Main loop. -plot.show() |