├── .gitattributes ├── .gitignore └── README.md /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | 4 | # Custom for Visual Studio 5 | *.cs diff=csharp 6 | *.sln merge=union 7 | *.csproj merge=union 8 | *.vbproj merge=union 9 | *.fsproj merge=union 10 | *.dbproj merge=union 11 | 12 | # Standard to msysgit 13 | *.doc diff=astextplain 14 | *.DOC diff=astextplain 15 | *.docx diff=astextplain 16 | *.DOCX diff=astextplain 17 | *.dot diff=astextplain 18 | *.DOT diff=astextplain 19 | *.pdf diff=astextplain 20 | *.PDF diff=astextplain 21 | *.rtf diff=astextplain 22 | *.RTF diff=astextplain 23 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ################# 2 | ## Eclipse 3 | ################# 4 | 5 | *.pydevproject 6 | .project 7 | .metadata 8 | bin/ 9 | tmp/ 10 | *.tmp 11 | *.bak 12 | *.swp 13 | *~.nib 14 | local.properties 15 | .classpath 16 | .settings/ 17 | .loadpath 18 | 19 | # External tool builders 20 | .externalToolBuilders/ 21 | 22 | # Locally stored "Eclipse launch configurations" 23 | *.launch 24 | 25 | # CDT-specific 26 | .cproject 27 | 28 | # PDT-specific 29 | .buildpath 30 | 31 | 32 | ################# 33 | ## Visual Studio 34 | ################# 35 | 36 | ## Ignore Visual Studio temporary files, build results, and 37 | ## files generated by popular Visual Studio add-ons. 38 | 39 | # User-specific files 40 | *.suo 41 | *.user 42 | *.sln.docstates 43 | 44 | # Build results 45 | [Dd]ebug/ 46 | [Rr]elease/ 47 | *_i.c 48 | *_p.c 49 | *.ilk 50 | *.meta 51 | *.obj 52 | *.pch 53 | *.pdb 54 | *.pgc 55 | *.pgd 56 | *.rsp 57 | *.sbr 58 | *.tlb 59 | *.tli 60 | *.tlh 61 | *.tmp 62 | *.vspscc 63 | .builds 64 | *.dotCover 65 | 66 | ## TODO: If you have NuGet Package Restore enabled, uncomment this 67 | #packages/ 68 | 69 | # Visual C++ cache files 70 | ipch/ 71 | *.aps 72 | *.ncb 73 | *.opensdf 74 | *.sdf 75 | 76 | # Visual Studio profiler 77 | *.psess 78 | *.vsp 79 | 80 | # ReSharper is a .NET coding add-in 81 | _ReSharper* 82 | 83 | # Installshield output folder 84 | [Ee]xpress 85 | 86 | # DocProject is a documentation generator add-in 87 | DocProject/buildhelp/ 88 | DocProject/Help/*.HxT 89 | DocProject/Help/*.HxC 90 | DocProject/Help/*.hhc 91 | DocProject/Help/*.hhk 92 | DocProject/Help/*.hhp 93 | DocProject/Help/Html2 94 | DocProject/Help/html 95 | 96 | # Click-Once directory 97 | publish 98 | 99 | # Others 100 | [Bb]in 101 | [Oo]bj 102 | sql 103 | TestResults 104 | *.Cache 105 | ClientBin 106 | stylecop.* 107 | ~$* 108 | *.dbmdl 109 | Generated_Code #added for RIA/Silverlight projects 110 | 111 | # Backup & report files from converting an old project file to a newer 112 | # Visual Studio version. Backup files are not needed, because we have git ;-) 113 | _UpgradeReport_Files/ 114 | Backup*/ 115 | UpgradeLog*.XML 116 | 117 | 118 | 119 | ############ 120 | ## Windows 121 | ############ 122 | 123 | # Windows image file caches 124 | Thumbs.db 125 | 126 | # Folder config file 127 | Desktop.ini 128 | 129 | 130 | ############# 131 | ## Python 132 | ############# 133 | 134 | *.py[co] 135 | 136 | # Packages 137 | *.egg 138 | *.egg-info 139 | dist 140 | build 141 | eggs 142 | parts 143 | bin 144 | var 145 | sdist 146 | develop-eggs 147 | .installed.cfg 148 | 149 | # Installer logs 150 | pip-log.txt 151 | 152 | # Unit test / coverage reports 153 | .coverage 154 | .tox 155 | 156 | #Translations 157 | *.mo 158 | 159 | #Mr Developer 160 | .mr.developer.cfg 161 | 162 | # Mac crap 163 | .DS_Store 164 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Applying Low Pass Filter to Android Sensor's Readings # 2 | 3 | ---------- 4 | 5 | 6 | ## Overview of Android Sensors ## 7 | The Android sensor framework lets you access many types of sensors. Two very basic types are: 8 | 9 | 1. Hardware Sensors. 10 | 2. Software Sensors. 11 | 12 | **Hardware sensors** are physical components built into a handset or tablet device. They derive their data by directly measuring specific environmental properties, such as acceleration, geomagnetic field strength, or angular change.
13 | ex. `Sensor.TYPE_ACCELEROMETER, Sensor.TYPE_MAGNETIC_FIELD` 14 | 15 | **Software sensors** are not physical devices, although they mimic hardware-based sensors. Software-based sensors derive their data from one or more of the hardware-based sensors and are sometimes called virtual sensors or synthetic sensors. 16 | ex.`Sensor.TYPE_ORIENTATION, Sensor.TYPE_ROTATION_VECTOR` 17 | 18 | ## Best Practices for Accessing and Using Sensors ## 19 | 1. Unregister sensor listeners. 20 | 2. Don't test your code on the emulator. 21 | 3. Don't block the onSensorChanged() method. 22 | 4. Avoid using deprecated methods or sensor types. 23 | 5. Verify sensors before you use them. 24 | 6. Choose sensor delays carefully. 25 | 7. **Filter the values received in `onSensorChanged()`. Allow only those that are needed.** 26 | 27 | After we register the Sensors, the sensor reading get notified in `SensorEventListener`'s `onSensorChanged()` method. However, the rate of change in sensor values is such high that if we map these small changes a.k.a 'Noise' the values jump within a large range of values.
28 | 29 |
We can also specify the `SensorManager`'s delay properties from one of these:
30 | 1. `SENSOR_DELAY_FASTEST`
31 | 2. `SENSOR_DELAY_GAME`
32 | 3. `SENSOR_DELAY_UI`
33 | 4. `SENSOR_DELAY_NORMAL`
34 | 35 |
This is however only a hint to the system. Events may be received faster or slower than the specified rate. Usually events are received faster. 36 |

