平滑数组的值

时间:2015-09-25 18:53:01

标签: javascript arrays smoothing

如果我有一个数组,如[3,5,5,8,4,2,6],有没有办法“平滑”这些值,使它们彼此更接近并显示更少方差σ

我已经研究过使用高斯函数对一个 1维情况进行窗口化处理,这是我的数组,但是在实现它时遇到了麻烦。 This thread似乎正好解决了我的需要,但我不明白用户naschilling(第二篇文章)如何提出高斯矩阵值。

背景:我正在研究音乐波形发生器(借用SoundCloud的设计),将时间 t 的歌曲幅度映射到相应的条形高度。不幸的是,有很多噪音,当程序映射出微小的振幅导致高度突然下降时,它看起来特别难看。我基本上想要平滑酒吧的高度,所以它们不是那么多变。

我使用的语言是Javascript。

编辑:抱歉,让我更具体地说明“平滑”这些值。根据上面链接的线程,用户采用了数组

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

并使用高斯函数将其映射到

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

注意数字是如何彼此更接近的。

编辑2 :它奏效了!感谢用户Awal Garg的算法,结果如下:

没有平滑 一些平滑 最大平滑

编辑3 :这是我在JS中的最终代码。我调整了它,以便数组的第一个和最后一个元素能够通过包裹数组来找到它的邻居,而不是自己调用它。

var array = [10, 13, 7, 11, 12, 9, 6, 5];

function smooth(values, alpha) {
    var weighted = average(values) * alpha;
    var smoothed = [];
    for (var i 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);

2 个答案:

答案 0 :(得分:7)

有趣的问题!

平滑值的算法显然可以改变 lot ,但这是我的看法:



"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);
  for (var i = 0; i < 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));
&#13;
&#13;
&#13;

注意:它使用一些ES6功能,如胖箭头功能和模板字符串。 Firefox 35+和Chrome 45+应该可以正常工作。请使用babel repl否则。

我的方法基本上是预先计算数组中所有元素的平均值,并将其用作主要因子来计算新值以及当前元素值,前一个元素值,以及之后的那个。我也使用先前值作为计算的那个,而不是原始数组中的那个。您可以根据自己的需要进行实验和修改。您还可以传递&#34;差异&#34;参数来控制元素之间的差异。降低它会使元素彼此更接近,因为它会降低平均值。

稍微改变以放松平滑将是这样的:

&#13;
&#13;
"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);
  for (var i = 0; i < 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));
&#13;
&#13;
&#13;

并不将平均值作为主要因素。

随意尝试,希望有所帮助!

答案 1 :(得分:6)

您描述的技术听起来像Gaussian blur的1D版本。将1D高斯数组的值乘以数组中给定窗口的时间并对结果求和。例如

  1. 假设高斯数组{.242,.399,.242}
  2. 计算输入数组位置n的新值 - 将输入数组的n-1,n和n + 1处的值乘以(1)中的值,并将结果相加。例如[3,5,0,8,4,2,6],n = 1:

    n1 = 0.242 * 3 + 0.399 * 5 + 0.242 * 0 = 2.721

  3. 您可以更改高斯的方差,以增加或减少模糊的影响。