API Docs for: 2.0.0

src/node-1euro.js

/**
 * Provides 1euro filtering technique
 *
 * Author: Florian Renaut (florian.renaut@gmail.com)
 *
 * Details: http://www.lifl.fr/~casiez/1euro
 *
 * @class oneEuroFilter
 * @module server
 * @submodule oneEuroFilter
 */

// require variables to be declared
"use strict";

function lowPassFilter(alpha, initval) {
	var that = {};
	var y = initval || 0;
	var s = y;

	function lowpass(v) {
		y = v;
		s = alpha * v + (1 - alpha) * s;
		return s;
	}

	that.filter = function(v) {
		y = v;
		s = v;
		that.filter = lowpass;
		return s;
	};

	that.filterWithAlpha = function(v, a) {
		alpha = a;
		return that.filter(v);
	};

	that.hasLastRawValue = function() {
		return that.filter === lowpass;
	};

	that.lastRawValue = function() {
		return y;
	};

	return that;
}

/**
 * Class describing a filter
 *
 * @class oneEuroFilter
 * @constructor
 * @param freq {Number} Data update rate
 * @param mincutoff {Number} Minimum cutoff frequency
 * @param beta {Number} Cutoff slope
 * @param dcutoff {Number} Cutoff frequency for derivate
 * @return {Object} an object representing a filter
 */
function oneEuroFilter(freq, mincutoff, beta, dcutoff) {

	function alpha(cutoff) {
		var te = 1 / freq;
		var tau = 1 / (2 * Math.PI * cutoff);
		return 1 / (1 + tau / te);
	}

	var that = {};
	var x  = lowPassFilter(alpha(mincutoff));
	var dx = lowPassFilter(alpha(dcutoff));
	var lastTime;

	mincutoff = mincutoff || 1;
	beta = beta || 0;
	dcutoff = dcutoff || 1;

	that.filter = function(v, timestamp) {
		if (lastTime !== undefined && timestamp !== undefined) {
			freq = 1 / (timestamp - lastTime);
		}
		lastTime = timestamp;
		var dvalue = x.hasLastRawValue() ? (v - x.lastRawValue()) * freq : 0;
		var edvalue = dx.filterWithAlpha(dvalue, alpha(dcutoff));
		var cutoff = mincutoff + beta * Math.abs(edvalue);
		return x.filterWithAlpha(v, alpha(cutoff));
	};

	return that;
}

module.exports = oneEuroFilter;