Я рассчитываю среднее значение массива значений журнала (децибел, если это имеет значение) в JavaScript. Мне пришло в голову, что если числа являются логарифмическими значениями (где 55 - это 10, умноженное на 54), средний уровень в децибелах не будет средним от логарифмов. Какой лучший способ подойти к этому?

Ниже приведен код, в котором я обычно вычисляю среднее значение в JS. Какой бы изящный способ вычислить среднее значение массива лог-значений в JavaScript?

// These values are in decibels
const samples = [40, 50, 55, 80, 45];
document.getElementById('samples').innerText = JSON.stringify(samples);

let total = 0;

samples.forEach(value => {
  total = total + value;
});

const average = total / samples.length;

document.getElementById('avg').innerText = JSON.stringify(average);
<div>
  Decibel samples:
  <span id="samples"></span>
</div>

<div>
  Average:
  <span id="avg"></span>
</div>
1
caitlin 2 Май 2019 в 16:12

3 ответа

Лучший ответ

Основано на определении децибела (@schnauss) децибела в Википедии. Есть 2 определения: мощность и амплитуда децибел. Я смотрю на мощность децибела.

Избавьтесь от логарифмов, найдите средний и повторно примените логарифм.

mathematics behind the calculations

var samples = [40, 50, 55, 80, 45],
    x = 0.0;

samples.forEach(value => {
    x += Math.pow(10, value/10.0);
});

var average = x / samples.length,
    logAverage = 10 * Math.log10(average);
    
console.log(logAverage);

Результат ~ 73 дБ

2
yW0K5o 2 Май 2019 в 14:12

Я думаю, это подходящая формула. (Децибелы могут быть довольно запутанными.)

const mean = (ns) => ns.reduce((a, b) => a + b, 0) / (ns.length || 1)

const decibelAverage = (decibels) =>
    10 * Math.log10(mean(decibels.map(n => 10 ** (n / 10))))

console.log(decibelAverage([40, 50, 55, 80, 45])) //~> 73.03013877157564

Дело в том, что децибел представляет 10-кратный логарифм базового-10 уровня мощности. (Существует также другой тип децибела. Если вам нужно, то где-то вокруг есть плавающий квадратный корень.)

1
Scott Sauyet 2 Май 2019 в 14:24

Простой подход может состоять в том, чтобы инвертировать журнал в значения, сделать среднее значение, как обычно, и затем применить журнал к результату. Это может быть более эффективный способ выполнения этой операции, но если производительность не критична, вы можете попробовать ее.

Я не могу попробовать этот код, поэтому, если что-то пойдет не так, не стесняйтесь говорить что-нибудь! Любое предложение приветствуется.

РЕДАКТИРОВАТЬ: забыл заново сделать журнал в конце, просто добавил его

// These values are in decibels
const samples = [40, 50, 55, 80, 45];

//Undo the log. Be careful if base 10 is not the one you are using!
samples.forEach(function(element, index, array){
    array[index] = Math.pow(10, element);
});

document.getElementById('samples').innerText = JSON.stringify(samples);

let total = 0;
 
 samples.forEach(value => {
   total = total + value;
 });

const average = Math.log10(total / samples.length);

document.getElementById('avg').innerText = JSON.stringify(average);
<div>
  Decibel samples:
  <span id="samples"></span>
</div>

<div>
  Average:
  <span id="avg"></span>
</div>
1
caitlin 2 Май 2019 в 14:10