Сглаживание значений массива

Если бы у меня был массив чисел, таких как [3, 5, 0, 8, 4, 2, 6], Есть ли способ, чтобы "сгладить" значения, поэтому они ближе друг к другу и дисплей меньше дисперсия?

Я просмотрел оконные данные, используя что-то, называемое функцией Гаусса для 1-мерном случае, который является моим массивом, но у меня возникли проблемы с его реализацией. этой теме кажется, решить именно то, что мне нужно, но я не понимаю, как пользователь 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 ответов


интересный вопрос!

алгоритм сглаживания значений, очевидно, может варьироваться много, но вот мое мнение:

"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));

Примечание: он использует некоторые функции ES6, такие как функции fat-arrow и строки шаблонов. Firefox 35+ и Chrome 45+ должны работать нормально. Пожалуйста, используйте babel repl в противном случае.

мой метод в основном вычисляет среднее арифметическое всех элементов массива заранее, и использует это как основные фактор для вычисления нового значения вместе с текущим значением элемента, до него и после него. Я также использую Предыдущее значение как one нов вычисляется, а не из исходного массива. Не стесняйтесь экспериментировать и изменять в соответствии с вашими потребностями. Вы также можете передать параметр "дисперсия" для управления разницей между элементами. Снижение его принесет элементы гораздо ближе друг к другу, так как это уменьшает значение средняя величина.

небольшое изменение, чтобы ослабить сглаживание, будет следующим:

"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));

который не принимает усредненное значение в качестве основного фактора.

Не стесняйтесь экспериментировать, надеюсь, что помогает!


техника вы описываете звучит как версии 1D из размытие по Гауссу. Умножьте значения 1D гауссовского массива раз на заданное окно в массиве и суммируйте результат. Например

  1. предполагая гауссовский массив {.242, .399, .242}
  2. для вычисления нового значения в позиции n входного массива-умножьте значения в n-1, n и n+1 входного массива на значения в (1) и суммируйте результат. например [3, 5, 0, 8, 4, 2, 6], н = 1:

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

вы можете изменить дисперсию Гауссова, чтобы увеличить или уменьшить влияние размытия.