산업 제조
산업용 사물 인터넷 | 산업자재 | 장비 유지 보수 및 수리 | 산업 프로그래밍 |
home  MfgRobots >> 산업 제조 >  >> Manufacturing Technology >> 제조공정

아두이노 나노 33 BLE 사운드 스펙트럼 비주얼라이저: 실시간 오디오 디스플레이

부품 및 소모품

부품 수량 비고
아두이노 나노 33 BLE 1
일렉트렛 마이크 앰프 MAX9814 1
0.91인치 OLED I2C 디스플레이 128x32 픽셀 1
콘덴서 4.7nF 1 RC 로우패스 필터 및 차단 주파수에 따라 달라짐
콘덴서 470µF 1
저항 2kΩ 1 RC 로우패스 필터 및 차단 주파수에 따라 달라짐

앱 및 온라인 서비스

프로젝트 소개

소개

작은 OLED 디스플레이에서 막대 그래프가 음악과 소리에 반응하는 모습을 보세요. 최저 주파수는 그래프 왼쪽, 최고 주파수는 오른쪽에 표시됩니다.

구성

연결

저주파 노이즈가 문제인가요?

측정 시스템 근처에서 작동하는 모든 전자 기기에서 노이즈가 발생합니다. 모든 전자 기기는 고정 주파수와 전압의 교류(AC)로 작동하며, 국가에 따라 50Hz 또는 60Hz가 전력선 주파수입니다. 패러데이 케이지로 쉽게 제거 가능합니다. 회로를 상자에 넣고 상자를 그라운드에 연결하세요. 회로도 잘 접지하세요.

아두이노 나노 33 BLE 사운드 스펙트럼 비주얼라이저: 실시간 오디오 디스플레이

아두이노 나노 33 BLE 핀아웃

아두이노 나노 33 BLE 사운드 스펙트럼 비주얼라이저: 실시간 오디오 디스플레이

아두이노 코어 AnalogRead와 아두이노 나노 33 BLE로는 초당 약 35,000 샘플만 얻을 수 있어 FFT로 17.5kHz 이상 주파수 처리는 불가능합니다. 클럭 읽기와 비지 웨이트 루프 내 비교 연산 등을 고려해 안전하게 8kHz 상한으로 잡습니다. 이 이상 주파수를 차단하는 간단한 RC 로우패스 필터를 사용합니다.

아두이노 나노 33 BLE 사운드 스펙트럼 비주얼라이저: 실시간 오디오 디스플레이
아두이노 나노 33 BLE 사운드 스펙트럼 비주얼라이저: 실시간 오디오 디스플레이

R=180Ω, C=0.1µF → 차단 주파수 fc=8842Hz

본 프로젝트: 2kΩ 저항 + 4.7nF 콘덴서 → fc=17000Hz

아두이노 나노 33 BLE 사운드 스펙트럼 비주얼라이저: 실시간 오디오 디스플레이

최대 샘플링 레이트 대략 계산

일반 Arduino analogRead()는 오디오 샘플링에 너무 느립니다. 최대 샘플링 레이트를 계산해 봅시다.

아두이노 코어 AnalogRead와 아두이노 나노 33 BLE로 얼마나 많은 샘플을 얻을 수 있는지 추정합니다.

아래 작은 프로그램을 돌려 추정해 보세요.


/*
 * AnalogRead 최대 샘플링 레이트 대략 계산
 */
#define ANALOG_PIN A0
#define SAMPLES 1000000.0
int newTime;
int analogValue;
void setup() {
  Serial.begin(9600);
  Serial.println("Sampling... please, wait. ");
}
void loop() {
  newTime = micros();
  for (int i = 0; i < (int)SAMPLES; i++) {
    analogValue = analogRead(ANALOG_PIN);
  }
  float elapsedTimePerSampleUs = (micros() - newTime) / SAMPLES;
  Serial.print("Time per sample (us): ");
  Serial.println(elapsedTimePerSampleUs);
  Serial.print("Max sampling freq(hz): ");
  Serial.println(pow(10,6) / elapsedTimePerSampleUs);
}
아두이노 나노 33 BLE 사운드 스펙트럼 비주얼라이저: 실시간 오디오 디스플레이

아두이노 코어 AnalogRead와 아두이노 나노 33 BLE로 초당 약 35,000 샘플 획득 가능. 나이퀴스트 정리(2배 샘플링 필요)에 따라 17kHz 이상 주파수는 처리 불가. 로우패스 필터로 그 이상 차단.

클럭 읽기와 비지 웨이트 루프 비교 연산 등을 고려해 8kHz 상한으로 안전하게 설정.


