В этой статье мы рассмотрим создание 32-полосного анализатора-визуализатора спектра звуковых частот на основе платы Arduino. Надеемся, что этот проект вызовет интерес у аудио энтузиастов и любителей электроники, увлекающихся программированием Arduino. Компоненты, используемые в данном проекте, сравнительно дешево стоят, поэтому собрать его будет достаточно просто.
Основные особенности данного анализатора спектра:
- использует легко устанавливаемые библиотеки “arduinoFFT” и “MD_MAX72xx”;
- пять различных режимов отображения, переключаемых кнопкой;
- смешивание правого и левого каналов аудио сигнала, поэтому вы не пропустите ни один звук;
- использование 32х8 матричного дисплея из светодиодов, вы можете изменить это по своему желанию;
- аудио сигнал можно подать с выхода наушников или с выхода Line-out звуковой системы или усилителя.
Необходимые компоненты
- Плата Arduino Nano (купить на AliExpress) или Uno (купить на AliExpress).
- Светодиодный матричный дисплей 32х8.
- Кнопочный переключатель.
- Конденсатор 100 нФ (2 шт.) (купить на AliExpress).
- Резисторы 5 кОм (3 шт.), 10 кОм (1 шт.), 100 кОм (2 шт.) (купить на AliExpress).
- Источник питания с напряжением 5 В (можно по кабелю USB от компьютера).
Реклама: ООО "АЛИБАБА.КОМ (РУ)" ИНН: 7703380158
Значения сопротивлений резисторов не являются "строгими", вы можете варьировать их в небольших пределах по своему желанию. Но значения сопротивлений R1 и R2 (см. схему ниже) должны быть одинаковыми.
Общие принципы работы проекта
Плата Arduino сконструирована на основе микроконтроллера ATmega328P и имеет встроенные аналогово-цифровые преобразователи (в англ. аббревиатуре ADC - Analog To Digital converter), которые в нашем проекте используются для преобразования поступающего аналогового аудио сигнала в цифровую форму. АЦП Arduino производит дискретизацию поступающего входного сигнала с частотой дискретизации 38,46 кГц. Это достигается при помощи установки коэффициента деления предделителя (prescaler) АЦП равным 32. Если частота дискретизации равна 38,46 кГц, то согласно теореме Котельникова это значит что максимальная частота входного аналогового сигнала, который может быть преобразован без потерь в цифровую форму, равна 19,32 кГц – этого вполне достаточно для большинства аудио сигналов.
Главная цель проекта – показать спектр музыкального аудио сигнала. Для этого левый и правый каналы аудио сигнала смешиваются вместе и подаются на аналоговый контакт A0 платы Arduino. При необходимости вы можете использовать сплиттер чтобы подавать аудио сигнал одновременно и на анализатор спектра, и в другое какое-нибудь устройство, например, усилитель.
АЦП в данном проекте конфигурируются на использование внешнего опорного напряжения (reference voltage). В этом проекте в качестве опорного напряжения для АЦП используется стабилизированное напряжение 3.3v с платы Arduino. Поскольку аналоговый сигнал колеблется как выше, так и ниже нуля, мы должны использовать положительное напряжение смещения на входе АЦП – это необходимо для того чтобы АЦП не обрезал отрицательные циклы сигнала. То же самое стабилизированное напряжение разделяется с помощью двух резисторов R1 и R2 и затем подается на вход АЦП для формирования положительного напряжения смещения. С таким напряжением смещения на выходе АЦП будет значение 512 при отсутствии аудио сигнала на входе. В дальнейшем в коде программы это значение 512 вычитается чтобы получить реальные изменения входного сигнала.
"Сердцем" кода программы является библиотека ArduinoFFT – именно она выполняет быстрое преобразование Фурье (БПФ) и вычисляет спектр входного сигнала. Опытный образец данного проекта был сконфигурирован для формирования 64 отсчетов (сэмплов, samples) и выполнения быстрого преобразования Фурье над этими отсчетами. Библиотека ArduinoFFT может выполнять БПФ над числом отсчетов от 16 до 128 – это можно сконфигурировать в программе. Но для 128 отсчетов БПФ выполняется достаточно медленно, поэтому в нашем проекте мы решили ограничиться 128 отсчетами.
В качестве средства отображения спектра в нашем проекте используется светодиодная матрица 32 столбца х 8 строк. Управлять подобной матрицей сравнительно просто с помощью библиотеки MD_MAX72xx, которую мы будем использовать в нашем проекте. С помощью этой библиотеки можно включить/выключить любое число светодиодов в столбце, который в данный момент времени используется в программе. Амплитуда каждого частотного канала (полосы) конвертируется в диапазон от 0 до 8 и в зависимости от этой амплитуды зажигается необходимое количество светодиодов в столбце, то есть чем больше амплитуда, тем больше светодиодов в столбце будут гореть.
В проекте доступны 5 режимов дисплея, которые заключаются в различных вариантах включения светодиодов в столбцах. Каждый из этих режимов вы при необходимости можете перепрограммировать самостоятельно. Для переключения режимов используется кнопка. С каждым нажатием кнопки происходит переход к следующему режиму, при нажатии кнопки на 5-м режиме снова происходит переход к 1-му режиму. Эта кнопка подключена к цифровому контакту платы Arduino и после каждого обновления экрана дисплея производится проверка ее нажатия.
Частотная характеристика
Частотная характеристика проектируемого анализатора спектра была проверена с помощью подачи на вход анализатора синусоидального колебания, сформированной генератором сигналов на одном из веб-сайтов. Было установлено, что частотная характеристика анализатора достигает частоты 18,6 кГц.
Дополнительные детали
Чтобы узнать более полную информацию о данном проекте, необходимо посетить страницу автора этого проекта на сервисе github - https://github.com/shajeebtm/Arduino-audio-spectrum-visualizer-analyzer/.
Подача входного сигнала на анализатор спектра
Существует несколько способов подачи аудио сигнала на рассматриваемый нами анализатор спектра. Первый способ – взять аудио сигнал с выхода LINE out вашей музыкальной системы/усилителя. Второй способ – взять аудио сигнал с выхода наушников или мобильного телефона.
На следующем рисунке показан пример соединения выхода LINE out усилителя/музыкальной системы с анализатором спектра.
Далее на рисунке показан пример соединения выхода наушников/мобильной системы с анализатором спектра. Когда вы соедините кабель к выходу наушников вы уже не сможете услышать звук с них, поэтому в этом случае, если вы хотите и анализировать спектр сигнала, и слышать сам звук, вам необходимо будет использовать специальный разделитель.
Работа схемы
Схема устройства представлена на следующем рисунке.
Исходный код программы (скетча)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 |
/* Copyright (c) 2019 Shajeeb TM Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include <arduinoFFT.h> #include <MD_MAX72xx.h> #include <SPI.h> #define SAMPLES 64 //Must be a power of 2 #define HARDWARE_TYPE MD_MAX72XX::FC16_HW // Set display type so that MD_MAX72xx library treets it properly #define MAX_DEVICES 4 // Total number display modules #define CLK_PIN 13 // Clock pin to communicate with display #define DATA_PIN 11 // Data pin to communicate with display #define CS_PIN 10 // Control pin to communicate with display #define xres 32 // Total number of columns in the display, must be <= SAMPLES/2 #define yres 8 // Total number of rows in the display int MY_ARRAY[]={0, 128, 192, 224, 240, 248, 252, 254, 255}; // default = standard pattern int MY_MODE_1[]={0, 128, 192, 224, 240, 248, 252, 254, 255}; // standard pattern int MY_MODE_2[]={0, 128, 64, 32, 16, 8, 4, 2, 1}; // only peak pattern int MY_MODE_3[]={0, 128, 192, 160, 144, 136, 132, 130, 129}; // only peak + bottom point int MY_MODE_4[]={0, 128, 192, 160, 208, 232, 244, 250, 253}; // one gap in the top , 3rd light onwards int MY_MODE_5[]={0, 1, 3, 7, 15, 31, 63, 127, 255}; // standard pattern, mirrored vertically double vReal[SAMPLES]; double vImag[SAMPLES]; char data_avgs[xres]; int yvalue; int displaycolumn , displayvalue; int peaks[xres]; const int buttonPin = 5; // к этому контакту подключена кнопка int state = HIGH; // the current reading from the input pin int previousState = LOW; // the previous reading from the input pin int displaymode = 1; unsigned long lastDebounceTime = 0; // the last time the output pin was toggled unsigned long debounceDelay = 50; // the debounce time; increase if the output flickers MD_MAX72XX mx = MD_MAX72XX(HARDWARE_TYPE, CS_PIN, MAX_DEVICES); // display object arduinoFFT FFT = arduinoFFT(); // FFT object void setup() { ADCSRA = 0b11100101; // устанавливаем АЦП в режим непрерывного преобразования и коэффициент деления предделителя в 32 (0xe5) ADMUX = 0b00000000; // используем контакт A0 и внешнее опопрное напряжение pinMode(buttonPin, INPUT); mx.begin(); // инициализируем дисплей delay(50); // ждем пока опорное напряжение стабилизируется } void loop() { // ++ Sampling for(int i=0; i<SAMPLES; i++) { while(!(ADCSRA & 0x10)); // ждем пока АЦП полностью завершит преобразование ADCSRA = 0b11110101 ; // очищаем бит ADIF чтобы АЦП смог приступить к следующему преобразованию (0xf5) int value = ADC - 512 ; // считывваем информацию из АЦП и вычитаем постоянный сдвиг (512) vReal[i]= value/8; // Copy to bins after compressing vImag[i] = 0; } // -- Sampling // ++ FFT FFT.Windowing(vReal, SAMPLES, FFT_WIN_TYP_HAMMING, FFT_FORWARD); FFT.Compute(vReal, vImag, SAMPLES, FFT_FORWARD); FFT.ComplexToMagnitude(vReal, vImag, SAMPLES); // -- FFT // ++ re-arrange FFT result to match with no. of columns on display ( xres ) int step = (SAMPLES/2)/xres; int c=0; for(int i=0; i<(SAMPLES/2); i+=step) { data_avgs[c] = 0; for (int k=0 ; k< step ; k++) { data_avgs[c] = data_avgs[c] + vReal[i+k]; } data_avgs[c] = data_avgs[c]/step; c++; } // -- re-arrange FFT result to match with no. of columns on display ( xres ) // ++ send to display according measured value for(int i=0; i<xres; i++) { data_avgs[i] = constrain(data_avgs[i],0,80); // set max & min values for buckets data_avgs[i] = map(data_avgs[i], 0, 80, 0, yres); // remap averaged values to yres yvalue=data_avgs[i]; peaks[i] = peaks[i]-1; // decay by one light if (yvalue > peaks[i]) peaks[i] = yvalue ; yvalue = peaks[i]; displayvalue=MY_ARRAY[yvalue]; displaycolumn=31-i; mx.setColumn(displaycolumn, displayvalue); // for left to right } // -- send to display according measured value displayModeChange (); // проверяем нажата ли кнопка изменения режима отображения дисплея } void displayModeChange() { int reading = digitalRead(buttonPin); if (reading == HIGH && previousState == LOW && millis() - lastDebounceTime > debounceDelay) // works only when pressed { switch (displaymode) { case 1: // переключаемся из режима 1 в режим 2 displaymode = 2; for (int i=0 ; i<=8 ; i++ ) { MY_ARRAY[i]=MY_MODE_2[i]; } break; case 2: // переключаемся из режима 2 в режим 3 displaymode = 3; for (int i=0 ; i<=8 ; i++ ) { MY_ARRAY[i]=MY_MODE_3[i]; } break; case 3: // переключаемся из режима 3 в режим 4 displaymode = 4; for (int i=0 ; i<=8 ; i++ ) { MY_ARRAY[i]=MY_MODE_4[i]; } break; case 4: // переключаемся из режима 4 в режим 5 displaymode = 5; for (int i=0 ; i<=8 ; i++ ) { MY_ARRAY[i]=MY_MODE_5[i]; } break; case 5: // переключаемся из режима 5 в режим 1 displaymode = 1; for (int i=0 ; i<=8 ; i++ ) { MY_ARRAY[i]=MY_MODE_1[i]; } break; } lastDebounceTime = millis(); } previousState = reading; } |
Не лучше ли запитывать светодиодную матрицу напрямую от 5 вольтового питания, а не от 5 Вт выхода ардуины?
Ну если у вас есть такой отдельный источник питания то конечно это будет удобнее
Подключение этого визуализатора не повлияет на качество звука в динамиках?
Не должен если правильно подключите, он не должен делать короткое замыкание на аудиовыходе