javascript - Smoothing out values of an array -


if had array of numbers such [3, 5, 0, 8, 4, 2, 6], there way “smooth out” values they’re closer each other , display less variance?

i’ve looked windowing data using called gaussian function 1-dimensional case, array, having trouble implementing it. this thread seems solve need don’t understand how user naschilling (second post) came gaussian matrix values.

context: i’m working on music waveform generator (borrowing soundcloud’s design) maps amplitude of song @ time t corresponding bar height. unfortunately there’s lot of noise, , looks particularly ugly when program maps tiny amplitude results in sudden decrease in height. want smooth out bar heights aren’t varied.

the language i'm using javascript.

edit: sorry, let me more specific "smoothing out" values. according thread linked above, user took array

[10.00, 13.00, 7.00, 11.00, 12.00, 9.00, 6.00, 5.00] 

and used gaussian function map to

[ 8.35,  9.35, 8.59,  8.98,  9.63, 7.94, 5.78, 7.32] 

notice how numbers closer each other.

edit 2: worked! user awal garg's algorithm, here results:

no smoothing some smoothing maximum smoothing

edit 3: here's final code in js. tweaked first , last elements of array able find neighbors wrapping around array, rather calling itself.

var array = [10, 13, 7, 11, 12, 9, 6, 5];  function smooth(values, alpha) {     var weighted = average(values) * alpha;     var smoothed = [];     (var in values) {         var curr = values[i];         var prev = smoothed[i - 1] || values[values.length - 1];         var next = curr || values[0];         var improved = number(this.average([weighted, prev, curr, next]).tofixed(2));         smoothed.push(improved);     }     return smoothed; }  function average(data) {     var sum = data.reduce(function(sum, value) {         return sum + value;     }, 0);     var avg = sum / data.length;     return avg; }  smooth(array, 0.85); 

interesting question!

the algorithm smooth out values vary lot, here take:

"use strict";  var array = [10, 13, 7, 11, 12, 9, 6, 5];    function avg (v) {    return v.reduce((a,b) => a+b, 0)/v.length;  }    function smoothout (vector, variance) {    var t_avg = avg(vector)*variance;    var ret = array(vector.length);    (var = 0; < vector.length; i++) {      (function () {        var prev = i>0 ? ret[i-1] : vector[i];        var next = i<vector.length ? vector[i] : vector[i-1];        ret[i] = avg([t_avg, avg([prev, vector[i], next])]);      })();    }    return ret;  }    function display (x, y) {    console.clear();    console.assert(x.length === y.length);    x.foreach((el, i) => console.log(`${el}\t\t${y[i]}`));  }    display(array, smoothout(array, 0.85));

note: uses es6 features fat-arrow functions , template strings. firefox 35+ , chrome 45+ should work fine. please use babel repl otherwise.

my method computes average of elements in array in advance, , uses major factor compute new value along current element value, 1 prior it, , 1 after it. using prior value 1 newly computed , not 1 original array. feel free experiment , modify according needs. can pass in "variance" parameter control difference between elements. lowering bring elements closer each other since decreases value of average.

a slight variation loosen out smoothing this:

"use strict";  var array = [10, 13, 7, 11, 12, 9, 6, 5];    function avg (v) {    return v.reduce((a,b) => a+b, 0)/v.length;  }    function smoothout (vector, variance) {    var t_avg = avg(vector)*variance;    var ret = array(vector.length);    (var = 0; < vector.length; i++) {      (function () {        var prev = i>0 ? ret[i-1] : vector[i];        var next = i<vector.length ? vector[i] : vector[i-1];        ret[i] = avg([t_avg, prev, vector[i], next]);      })();    }    return ret;  }    function display (x, y) {    console.clear();    console.assert(x.length === y.length);    x.foreach((el, i) => console.log(`${el}\t\t${y[i]}`));  }    display(array, smoothout(array, 0.85));

which doesn't take averaged value major factor.

feel free experiment, hope helps!


Comments