// 샘플링
for (int i = 0; i < SAMPLES; i++) {
  unsigned long newTime = micros();
  int value = analogRead(ANALOG_PIN);
  vReal[i] = value;
  vImag[i] = 0;
  while (micros() < (newTime + sampling_period_us)) {
    yield();
  }
}

사용자 인터페이스

아두이노 나노 33 BLE 사운드 스펙트럼 비주얼라이저: 실시간 오디오 디스플레이

화면이 11개 주파수 존(Zone)으로 나뉘며, 인간의 청각 인식과 유사한 로그 스케일로 주파수를 그룹화합니다.

인간 가청 주파수는 약 20Hz~20kHz. (영아는 20kHz 이상도 들리지만 성인 평균은 15~17kHz가 상한.)

존 3~13 (11개 존)을 표현에 사용.

아두이노 나노 33 BLE 사운드 스펙트럼 비주얼라이저: 실시간 오디오 디스플레이

각 막대는 해당 대역의 최대값을 점선으로, 평균값을 채워진 직사각형으로 표시.

값은 휴리스틱하게 얻은 미리 선택된 레퍼런스를 기준으로 데시벨(dB) 단위로 표시.

작동 원리

오디오 샘플을 고속 푸리에 변환(FFT)으로 주파수 스펙트럼으로 변환.

스펙트럼을 14개 존으로 나누고 그룹화한 뒤 11개 존만 dB로 표현.

마이크 모듈 상세

아두이노 나노 33 BLE 사운드 스펙트럼 비주얼라이저: 실시간 오디오 디스플레이
아두이노 나노 33 BLE 사운드 스펙트럼 비주얼라이저: 실시간 오디오 디스플레이
아두이노 나노 33 BLE 사운드 스펙트럼 비주얼라이저: 실시간 오디오 디스플레이

일렉트렛 마이크

일렉트렛은 준영구적으로 대전된 유전체입니다. 세라믹 소재를 가열해 자기장에 놓고 냉각시키며 만듭니다. 영구 자석의 정전기 버전이라 할 수 있습니다. 일렉트렛 마이크에서 이 소재 조각을 커패시터 유전체 일부로 쓰고, 마이크 다이어프램이 한 쪽 극판 역할을 합니다. 음압이 다이어프램을 움직이면 음압에 비례해 정전용량 변함. 유전체에 내장된 고정 전하 때문에 커패시터 양단 전압도 변합니다. 이 일렉트렛 커패시터가 내장 FET 앰프 입력에 연결됩니다. 일렉트렛 마이크는 작고 감도 우수, 광대역 주파수 응답, 저가격 장점.

MAX9814 마이크 앰프

MAX9814는 자동 이득 제어(AGC), 저잡음 마이크 바이어스 갖춘 마이크 앰프. 브레이크아웃 보드로 몇 가지 설정 가능.

감도(Sensitivity)

감도는 아날로그 출력 전압이나 디지털 출력 값과 입력 음압 비율로, 마이크 핵심 스펙입니다. 음향 도메인 단위를 전기 도메인 단위로 매핑해 알려진 입력에 대한 출력 크기 결정.

마이크 감도는 표준 음향 입력(1kHz 사인파, 94dB SPL, 1Pa)에 대한 전기적 출력 반응. 감도 값이 높을수록 고정 음향 입력에 대한 출력이 큼. 데시벨(dB) 단위 감도는 보통 음수라 절대값이 작을수록 고감도.

아날로그 마이크 감도는 보통 dBV(1.0V rms 기준 데시벨) 단위.

레퍼런스 레벨과 주파수 응답

마이크 주파수 응답은 주파수 스펙트럼 전반에 걸친 출력 레벨. 상/하한 주파수는 1kHz 기준 출력보다 3dB 낮은 지점. 1kHz 레퍼런스 레벨은 관례상 0dB로 정규화.

0.91인치 OLED I2C 디스플레이 128x32 픽셀

대각선 약 1인치 작은 디스플레이. 128x32 개별 백색 OLED 픽셀, 컨트롤러 칩이 각 픽셀 온/오프 제어. 백라이트 불필요 → 전력 소모 감소.

여기 쓴 모델은 4핀만 있고 I2C 프로토콜로 아두이노와 통신. RESET 핀 없음. 아두이노 우노 I2C 핀에 연결:

OLED 제어용 adafruit_SSD1306.h, adafruit_GFX.h 라이브러리 필요. 설치 방법은 아래 참조.

아다프루트 라이브러리 사용. 아다프루트에서 뭐라도 사서 지원해 주세요.

