Детектор уровня звука на Arduino своими руками
Платформа Arduino зарекомендовала себя уже во многих радиолюбительских проектах благодаря своей простоте и функциональности. С ее помощью делают системы домашней автоматизации, устройства Интернета вещей и прочие электронные приборы и системы. Кроме того, Arduino может с успехом применяться в музыкальных приложениях.
Так, на основе Arduino можно самостоятельно собрать детектор уровня звука или бит-детектор для регистрации сигналов (преимущественно звуковых) определенного уровня.
Идея этого проекта заключается в использовании Arduino для обнаружения ударов (битов) в музыке на линейном выходе (например, красный и белый RCA аудио кабели). Проект довольно прост, но был бы еще проще, если бы не ограничение аналогового входа Arduino, который может принимать сигналы напряжением от 0 до 5 В. Но аудиосигнал – это сигнал переменного тока, и он может менять свое значение относительно нуля. Итак, как получить отрицательную часть волны аудиосигнала на входе Arduino? Необходимо сместить ноль на уровень 2.5 В. В итоге волна сигнала будет «ходить» выше и ниже этого нового нуля. Только так мы сможем подключиться к аналоговому входу Arduino. Схема подключения приведена на рисунке ниже.
Ниже приведен код (скетч) для Arduino, который позволяет определить уровень бита в аудиосигнале, и в зависимости от этого можно сформировать какое-либо действие на выходе, например, мигание светодиода или включение реле.
#define SAMPLEPERIODUS 200
// Определение настроек и очистка битов регистров
#ifndef cbi
#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))
#endif
#ifndef sbi
#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))
#endif
void setup() {
// Настройка АЦП на 77 КГц и 10 разрядов
sbi(ADCSRA,ADPS2);
cbi(ADCSRA,ADPS1);
cbi(ADCSRA,ADPS0);
// Вывод на светодиод или реле
pinMode(2, OUTPUT);
}
// КИХ-фильтр 20 - 200 Гц
float bassFilter(float sample) {
static float xv[3] = {0,0,0}, yv[3] = {0,0,0};
xv[0] = xv[1]; xv[1] = xv[2];
xv[2] = (sample) / 3.f; // измените на значение близкое к 2, чтобы адаптировать силу источника аудиосигнала
yv[0] = yv[1]; yv[1] = yv[2];
yv[2] = (xv[2] - xv[0])
+ (-0.7960060012f * yv[0]) + (1.7903124146f * yv[1]);
return yv[2];
}
// КИХ-фильтр 10 Гц
float envelopeFilter(float sample) {
static float xv[2] = {0,0}, yv[2] = {0,0};
xv[0] = xv[1];
xv[1] = sample / 50.f;
yv[0] = yv[1];
yv[1] = (xv[0] + xv[1]) + (0.9875119299f * yv[0]);
return yv[1];
}
// КИХ-фильтр 1.7 - 3.0 Гц
float beatFilter(float sample) {
static float xv[3] = {0,0,0}, yv[3] = {0,0,0};
xv[0] = xv[1]; xv[1] = xv[2];
xv[2] = sample / 2.7f;
yv[0] = yv[1]; yv[1] = yv[2];
yv[2] = (xv[2] - xv[0])
+ (-0.7169861741f * yv[0]) + (1.4453653501f * yv[1]);
return yv[2];
}
void loop() {
unsigned long time = micros(); // Используется для отслеживания скорости сигнала
float sample, value, envelope, beat, thresh;
unsigned char i;
for(i = 0;;++i){
// Считывание АЦП и центрирование на +-512
sample = (float)analogRead(0)-503.f;
// Фильтровать только басовый компонент
value = bassFilter(sample);
// Взять амплитуду сигнала и отфильтровать
if(value < 0)value=-value;
envelope = envelopeFilter(value);
// Каждые 200 отсчетов (25 Гц) фильтровать огибающую
if(i == 200) {
// Отфильтровать повторяющиеся басовые звуки 100 - 180 bpm
beat = beatFilter(envelope);
// Уровень срабатывания, порог основан на потенциометре на AN1
thresh = 0.02f * (float)analogRead(1);
// Если порог превышен, то включаем светодиод или реле
if(beat > thresh) digitalWrite(2, HIGH);
else digitalWrite(2, LOW);
// сбрасываем счетчик
i = 0;
}
// Потребляет избыточные тактовые циклы, чтобы поддерживать 5000 Гц
for(unsigned long up = time+SAMPLEPERIODUS; time > 20 && time < up; time = micros());
}
}