Motion Sensors Explainer

Editor’s Draft,

This version:
Latest published version:
Version History:
Feedback: with subject line “[motion-sensors] … message topic …” (archives)
Issue Tracking:
Kenneth Rohde Christiansen (Intel Corporation)
Bug Reports:
via the w3c/motion-sensors repository on GitHub


This explainer is an introduction to low-level and high-level motion sensors, their relation, inner workings and common use-cases. Common cases of event filtering and sensor fusion are introduced with examples, showing how to apply that on sensors following the Generic Sensor API specification.

Status of this document

This is a public copy of the editors’ draft. It is provided for discussion only and may change at any moment. Its publication here does not imply endorsement of its contents by W3C. Don’t cite this document other than as work in progress.

If you wish to make comments regarding this document, please send them to (subscribe, archives). When sending e-mail, please put the text “motion-sensors” in the subject, preferably like this: “[motion-sensors] …summary of comment…”. All comments are welcome.

This document was produced by the Device and Sensors Working Group.

This document was produced by a group operating under the 5 February 2004 W3C Patent Policy. W3C maintains a public list of any patent disclosures made in connection with the deliverables of the group; that page also includes instructions for disclosing a patent. An individual who has actual knowledge of a patent which the individual believes contains Essential Claim(s) must disclose the information in accordance with section 6 of the W3C Patent Policy.

This document is governed by the 1 March 2017 W3C Process Document.

1. Introduction

There are a handful of different motion sensors available in modern hardware such as phones.

The motion sensors extends the Generic Sensor API [GENERIC-SENSOR] to expose a class of low-level and fusion sensors. This document explains the relation between these sensors.

The low-level sensors include:

Multiple new sensors can be created using the data from these above sensors in different ways. These are commonly known as fusion sensors.

2. Security and Privacy Considerations

There are no specific security and privacy considerations beyond those described in the Generic Sensor API [GENERIC-SENSOR].

3. Low-level Sensors

3.1. Accelerometer

A raw accelerometer sensor measures changes in acceleration in 3 different directions, but is affected by gravity.

This means that when the device is in free fall, the acceleration will be 0 m/s2 in the falling direction, and when a device is laying flat on a table, the acceleration in upwards direction will be equal to the earth gravity, i.e. g := +9.8 m/s2 as it is measuring the force of the table holding up the device.

Accelerometers are less useful by themselves and often take part in other fusion sensors, but they do have some purposes like registering shakes, steps and the like.

Often for such use-cases the developer is interested in the linear acceleration which is the acceleration without the gravity, called gravity compensation (See Linear Acceleration Sensor); or the developer is interested in the isolated gravity, in order to know the gravity vector (see Gravity Sensor), which can be useful for some kinds of sensor fusion like creating a magnetic compass.

For acceleration, you usually care about the big changes and want to avoid noise, like the gravity, thus a high pass filter can help isolate the linear acceleration and a low pass filter can help isolate the gravity. A low pass filter can thus be useful for measuring a tilt. Unfortunately any high or low pass filter introduced a delay, which may or may not be acceptable.

Notice, as accelerometers report acceleration, you need to integrate to get velocity:

v = ∫a×∂t

And again to get position:

x = ∫v×∂t

An integral creates drift, and a double integral amplifies that:

a = g×sin(θ), x = ½×at2

So position from an accelerometer is very imprecise and not very useful.

3.2. Gyroscope

A gyroscope senses angular velocity, relative to itself, thus they measure their own rotation, using something called the Coriolis effect. Gyroscopes oscillate at relative high frequency in order to measure this and are thus one of the most power hungry motion sensors. This also means that they can easily be effected by other vibrations, like a vibration (rumble) motor or speaker on the same device.

In order to get rotation (angle) from a gyroscope, which senses angular velocity, you need to perform a single integration.

f ≡ frequency

∫cos(2π×ft)) = (1/(2π×f)) × sin(2π×ft)

