Подтвердить что ты не робот

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

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

Ive посмотрел на окно данных, используя что-то, называемое гауссовой функцией, для 1-мерного случая, который является моим массивом, но у меня проблемы с его реализацией. Этот поток, кажется, решает именно то, что мне нужно, но я не понимаю, как пользовательское нашивание (второе сообщение) придумало значения матрицы Гаусса.

Контекст: Я работаю над генератором звуковых сигналов (заимствованием из проекта SoundClouds), который отображает амплитуду песни в момент времени 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]

Обратите внимание, как цифры намного ближе друг к другу.

EDIT 2: Это сработало! Благодаря алгоритму пользователя Awal Garg, вот результаты:

Отсутствие сглаживания 0HQpG0o.png Некоторые сглаживания uwMpXcU.png Максимальное сглаживание IkCbh5j.png

EDIT 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);
4b9b3361

Ответ 1

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

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

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

Ответ 2

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

  • Предполагая гауссовский массив {.242,.399,.242}
  • Чтобы вычислить новое значение в позиции 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

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