Moral of the story is... 37 | > Allow only those values which are useful and discard the unnecessary noise. 38 | 39 | The solution for this is to apply a **[Low-Pass Filter](http://en.wikipedia.org/wiki/Low-pass_filter)** on these values. 40 | 41 | ## A Small Glimpse of Low Pass Filter ## 42 | A [low-pass filter](http://en.wikipedia.org/wiki/Low-pass_filter) is a filter that passes low-frequency signals/values and attenuates (reduces the amplitude of) signals/values with frequencies higher than the cutoff frequency.
43 | Let us take an example of simple signal with values ranging from 0 to 1. The values can be anything between 0 to 1. 44 | Due to some external source, environmental factors such as jerks, vibrations., a considerable amount of noise is added to these signals. These high frequency signals (noise) cause the readings to hop between considerable high and low values. 45 |
46 |
47 | **Enough of Physics...**
48 | Lets understand this in programming concept rather. :) 49 | ## Programmatically Apply Low Pass Filter ## 50 | Device's sensor readings add noise data due to high sensitivity of its hardware to various factors as mentioned above. For gaming purpose these highly sensitive values are much a boon. But for application where there has to be smoothness in the readings, these hopping values are a mess.
51 | Lets take an example of [Augmented Reality View](https://github.com/Bhide/AugmentedRealityView.git), where we have to point markers on `Camera` `SurfaceView`.
52 | The high sensitivity causes the markers the change positions very randomly due to the noise.
53 | A Low-Pass Filter concept comes to rescue. We can omit those high frequencies in the input signal applying some suitable threshold and apply the filter output reading to plot the markers.
54 | With this implementation the markers won't hop randomly because we have removed the unwanted high reading values. 55 | 56 | Here is the algorithm implementation:
57 | `for i from 1 to n`
58 | `y[i] := y[i-1] + α * (x[i] - y[i-1])`
59 |
60 | Here, α is the cut-off/threshold.
61 |
62 | Lets see how to implement it in Android.
63 | `lowPass(float[] input, float[] output)`
64 | The above method filters the input values and applies LPF and outputs the filtered signals

65 | `static final float ALPHA = 0.25f; // if ALPHA = 1 OR 0, no filter applies.` 66 | 67 | protected float[] lowPass( float[] input, float[] output ) { 68 | if ( output == null ) return input; 69 | 70 | for ( int i=0; iLow-Pass Filter is finally applied to sensor values in `onSensorChanged(SensorEvent event)` as follows:

77 | 78 | @Override 79 | public void onSensorChanged(SensorEvent evt) { 80 | 81 | 82 | if (evt.sensor.getType() == Sensor.TYPE_ACCELEROMETER) { 83 | gravSensorVals = lowPass(evt.values.clone(), gravSensorVals); 84 | 85 | } else if (evt.sensor.getType() == Sensor.TYPE_MAGNETIC_FIELD) { 86 | magSensorVals = lowPass(evt.values.clone(), magSensorVals); 87 | } 88 | 89 | if (gravSensorVals != null && magSensorVals != null) { 90 | SensorManager.getRotationMatrix(RTmp, I, gravSensorVals, magSensorVals); 91 | 92 | int rotation = Compatibility.getRotation(this); 93 | 94 | if (rotation == 1) { 95 | SensorManager.remapCoordinateSystem(RTmp, SensorManager.AXIS_X, SensorManager.AXIS_MINUS_Z, Rot); 96 | } else { 97 | SensorManager.remapCoordinateSystem(RTmp, SensorManager.AXIS_Y, SensorManager.AXIS_MINUS_Z, Rot); 98 | } 99 | 100 | SensorManager.getOrientation(Rot, results); 101 | 102 | UIARView.azimuth = (float)(((results[0]*180)/Math.PI)+180); 103 | UIARView.pitch = (float)(((results[1]*180/Math.PI))+90); 104 | UIARView.roll = (float)(((results[2]*180/Math.PI))); 105 | 106 | radarMarkerView.postInvalidate(); 107 | } 108 | } 109 | 110 |
An example of this can be found [here](https://github.com/Bhide/AugmentedRealityView.git). 111 |
Here i have applied low pass filter for `Sensor.TYPE_ACCELEROMETER` and `Sensor.TYPE_MAGNETIC_FIELD`. 112 | --------------------------------------------------------------------------------