Сглаживание значений массива
Если бы у меня был массив чисел, таких как [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 гауссовского массива раз на заданное окно в массиве и суммируйте результат. Например
- предполагая гауссовский массив {.242, .399, .242}
-
для вычисления нового значения в позиции 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
вы можете изменить дисперсию Гауссова, чтобы увеличить или уменьшить влияние размытия.