아두이노 나노 33 BLE 사운드 스펙트럼 비주얼라이저: 실시간 오디오 디스플레이
아두이노 나노 33 BLE 사운드 스펙트럼 비주얼라이저: 실시간 오디오 디스플레이
아두이노 나노 33 BLE 사운드 스펙트럼 비주얼라이저: 실시간 오디오 디스플레이

다음 단계

아두이노 나노 33 BLE는 아날로그 읽기 성능을 더 끌어올릴 수 있습니다. 다음 버전에선 nRF52840에 최적화된 FFT와 아날로그 입력을 사용할 예정입니다.

코드

아두이노 나노 33 BLE용 사운드 스펙트럼 비주얼라이저 (Arduino)

arduinoFFT 사용: https://github.com/kosme/arduinoFFT

Adafruit_GFX 사용: https://github.com/adafruit/Adafruit-GFX-Library

Adafruit_SSD1306 사용: https://github.com/adafruit/Adafruit_SSD1306

/* Sound Spectrum Visualizer for Arduino Nano 33 BLE
 * Arduino based sound visualizer
 * @author Enrique Albertos
 * Hardware requirements:
 * - Arduino or Arduino-compatible boards.
 * - ssd1306 oled I2C 128x32 display
 * - Electret Microphone Amplifier with max9814
 * - Optional: battery for portable use (else power through USB)
 * Software requirements:
 * - arduinoFFT https://github.com/kosme/arduinoFFT
 * - Adafruit_GFX https://github.com/adafruit/Adafruit-GFX-Library
 * - Adafruit_SSD1306 https://github.com/adafruit/Adafruit_SSD1306
 * Connections:
 * - Mic GAIN: * VCC to mic GAIN for 40dB * GND to mic GAIN for 50dB * floating mic GAIN for 60dB
 * - Analog pin 0 to mic amp output
 * - +3.3V, GND, SDA (or analog 4) and SCL (analog 5) to I2C SSD1306
 * @uses arduinoFFT https://github.com/kosme/arduinoFFT
 * @uses Adafruit_GFX https://github.com/adafruit/Adafruit-GFX-Library
 * @uses Adafruit_SSD1306 https://github.com/adafruit/Adafruit_SSD1306
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 */
#include "arduinoFFT.h"
#include 
#include 

#define SAMPLES 1024              // 2의 거듭제곱
#define SAMPLING_FREQ 24000       // 12kHz Fmax = sampleF/2
#define AMPLITUDE 100             // 감도
#define FREQUENCY_BANDS 14
#define SCREEN_WIDTH 128          // OLED 디스플레이 너비 (픽셀)
#define SCREEN_HEIGHT 32          // OLED 디스플레이 높이 (픽셀)
#define BARWIDTH 11
#define BARS 11
#define ANALOG_PIN A0

// I2C(SDA, SCL)로 연결된 SSD1306 디스플레이 선언
#define OLED_RESET -1             // 리셋 핀 번호 (아두이노 리셋 핀 공유 시 -1)
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);

double vImag[SAMPLES];
double vReal[SAMPLES];
unsigned long sampling_period_us;
arduinoFFT fft = arduinoFFT(vReal, vImag, SAMPLES, SAMPLING_FREQ);

// 배경 노이즈 제거용 레퍼런스 (휴리스틱하게 결정)
float reference = log10(50.0);
double coutoffFrequencies[FREQUENCY_BANDS];

void setup() {
  // SSD1306_SWITCHCAPVCC = 3.3V 내부에서 디스플레이 전압 생성
  if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) { // 128x32 주소 0x3C
    for (;;); // 진행 안 함, 무한 루프
  }
  // 디스플레이 설정
  display.clearDisplay();
  display.display();
  display.setRotation(0);
  display.invertDisplay(false);
  sampling_period_us = (1.0 / SAMPLING_FREQ) * pow(10.0, 6);

  // 차단 주파수 계산, 로그 스케일 베이스 basePot
  double basePot = pow(SAMPLING_FREQ / 2.0, 1.0 / FREQUENCY_BANDS);
  coutoffFrequencies[0] = basePot;
  for (int i = 1; i < FREQUENCY_BANDS; i++) {
    coutoffFrequencies[i] = basePot * coutoffFrequencies[i - 1];
  }

  // 주파수 대역 구분용 점선 그리기
  for (int i = 0; i < BARS - 1; i++) {
    for (int j = 0; j < SCREEN_HEIGHT; j += 4) {
      display.writePixel((i + 1) * BARWIDTH + 2, j, SSD1306_WHITE);
    }
  }
  display.drawRect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, SSD1306_WHITE);
}

