1 /* 2 * Copyright (C) 2014 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package android.hardware.cts.helpers.sensorverification; 18 19 import junit.framework.Assert; 20 21 import android.content.Context; 22 import android.content.pm.PackageManager; 23 import android.hardware.Sensor; 24 import android.hardware.cts.helpers.SensorStats; 25 import android.hardware.cts.helpers.TestSensorEnvironment; 26 import android.hardware.cts.helpers.TestSensorEvent; 27 import android.hardware.cts.helpers.SensorCtsHelper; 28 import android.util.Log; 29 30 import java.util.concurrent.TimeUnit; 31 import java.util.HashMap; 32 import java.util.Map; 33 34 /** 35 * A {@link ISensorVerification} which verifies that the standard deviations is within the expected 36 * range. 37 */ 38 public class StandardDeviationVerification extends AbstractSensorVerification { 39 public static final String PASSED_KEY = "standard_deviation_passed"; 40 41 // sensorType: threshold 42 private static final Map<Integer, float[]> DEFAULTS = new HashMap<Integer, float[]>(12); 43 static { 44 // Use a method so that the @deprecation warning can be set for that method only setDefaults()45 setDefaults(); 46 } 47 48 private final float[] mThreshold; 49 50 private float[] mMeans = null; 51 private float[] mM2s = null; 52 private int mCount = 0; 53 54 /** 55 * Construct a {@link StandardDeviationVerification} 56 * 57 * @param threshold the thresholds 58 */ StandardDeviationVerification(float[] threshold)59 public StandardDeviationVerification(float[] threshold) { 60 mThreshold = threshold; 61 } 62 63 /** 64 * Get the default {@link StandardDeviationVerification} for a sensor. 65 * 66 * @param environment the test environment 67 * @return the verification or null if the verification does not apply to the sensor. 68 */ getDefault(TestSensorEnvironment environment)69 public static StandardDeviationVerification getDefault(TestSensorEnvironment environment) { 70 int sensorType = environment.getSensor().getType(); 71 float graceFactorAccelGyro = 2.0f; 72 float graceFactorMagPressure = 4.0f; 73 float currOperatingFreq = (float) environment.getFrequencyHz(); 74 float maxBandWidth = (float)SensorCtsHelper.getFrequency( 75 environment.getSensor().getMinDelay(), TimeUnit.MICROSECONDS); 76 float minBandWidth = (float) SensorCtsHelper.getFrequency( 77 environment.getSensor().getMaxDelay(), TimeUnit.MICROSECONDS); 78 79 if (Float.isInfinite(currOperatingFreq)) { 80 currOperatingFreq = maxBandWidth; 81 } 82 83 if (currOperatingFreq > maxBandWidth && !Float.isInfinite(maxBandWidth)) { 84 currOperatingFreq = maxBandWidth; 85 } 86 87 if (currOperatingFreq < minBandWidth && !Float.isInfinite(minBandWidth)) { 88 currOperatingFreq = minBandWidth; 89 } 90 91 float mAccelNoise = (float)(graceFactorAccelGyro * Math.sqrt(currOperatingFreq) * 92 (9.81 * 0.0004)); 93 float mGyroNoise = (float)(graceFactorAccelGyro * Math.sqrt(currOperatingFreq) * 94 (Math.PI/180.0 * 0.014)); 95 float mMagNoise = (float)((graceFactorMagPressure) * 0.5); // Allow extra grace for mag 96 float mPressureNoise = (float)(graceFactorMagPressure * 0.02 * 97 (float)Math.sqrt(currOperatingFreq)); // Allow extra grace for pressure 98 99 if (!DEFAULTS.containsKey(sensorType)) { 100 return null; 101 } 102 boolean hasHifiSensors = environment.getContext().getPackageManager().hasSystemFeature( 103 PackageManager.FEATURE_HIFI_SENSORS); 104 105 if (hasHifiSensors) { 106 107 DEFAULTS.put(Sensor.TYPE_ACCELEROMETER, new float[]{mAccelNoise, mAccelNoise, mAccelNoise}); 108 // Max gyro deviation: 0.014°/s/√Hz 109 DEFAULTS.put(Sensor.TYPE_GYROSCOPE, 110 new float[]{mGyroNoise, mGyroNoise, mGyroNoise}); 111 // Max magnetometer deviation: 0.1uT/√Hz 112 DEFAULTS.put(Sensor.TYPE_MAGNETIC_FIELD, new float[]{mMagNoise, mMagNoise, mMagNoise}); 113 // Max pressure deviation: 2Pa/√Hz 114 DEFAULTS.put(Sensor.TYPE_PRESSURE, new float[]{mPressureNoise}); 115 } 116 return new StandardDeviationVerification(DEFAULTS.get(sensorType)); 117 } 118 119 /** 120 * Verify that the standard deviation is in the acceptable range. Add {@value #PASSED_KEY} and 121 * {@value SensorStats#STANDARD_DEVIATION_KEY} keys to {@link SensorStats}. 122 * 123 * @throws AssertionError if the verification failed. 124 */ 125 @Override verify(TestSensorEnvironment environment, SensorStats stats)126 public void verify(TestSensorEnvironment environment, SensorStats stats) { 127 verify(stats); 128 } 129 130 /** 131 * Visible for unit tests only. 132 */ verify(SensorStats stats)133 void verify(SensorStats stats) { 134 if (mCount < 2) { 135 stats.addValue(PASSED_KEY, true); 136 return; 137 } 138 139 float[] stdDevs = new float[mM2s.length]; 140 for (int i = 0; i < mM2s.length; i++) { 141 stdDevs[i] = (float) Math.sqrt(mM2s[i] / (mCount - 1)); 142 } 143 144 boolean failed = false; 145 StringBuilder stddevSb = new StringBuilder(); 146 StringBuilder expectedSb = new StringBuilder(); 147 148 if (stdDevs.length > 1) { 149 stddevSb.append("("); 150 expectedSb.append("("); 151 } 152 for (int i = 0; i < stdDevs.length; i++) { 153 if (stdDevs[i] > mThreshold[i]) { 154 failed = true; 155 } 156 stddevSb.append(String.format("%.6f", stdDevs[i])); 157 if (i != stdDevs.length - 1) stddevSb.append(", "); 158 expectedSb.append(String.format("<%.6f", mThreshold[i])); 159 if (i != stdDevs.length - 1) expectedSb.append(", "); 160 } 161 if (stdDevs.length > 1) { 162 stddevSb.append(")"); 163 expectedSb.append(")"); 164 } 165 166 stats.addValue(PASSED_KEY, !failed); 167 stats.addValue(SensorStats.STANDARD_DEVIATION_KEY, stdDevs); 168 169 if (failed) { 170 Assert.fail(String.format("Standard deviation out of range: stddev=%s (expected %s)", 171 stddevSb.toString(), expectedSb.toString())); 172 } 173 } 174 175 /** 176 * {@inheritDoc} 177 */ 178 @Override clone()179 public StandardDeviationVerification clone() { 180 return new StandardDeviationVerification(mThreshold); 181 } 182 183 /** 184 * {@inheritDoc} 185 * <p> 186 * Computes the standard deviation using 187 * <a href="http://en.wikipedia.org/wiki/Algorithms_for_calculating_variance#On-line_algorithm"> 188 * Welford's algorith</a>. 189 * </p> 190 */ 191 @Override addSensorEventInternal(TestSensorEvent event)192 protected void addSensorEventInternal(TestSensorEvent event) { 193 if (mMeans == null || mM2s == null) { 194 mMeans = new float[event.values.length]; 195 mM2s = new float[event.values.length]; 196 } 197 198 Assert.assertEquals(mMeans.length, event.values.length); 199 Assert.assertEquals(mM2s.length, event.values.length); 200 201 mCount++; 202 203 for (int i = 0; i < event.values.length; i++) { 204 float delta = event.values[i] - mMeans[i]; 205 mMeans[i] += delta / mCount; 206 mM2s[i] += delta * (event.values[i] - mMeans[i]); 207 } 208 } 209 210 @SuppressWarnings("deprecation") setDefaults()211 private static void setDefaults() { 212 DEFAULTS.put(Sensor.TYPE_ACCELEROMETER, new float[]{1.0f, 1.0f, 1.0f}); 213 DEFAULTS.put(Sensor.TYPE_GYROSCOPE, new float[]{0.5f, 0.5f, 0.5f}); 214 // Sensors that we don't want to test at this time but still want to record the values. 215 DEFAULTS.put(Sensor.TYPE_MAGNETIC_FIELD, 216 new float[]{Float.MAX_VALUE, Float.MAX_VALUE, Float.MAX_VALUE}); 217 DEFAULTS.put(Sensor.TYPE_ORIENTATION, 218 new float[]{Float.MAX_VALUE, Float.MAX_VALUE, Float.MAX_VALUE}); 219 DEFAULTS.put(Sensor.TYPE_PRESSURE, 220 new float[]{Float.MAX_VALUE, Float.MAX_VALUE, Float.MAX_VALUE}); 221 DEFAULTS.put(Sensor.TYPE_GRAVITY, 222 new float[]{Float.MAX_VALUE, Float.MAX_VALUE, Float.MAX_VALUE}); 223 DEFAULTS.put(Sensor.TYPE_LINEAR_ACCELERATION, 224 new float[]{Float.MAX_VALUE, Float.MAX_VALUE, Float.MAX_VALUE}); 225 DEFAULTS.put(Sensor.TYPE_ROTATION_VECTOR, 226 new float[]{Float.MAX_VALUE, Float.MAX_VALUE, Float.MAX_VALUE, Float.MAX_VALUE, 227 Float.MAX_VALUE}); 228 DEFAULTS.put(Sensor.TYPE_MAGNETIC_FIELD_UNCALIBRATED, 229 new float[]{Float.MAX_VALUE, Float.MAX_VALUE, Float.MAX_VALUE, Float.MAX_VALUE, 230 Float.MAX_VALUE, Float.MAX_VALUE}); 231 DEFAULTS.put(Sensor.TYPE_GAME_ROTATION_VECTOR, 232 new float[]{Float.MAX_VALUE, Float.MAX_VALUE, Float.MAX_VALUE, Float.MAX_VALUE, 233 Float.MAX_VALUE}); 234 DEFAULTS.put(Sensor.TYPE_GYROSCOPE_UNCALIBRATED, 235 new float[]{Float.MAX_VALUE, Float.MAX_VALUE, Float.MAX_VALUE, Float.MAX_VALUE, 236 Float.MAX_VALUE, Float.MAX_VALUE}); 237 DEFAULTS.put(Sensor.TYPE_GEOMAGNETIC_ROTATION_VECTOR, 238 new float[]{Float.MAX_VALUE, Float.MAX_VALUE, Float.MAX_VALUE, Float.MAX_VALUE, 239 Float.MAX_VALUE}); 240 } 241 } 242