But be aware that integration turns noise into drift. As we see above, the integration gets a 1/f outside, meaning that high frequency (f) noise disappears with integration, i.e. a noise of frequency will drop by a factor of a 100, but a very low frequency will be amplified, meaning the gyroscope will drift over time.

So in order to do it well you need to do it quickly and as you see below, we multiply with the ∂t, so any error in the reported time difference will manifest itself like the drift above.

θn = θn-1 + ω × ∂t

With ω denoting the angular velocity and θ, the resulting angle.

Most gyroscope sensors applies some soft of drift compensation in hardware for known low frequency caused by adjacent hardware on the device.

3.3. Magnetometer

Magnetometers are magnetic field sensors, which means that without any strong magnetic influence close by, it will sense the earth’s magnetic field, which more or less points in the direction of north, but not true north.

As said, magnetometers are very sensitive to outside influence, like anything on a table that has been slightly magnetized, and it is even affected by other things inside a device, though the device manufacturer can compensate for this somewhat. In practise though, these sensors work quite well for most common use-cases.

As long as nothing that is magnetizes in the surrounding is moving around, then the magnetometer readings are stable enough to be used to isolate gravity as mentioned above.

Magnetometers are 3-axis sensors, which means that it gives a 3D vector pointing to the strongest magnetic field. This also means that they don’t enforce a specific device orientation in order to work.

In order to tell how the device is being held, though, you need a gravity vector, which as a bare minimum requires an accelerometer, in the case of low pass filtering, and additionally a gyroscope if more precise readings are needed. This is called tilt compensation.

The most common use-case for magnetometers are as part of sensor fusion, in order to generate an Orientation Sensor which is stationary to the earth plane, or a compass, which is basically the former with corrections to the declination depending on geolocation position, such that it points to the true north.

4. High-level Sensors

As mentioned above, each sensor has its own issues, such as noise and drift, and often need some kind of compensation using input from a different sensor. Put another way, one sensor might not be very precise on its own, but the sum of multiple sensory input can be much more stable.

Unfortunately, sensors require power, and the more sensors and the higher measuring frequency, the higher power consumption. The gyroscope is typically considered more power hungry than the rest, as it needs to vibrate at a certain frequency in order to measure the angular velocity.

For the above reasons, it is always important to consider the minimum set of sensors which solves a task satisfactory. As many devices today can do certain kinds of sensor fusion in hardware, it most often makes sense to use these from a power and performance point of view.

4.1. Common fusion sensors

Below is a list of fusion sensors and what sensors they usually are made up of:

Sensor type Underlying physical sensors
Relative Orientation Sensor Accelerometer, Gyroscope, MUST NOT USE Magnetometer
Orientation Sensor Accelerometer, Magnetometer, AND (when present) Gyroscope
Geomagnetic Orientation Sensor Accelerometer, Magnetometer, MUST NOT USE Gyroscope
Gravity Sensor Accelerometer, Gyroscope
Linear Acceleration Sensor Accelerometer, AND EITHER Gyroscope OR Magnetometer

4.2. Low and high pass filters

As mentioned earlier, it is possible to remove noise (high or low frequency) using low and high pass filters. As the names say, the filters lets low or high frequencies pass and thus cuts of - or minimized the effect of unwanted frequences.

4.2.1. Low-pass filter

A common way to create a low-pass filter is to only use a percentage of the latest value and take the rest from the existing value. In a way this means that the filter remembers common values and thus smoothens out uncommon values which most often is a result of noise. As it uses a big percentage of the existing value, this solution introduces a delay in registering the actual events.

