Спектроанализатор

Начну без лишних слов. Все знают что такое спектроанализатор. Простейший 64-х полосный можно сделать платформе Arduino + GLCD. Звук будет сниматься с аналогово порта, раскладываться на частоты и выводиться на экран. Чтобы разложить сигнал на частоты, нужно использовать быстрое преобразование Фурье. Я нашел готовую библиотеку FFT.

Позже я совершенно случайно наткнулся на похожий проект, отличием которого был вывод картинки на экран телевизора; я лишь изменил его скетч для  вывода на GLCD. Код:

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
#include <glcd.h>
#include <fix_fft.h>
char im[128], data[128], lastpass[64];
char x=32, ylim=64;
int i=0,val;
 
void setup() {                                          
GLCD.Init();
GLCD.ClearScreen();
for (int z=0; z<64; z++) {lastpass[z]=80;}
}
void loop() {
 
for (i=0; i < 128; i++){                                    
  val = analogRead(0);                                      
  data[i] = val -128;                                     
  im[i] = 0;                                                
  }
 
fix_fft(data,im,7,0);
 
for (i=1; i< 64;i++) {
 
  data[i] = sqrt(data[i] * data[i] + im[i] * im[i]);  
  GLCD.DrawLine(i+x,lastpass[i],i+x,ylim,WHITE);         
  GLCD.DrawLine(i+x,ylim,i+x,ylim-data[i],BLACK);        
  lastpass[i]=ylim-data[i];
 
  }
}

Для проверки можно подключить микрофон через усилитель к аналоговому входу A0.

Ну и конечно видео:

В конце видео я замостил спектр, так как шире его не сделаешь. Библиотека FFT разбивает аудио-диапазон на 64 полосы. А дисплей  — 128х64. Если сделать два аудио канала, то Arduino — будет жутко тормозить. Еще один вариант — сделать спектральные полосы более толстыми.

Код концовки видео:

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
#include <glcd.h>
#include <fix_fft.h>
char im[128], data[128], lastpass[64];
char ylim=64;
int i=0,val;
 
void setup() {                                          
GLCD.Init();
GLCD.ClearScreen();
for (int z=0; z<64; z++) {lastpass[z]=80;}
}
void loop() {
 
for (i=0; i < 128; i++){                                    
  val = analogRead(0);                                      
  data[i] = val -128;                                     
  im[i] = 0;                                                
  }
 
fix_fft(data,im,7,0);
 
for (i=1; i< 64;i++) {
 
  data[i] = sqrt(data[i] * data[i] + im[i] * im[i]);  
  GLCD.DrawLine(i,lastpass[i],i,ylim,WHITE);         
  GLCD.DrawLine(i,ylim,i,ylim-data[i],BLACK); 
  GLCD.DrawLine(i+64,lastpass[i],i+64,ylim,WHITE);         
  GLCD.DrawLine(i+64,ylim,i+64,ylim-data[i],BLACK);    
  lastpass[i]=ylim-data[i];
 
  }
}

Файлы проекта:

Вы можите оставить комментарий, или поставить трэкбек со своего сайта.

