Search code examples
androidaccelerometersensorsdetectvibration

Detect vibration with Android accelerometer


I'm trying to detect patterns of knocking on the surface that the device is located on.

For example, if a user knocks one time on the surface, run method A. If the user knocks two times, run method B.

I have everything I need to make this happen except for the logics in the onSensorChanged method. This is my code right now:

@Override
public void onSensorChanged(SensorEvent event) {
    float x = event.values[0];
    float y = event.values[1];
    float z = event.values[2];

    //Check time interval, not sure if this is correct though.
    long actualTime = System.currentTimeMillis();
    if ((actualTime - lastUpdate) > 100) {
        long diffTime = (actualTime - lastUpdate);
        lastUpdate = actualTime;

        //This is where the magic should happen
    }
}

I guess the main question is, how do I detect vibrations? Almost all other examples on the net is about how to detect shakes and movement.


Solution

  • Real answer- you're going to need to study DSP to get good results. This is a non-trivial problem.

    Quick overview- when a vibration occurs, you're going to see a sinusoidal attenuating wave pattern (the attenuating signal after the main vibration is called "ringing" and is a bad thing for us- it means we need to separate ringing from real results). This can be detected and a vibration signalled based on looking for rapid changes in amplitude on the downwards vector (whichever one has gravity on it at the moment). The relative heights of the peak of the waves should be the relative strength of the knock.

    So detecting one knock is fairly easy. Things that aren't easy:

    *Telling the difference between a knock and footsteps across the room- both cause vibrations. They'll look the same. You may be able to filter it out via frequency analysis and filters

    *Telling two knocks vs one knock in a short time frame. The second knock tends to be weaker, and will be difficult to tell apart form the ringing of the first knock. It may also have destructive interference with the first wave.

    *Telling exactly when a knock occurred. There will be a time delay that may not be constant, and trying to figure it out means trying to find an exact peak. Difficult to do with noise.

    *Telling a knock in a noisy environment (vibrationally noisy, not sound). Again, you'll need filtering.

    I've actually done this, somewhat. And failed mostly I think. We were able to detect knocks well, but not to filter out noise at all. Of course we were looking for extremely small (1 finger) knocks, if you're looking for sharp raps you'll have fewer problems as the spike will be larger compared to the noise level. If you're expecting a single sharp knock the basics of looking for large spikes and ignoring secondary spikes for N milliseconds afterwards may be enough for you. If it isn't you're going to spend a lot of time on this.