summaryrefslogtreecommitdiffstats
path: root/tools/orientationplot
diff options
context:
space:
mode:
authorMike Lockwood <lockwood@google.com>2013-08-28 09:44:17 -0700
committerMike Lockwood <lockwood@google.com>2013-08-28 09:44:17 -0700
commit9f6a119c8aa276432ece4fe2118bd8a3c9b1067e (patch)
tree1391656f9ad624aa99d4c7d2880d38121801a424 /tools/orientationplot
parent647b6f5ed276bf93d95e5801e5e8af2802ef5fbb (diff)
downloadframeworks_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.txt87
-rwxr-xr-xtools/orientationplot/orientationplot.py457
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()