int oldHeight[20];
int oldMax[20];
double maxInFreq;

void loop() {
  // 샘플링
  for (int i = 0; i < SAMPLES; i++) {
    unsigned long newTime = micros();
    int value = analogRead(ANALOG_PIN);
    vReal[i] = value;
    vImag[i] = 0;
    while (micros() < (newTime + sampling_period_us)) {
      yield();
    }
  }

  // FFT 계산
  fft.DCRemoval();
  fft.Windowing(FFT_WIN_TYP_HAMMING, FFT_FORWARD);
  fft.Compute(FFT_FORWARD);
  fft.ComplexToMagnitude();

  double median[20];
  double max[20];
  int index = 0;
  double hzPerSample = (1.0 * SAMPLING_FREQ) / SAMPLES;
  double hz = 0;
  double maxinband = 0;
  double sum = 0;
  int count = 0;

  for (int i = 2; i < (SAMPLES / 2); i++) {
    count++;
    sum += vReal[i];
    if (vReal[i] > max[index]) {
      max[index] = vReal[i];
    }
    if (hz > coutoffFrequencies[index]) {
      median[index] = sum / count;
      sum = 0.0;
      count = 0;
      index++;
      max[index] = 0;
      median[index] = 0;
    }
    hz += hzPerSample;
  }

  // 대역별 중앙값과 최대값 계산
  if (sum > 0.0) {
    median[index] = sum / count;
    if (median[index] > maxinband) {
      maxinband = median[index];
    }
  }

  int bar = 0;
  for (int i = FREQUENCY_BANDS - 1; i >= 3; i--) {
    int newHeight = 0;
    int newMax = 0;

    // 실제 데시벨 계산
    if (median[i] > 0 && max[i] > 0) {
      newHeight = 20.0 * (log10(median[i]) - reference);
      newMax = 20.0 * (log10(max[i]) - reference);
    }

    // 최소/최대 레벨 보정
    if (newHeight < 0 || newMax < 0) {
      newHeight = 1;
      newMax = 1;
    }
    if (newHeight >= SCREEN_HEIGHT - 2) {
      newHeight = SCREEN_HEIGHT - 3;
    }
    if (newMax >= SCREEN_HEIGHT - 2) {
      newMax = SCREEN_HEIGHT - 3;
    }

    int barX = bar * BARWIDTH + 5;

    // 이전 중앙값 레벨 지우기
    if (oldHeight[i] > newHeight) {
      display.fillRect(barX, newHeight + 1, 7, oldHeight[i], SSD1306_BLACK);
    }
    // 이전 최대값 레벨 지우기
    if (oldMax[i] > newHeight) {
      for (int j = oldMax[i]; j > newHeight; j -= 2) {
        display.drawFastHLine(barX, j, 7, SSD1306_BLACK);
      }
    }
    // 새 최대값 레벨 그리기 (점선)
    for (int j = newMax; j > newHeight; j -= 2) {
      display.drawFastHLine(barX, j, 7, SSD1306_WHITE);
    }
    // 새 중앙값 레벨 그리기 (채워진 막대)
    display.fillRect(barX, 1, 7, newHeight, SSD1306_WHITE);

    oldMax[i] = newMax;
    oldHeight[i] = newHeight;
    bar++;
  }
  display.drawFastHLine(0, SCREEN_HEIGHT - 1, SCREEN_WIDTH, SSD1306_WHITE);
  display.display();
}

회로도

soundspectrumvisualizer_qLzRsVPVlc.fzz

아두이노 나노 33 BLE 사운드 스펙트럼 비주얼라이저: 실시간 오디오 디스플레이

제조공정

  1. 아두이노 우노와 OLED 디스플레이로 클래식 퐁(Pong) 게임 만들기: 단계별 튜토리얼
  2. K30 CO2 센서: 실시간 실내 공기질 모니터링
  3. 1Sheeld와 아두이노로 시각/청각 장애인 간 소통 돕기
  4. 스마트 저금통 만들기: 아두이노 나노로 동전 인식기 제어하기
  5. 아두이노 블루투스로 LED 제어하기 - HC-05 & MIT App Inventor 입문 가이드
  6. 아두이노 나노와 조이스틱으로 2개 스테퍼 모터 제어하기 – 비주이노(Visuino) 튜토리얼
  7. 아두이노 나노 33 BLE 센스로 오디오 데이터 전송하기
  8. 아두이노 나노로 만드는 휴대용 가이거 계수기
  9. 아두이노 우노와 이더넷 실드로 정확한 태양광 복사량 측정하기
  10. 아두이노 나노 기반 식사 로봇 만들기: 단계별 가이드