25 комментариев к “Спектроанализатор”

  1. armanlight:

    здравствуйте у меня вопрос а можно ли сделать вывод на светодиодную матрицу например 32 частотных канала (от 20 до 20000гц) и столбики высотой по 20 светодиодов понятно что надо будет использовать что-то типа 74HC595 просто я немогу разобраться как правильно это организовать мой маил armanlight@mail.ru

    • Вот ссылка. Здесь подключают к матрице 14х9(технология вывода изображения Charliplexing). Если понять принцип, то можно и на матрице 32х20. Насчет сдвиговых регистров — я ни разу с ними не работал. Но есть хорошая статья о этом. 🙂 Выбирайте.

  2. Artem:

    Добрый день! Хотел данный проект переделать под дисплей Nokia 5110. Размер дисплея 84*48. Можете написать комментарии к этим строкам

    char im[128], data[128], lastpass[64];
    char ylim=64;
    int i=0,val;

    Моя программа (укажите ошибки):

    #include
    #include
    #include
    char im[128], data[128], lastpass[64];
    char x=32, ylim=80;
    int i=0,val;

    // pin 3 — Serial clock out (SCLK)
    // pin 4 — Serial data out (DIN)
    // pin 5 — Data/Command select (D/C)
    // pin 7 — LCD chip select (CS)
    // pin 6 — LCD reset (RST)
    Adafruit_PCD8544 display = Adafruit_PCD8544(3, 4, 5, 7, 6);

    void setup() {
    Serial.begin(9600);

    // Инициализация дисплея
    display.begin();

    // Очищаем дисплей
    display.clearDisplay();
    display.display();
    // Устанавливаем контраст
    display.setContrast(40);
    delay(1000);

    for (int z=0; z<64; z++) {lastpass[z]=80;}
    }

    void loop()
    {
    for (i=0; i < 128; i++){
    val = analogRead(0);
    data[i] = val -128;
    im[i] = 0;
    }

    fix_fft(data,im,7,0);

    for (i=1; i< 64;i++)
    {

    data[i] = sqrt(data[i] * data[i] + im[i] * im[i]);
    display.drawLine(i+x,lastpass[i],i+x,ylim,WHITE);
    display.drawLine(i+x,ylim,i+x,ylim-data[i],BLACK);
    display.display();
    lastpass[i]=ylim-data[i];

    }

    }

  3. Artem:

    А у тебя случайно нет описания библиотеки ?

    • Конкретного описания нет. Знаю только, что в нее загружается сэмпл (несколько значений с ан.порта), а она возвращает разложенный на частоты сэмпл такого же размера.
      Официальное описание:

      1
      2
      3
      4
      5
      6
      7
      
      /*
        fix_fft() - perform forward/inverse fast Fourier transform.
        fr[n],fi[n] are real and imaginary arrays, both INPUT AND
        RESULT (in-place FFT), with 0 <= n < 2**m; set inverse to
        0 for forward transform (FFT), or 1 for iFFT.
      */
      int fix_fft(char fr[], char fi[], int m, int inverse);
  4. Artem:

    библиотеки fix_fft

  5. Шамиль:

    У меня вопрос: у меня вот такой дисплей(http://www.youtube.com/watch?v=H14JvfZSRAI) как его подсоединить(на нём 16 пинов)?

  6. KilLTHEBZzZ:

    Может кто нибудь помочь с кодом для rgb matrix (64×32) ? Я студент, многих тонкостей не знаю, так что не обессудьте.

    • А каким образом вы управляете этой матрицей?
      Явно есть какой-то драйвер, иначе у контроллера просто не хватит i/o, я думаю.

      • KilLTHEBZzZ:

        Подключаю к arduino mega 2560

        • Я так понимаю, вы используете матрицу со встроенным контроллером отсюда https://learn.adafruit.com/32×16-32×32-rgb-led-matrix?view=all.
          В там случае, если использовать библиотеку, которую предлагает разработчик, то нужно сделать примерно следующее:

          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
          
          #include <Adafruit_GFX.h>   
          #include <RGBmatrixPanel.h> 
          #include <fix_fft.h>
           
          char im[128], data[128];
          char ylim=32;
          int i=0,val;
           
          //Здесь указана схема подключения  
          #define OE   9
          #define LAT 10
          #define CLK 11
          #define A   A0
          #define B   A1
          #define C   A2
          #define D   A3
           
          //Создаем экземпляр матрицы + графический буфер 32x64 
          RGBmatrixPanel matrix(A, B, C, D, CLK, LAT, OE, true, 64);
           
          void setup() {                                          
          	matrix.begin();
           
          }
          void loop() {
          	//Заполнили буфер черным цветом
          	matrix.fillScreen(0);
          	for (i=0; i < 128; i++){                                    
          		val = analogRead(0);                                      
          		data[i] = val/2 -64;                                     
          		im[i] = 0;                                                
          	}
           
          	fix_fft(data,im,7,0);
           
           
          	for (i=1; i< 64;i++) {
           
          		data[i] = sqrt(data[i] * data[i] + im[i] * im[i]);  
          		//Рисуем столбик по оси X. Цвет столбика сделал зависимым от высоты
          		matrix.drawLine(i,ylim,i,ylim-data[i],matrix.Color333(data[i]/4, 4, 4));        
           
            }
            //Копируем буфер на матрицу
            matrix.swapBuffers(false);
          }
          • KilLTHEBZzZ:

            Большое Вам спасибо! Вы меня очень осчастливили! Всего вам самого хорошего!)

            • Надо же… заработало с первого раза 🙂
              Всегда пожалуйста.) И вам желаю удачи с проектом.

              • KilLTHEBZzZ:

                Спасибо, только еще один вопрос. Оно заработало, только не плавно,а рывками, так должно быть или нет? Просто я видел в других проектах, все происходит плавно, а у меня рывками. Сначала думал что проблема может быть с драйвером, но загрузив другой скетч «3д куб» все работало плавно. Не подскажите в чем может быть проблема?

              • KilLTHEBZzZ:

                Видимо экран просто не успевает обновляться достаточно быстро, есть функции
                void drawFastVLine(uint16_t x0, uint16_t y0, uint16_t length, uint16_t color);
                void drawFastHLine(uin86_t x0, uin86_t y0, uint8_t length, uint16_t color);
                но проблема в том что в ней 3 параметра, а в скетче который прислали вы 4
                matrix.drawLine(i,ylim,i,ylim-data[i],matrix.Color333(data[i]/3, 3, 0));
                Не могли бы вы еще немного помочь?

              • Всё достаточно просто.

                1
                2
                3
                
                 
                 
                drawFastVLine(i,0 , ylim-data[I],  matrix.Color333(data[i]/3, 3, 0));

                очень занят, извините, что не отвечал 🙂

  7. KilLTHEBZzZ:

    Не помогло, теперь матрица полностью залита цветом, а сами значения в виде черного цвета заливаются. Плохая в общем идея была с fastVLine… И все же не знаете какие еще могут быть причины не плавности ?

  8. Максим:

    Здравствуйте! Как изменить диапазон частот, которые раскладываются в спектр? Сейчас, насколько я понял, диапазон 0..500Гц, раскладывается на 64 гармоники, т.е. гармоники с шагом 500/64 = 7,8125Гц. Как изменить диапазон на 0..250Гц или на 0..1000Гц, где в библиотеке расчитывается или указывается диапазон частот?

Написать комментарий

XHTML: Вы можете использовать эти теги: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

Bug Report
Локализовано: шаблоны Wordpress