...

Implementing a simple one dimension Kalman Filter in NodeJS

You can try my kalman filter implementation here.

Kalman filtering, also known as linear quadratic estimation (LQE), is an algorithm that uses a series of measurements observed over time, containing statistical noise and other inaccuracies, and produces estimates of unknown variables that tend to be more accurate than those based on a single measurement alone, by estimating a joint probability distribution over the variables for each timeframe. The filter is named after Rudolf E. Kálmán, one of the primary developers of its theory.(Kalman Filter Wikipedia).

In order to implement the Kalman algorithm I have to draw a little flowchart of the algorithm :

...

The most 3 important steps in implementation of this algorithm are shown clearly in the picture above :

1.Calculate Kalman Gain,

KG = Eest/Eest + Emes where KG = Kalman Gain; Eest = error in estimate; Emes = error in measurement;

2.Calculate current estimated state,

ESTk = ESTk-1 + KG[MEA-ESTk-1] where ESTk = Current estimate; Estk-1 = Previous estimate; MEA = Measured state;

3.Calculate new error in estimate

Eest = EestK-1 - KG*EestK-1 where Eest = error in estimate; EestK-1 = previous error in estimate.


const  kalman = (data, kalmanParams) => {

    let R = kalmanParams.R;//expected noise
    
    let Q = kalmanParams.Q;//measured noise
    
    let A = kalmanParams.A;//state vector
    
    let y = NaN;
    
    let Err = NaN;
    
    let filtered = data.map(x => {
    
    if (isNaN(y)) {
        
        y = x;
        
        Err = Q;
        
    } else {
    
        /* Calculate previous state and previous error in estimate */
        
        let prevX = A * y;
        
        let prevErr = ((A * Err) * A) + R;
        
        
        
        /* calculate Kalman Gain */
        
        let K = prevErr / (prevErr + Q);
        
        
        
        /* Calculate new error in estimate */
        
        Err = prevErr - (K * prevErr);
        
        /* Calculate current estimate */
        
        y = prevX + K * (x - prevX); 
        
        return y;
        
    }});
    
    return filtered;

}
                        

The implemented algorithm receives 3 arguments R = kalmanParams.R = expected noise, Q = kalmanParams.Q = measured noise, A = kalmanParams.A = state vector and also the input that is an array of points that draw the raw signal.

Raw signal is generated in backend. There are 3 types of generated signal :

1.Linear


/* sinusoidal function generator */
for(i=0;i<100;i++){
    rawSignalSin.push(Math.sin(2 * Math.PI * i/100 * 5));
}

2.Exponential


/* exponential function generator */
for(i=0;i<100;i++){
    rawSignalExp.push(Math.pow(0.8, i));
}

3.Low frequency Sine Wave


/* sinewave function generator */
for(i=0;i<100;i++){
    rawSignalSin.push(Math.sin(2 * Math.PI * i/100 * 5));
}

For the purpose of this experiment, noise data was generated using the Math.random() method and added to the raw data.


/* Add noise to exonential function */
let noisySignalExp = rawSignalExp.map(function(v) {

    return v + Math.random();

});

/* Add noise to liniar function */

let noisySignalLin = rawSignalLin.map(function(v) {

    return v + Math.random();

});

/* Add noise to sinewave function */

let noisySignalSin = rawSignalSin.map(function(v) {

    return v + Math.random();

});
                        
...

The kalman filter algorithm was applied on the noisy data and the result of Kalman filtering can be seen in the next picture , the waveform in red color is the exponential function filtered by Kalman algorithm.

...