CMMotionManager lets us access data from various motion sensors like accelerometer or gyroscope on iOS device.

However, in many situations, the data we get from CMMotionManager is not smooth. Basically it contains noise. This article presents a way to smooth the accelerometer readings using a Low Pass Filter.

An accelerometer reading in iOS is modelled by CMAcceleration which is nothing more than a simple struct:

1
2
3
4
5
typedef struct {
      double x;
      double y;
      double z;
} CMAcceleration;

x, y and z are values of acceleration in G‘s (gravitational force unit) along x, y and z axis.

What we need here is a kind of a Low-pass filter that will allow us to ignore small movements. Low-pass filter provides a smoother form of a signal, removing the short-term fluctuations, and leaving the longer-term trend. Effectively, it will smooth out the data we get from CMMotionManager by taking out the jittery. This can be done by shifting the value of each accelerometer reading into closer harmony with the values of its neighbors.

If you ever had contact with signal processing or electronic circuit theories, you probably remember what a low pass filter was made of. Resistance and capacitance connected as depicted on the right.

The code snippet below does exactly what we need. The named the variable in a way that should seem familiar for those that tinkered with creating electronic circuits. You can also get it from my gist repo.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
- (CMAcceleration)smoothOutAcceleration:(CMAcceleration)acceleration {
    static CGFloat x0 = 0;
    static CGFloat y0 = 0;
    static CGFloat z0 = 0;

    const NSTimeInterval dt = (1.0 / 20);
    const double RC = 0.3;
    const double alpha = dt / (RC + dt);

    CMAcceleration smoothedAcceleration;
    smoothedAcceleration.x = (alpha * acceleration.x) + (1.0 - alpha) * x0;
    smoothedAcceleration.y = (alpha * acceleration.y) + (1.0 - alpha) * y0;
    smoothedAcceleration.z = (alpha * acceleration.z) + (1.0 - alpha) * z0;

    x0 = smoothed.x;
    y0 = smoothed.y;
    z0 = smoothed.z;

    return smoothedAcceleration;
}

The alpha value determines how much weight to give the previous data vs the raw data. The dt is how much time elapsed between samples. RC value controls the aggressiveness of the filter. Bigger values mean smoother output.

Based on CMMotionManager Class Reference.