class LowPassFilterData {
  constructor(reading, bias) {
    Object.assign(this, { x: reading.x, y: reading.y, z: reading.z });
    this.bias = bias;

  update(reading) {
    this.x = this.x * this.bias + reading.x * (1 - this.bias);
    this.y = this.y * this.bias + reading.y * (1 - this.bias);
    this.z = this.z * this.bias + reading.z * (1 - this.bias);

const accl = new Accelerometer({ frequency: 20 });
// Isolate gravity with low-pass filter.
const filter = new LowPassFilterData(accl, 0.8);

accl.onchange = () => {
  filter.update(accl); // Pass latest values through filter.
  console.log(`Isolated gravity (${filter.x}, ${filter.y}, ${filter.z})`);


4.2.2. High-pass filter

High-pass filters works like low-pass ones, but allows only high frequencies to pass through.

This can be useful in such cases like to get rid of the drift which builds up over time with gyroscope readings.

class HighPassFilterData {
  constructor(reading, cutoffFrequency) {
    Object.assign(this, { x: reading.x, y: reading.y, z: reading.z });
    this.cutoff = cutoffFrequency;
    this.timestamp = reading.timestamp;

  update(reading) {
    let dt = reading.timestamp - this.timestamp / 1000;
    this.timestamp = reading.timestamp;

    for (let i of ["x", "y", "z"]) {
      let alpha = this.cutoff / (this.cutoff + dt);
      this[i] = this[i] + alpha * (reading[i] - this[i]);

const gyro = new Gyroscope({ frequency: 20 });
// Remove drift with a  high pass filter.
const filter = new HighPassFilterData(gyro, 0.8);

gyro.onchange = () => {
  filter.update(gyro); // Pass latest values through filter.
  console.log(`Steady gyroscope (${filter.x}, ${filter.y}, ${filter.z})`);


4.3. Orientation Sensor

As mentioned before, the Orientation Sensor, is one of the common use-cases of a magnetometer, and it a sensor representing an orientation stationary (fixed to the magnetic field vector and gravity vector) to the earth plane.

An orientation sensor can be useful for game controls such as a ball-in-a-maze puzzle, or for a head-mounted display where you want to be able to rotate the display and look in all directions.

As the reference frame of an orientation sensor is stationary, they are not useful as a controller for say a driving game on a phone, as they would not allow you to move around, even slightly or slowly, without affecting your driving direction. (See Relative Orientation Sensor).

The orientation vector of the Orientation Sensor, can be calculated the following way:

The gravity vector points towards the earth’s core when mostly stationary and as long as we are not at the poles, we have enough vector length to project that gravity vector onto the ground plane.

By taking the cross product between the gravity vector (see Gravity Sensor) and the magnetic field vector, we get a vector which points East on the ground plane, using the right hand rule.

Now if we take the cross product of the gravity vector with the newly found East vector, then it will point in the northern direction towards the earth’s magnetic field.

Thus an Orientation Sensor is a fusion sensor of the Magnetometer and the Accelerometer, and potentially the Gyroscope for better isolated gravity (see Gravity Sensor).

4.4. Geomagnetic Orientation Sensor

A Geomagnetic Orientation Sensor, is a like the Orientation Sensor, but doesn’t use the Gyroscope which means that it uses less power. This also means that it is more sensitive to shakes and movement.

As the main use-case for a Geomagnetic Orientation Sensor is to create a compass, or use compass direction within a mapping application, this is not much of a problem as people usually hold the device steady for these use-cases.

The actual heading (N, S, E, W) can be found by adjusting the rotation vector with the local declination compensation calculated from the current geolocation position.

As the sensor uses the accelerometer to get a more steady heading, like when walking, the rotation vector is projected to the plane pendicular to the gravity vector (as isolated from the Accelerometer) which more or less represents the ground plane. This also means that if you are interested in the actual orientation of the gravity vector, then use the Magnetometer directly instead.

4.5. Relative Orientation Sensor

On most sensor hubs, gravity is isolated from the accelerometer using the gyroscope, and the linear acceleration is isolated by removing the isolated gravity, from the accelerometer values.

This avoids the delay which low and high pass filters introduce.

One way of doing this is using a Kalman filter or complementary filter, which leads us to the Relative Orientation Sensor. As a complementary filter yields quite good results and is easy to implement in hardware, this is a common solution.

4.5.1. Complementary filter

A complementary filter can be thought of as a low and high pass filter in one, complementing the gyroscope values with the accelerometer values:

θn = α × (θn-1 + ω × ∂t) + (1.0 - α) × a

With α being the weight constant, a the acceleration from accelerometer, ω the angular velocity from gyroscope and ∂t being the time between measurements.

A common value for 𝛼 is 0.98, which means that 98% of the weight lays on the gyroscope measurements.

Manually calculate the relative orientation in Euler angles (radian) using a complementary filter.

The gyroscope measures angular velocity, so by multiplying with the time difference, we get the change of angle. This change is always calculated relative to the current device position, so we need to use the accelerometer, which includes gravity, to calibrate this to the ground plane.

The values from the accelerometer brings no information about the heading (alpha, the rotation around z), so we don’t include that in our alpha component. On the other hand, the accelerometer (due to gravity) provides info on how the device is held around the x and y axis (beta and gamma).

When there are no or little movements, the vector obtained from the accelerometer reading, will contribute more to the (alpha, beta, gamma) angles than the gyroscope.

As values from a steady accelerometer represents the gravity vector, and we don’t include the z component in the alpha, the result of this is that the orientation will just follow the gyroscope and be stable. But as the origin of the heading depends on the device position at start this makes this a device-relative orientation sensor.

const options = { frequency: 50 };

const accl = new Accelerometer(options);
const gyro = new Gyroscope(options);

let timestamp = null;
let alpha = beta = gamma = 0;
const bias = 0.98;

gyro.onchange = () => {
   let dt = timestamp ? (gyro.timestamp - timestamp) / 1000 : 0;
   timestamp = gyro.timestamp;

   // Treat the acceleration vector as an orientation vector by normalizing it.
   // Keep in mind that the if the device is flipped, the vector will just be
   // pointing in the other direction, so we have no way to know from the
   // accelerometer data which way the device is oriented.
   const norm = Math.sqrt(accl.x ** 2 + accl.y ** 2 + accl.z ** 2);

   // As we only can cover half (PI rad) of the full spectrum (2*PI rad) we multiply
   // the unit vector with values from [-1, 1] with PI/2, covering [-PI/2, PI/2]
   const scale = Math.PI / 2;

   alpha = alpha + gyro.z * dt;
   beta = bias * (beta + gyro.x * dt) + (1.0 - bias) * (accl.x * scale / norm);
   gamma = bias * (gamma + gyro.y * dt) + (1.0 - bias) * (accl.y * -scale / norm);

   // Do something with Euler angles (alpha, beta, gamma).

An device-adjusting, relative orientation sensor.

From the above example, we notices that the alpha represented the initial heading orientation. We also know that this heading might drift over time due to being based on the gyroscope.

In some situations you might want the orientation to drift towards your current position. This can be useful for a controller inside a virtual reality environment, where you want a car to follow the heading of your controller, but you might move and turn around while playing. That would more or less work like driving a real car.

Changing one line in the above accomplishes that.

const zeroBias = 0.02;
alpha = (1 - zeroBias) * (alpha + gyro.z * dt);

With the above 2% of the alpha consists of the value 0. Thus, when the device is being held more or less steady, the heading will move towards 0, meaning being adjusted to your current device position and not positioned according to the surroundings.

This shows how useful manual fusion can be at times.

4.6. Gravity and Linear Acceleration Sensor

The complementary filter used above is quite good at isolating the gravity, and most sensor hubs thus isolate gravity from the accelerometer using the gyroscope, and the linear acceleration is isolated by removing the isolated gravity, from the accelerometer values.

This also means that the Linear Acceleration Sensor and the Gravity Sensor as exposed by most sensor hubs are most likely fusion sensors.

Gravity can also be removed from a linear acceleration sensor using a magnetometer, as the magnetic field vector is more or less stable.

Note, as the gravity changes with the frequency of the movements, i.e., 0 in falling direction in free fall, you can imagine that linear acceleration will be quite imprecise if you are trying to detect a shake, so keep that in mind.


Terms defined by this specification


Normative References

Tobie Langel; Rick Waldron. Generic Sensor API. URL: