├── .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 |
--------------------------------------------------------------------------------