[RISOLTO] MAX4466, MAX9814 o altro

Buonasera,
premesso che non ho alcuna competenza "audio", vorrei sapere se questi microfoni amplificati riescono a rilevare il "suono" in una stanza, quindi da una certa distanza.
Naturalmente non mi interessa il suono in se, ma solo la variazione del valore sul pin analogico.

Inoltre,
sto cercando di documentarmi su segnale analogico, calcolo della frequenza, FFT, etc, ma trovo articoli troppo semplificativi (di dubbia utilità) o troppo complessi; sapete consigliarmi qualcosa fatto bene per principianti.

TIA
Federico

Più esperti di me ti risponderanno.
Volevo solo segnalarti il sito di Adafruit. Sono attendibili e hanno ottimi tutorial/learn (in inglese però)
esempio Electret Microphone Amplifier - MAX9814 with Auto Gain Control : ID 1713 : $7.95 : Adafruit Industries, Unique & fun DIY electronics and kits

nid69ita:
Volevo solo segnalarti il sito di Adafruit.

Si, di solito parto da li, ma in questo caso li ho trovati troppo sintetici, o forse è solo un problema mio, visto che non conosco proprio le basi!

Grazie
Federico

Il MAX4466non lo conosco, ma il MAX9814 funziona molto bene

brunello22:
Il MAX4466non lo conosco, ma il MAX9814 funziona molto bene

Grazie, farò qualche prova con quello

Federico

Il 4466 è un amplificatore operazionale rail to rail alimentato a 5V specificamente pensato per il rilevamento di un capsula microfonica. Il 9814 ha più il compressore, cioè il fattore di amplificazione varia.

Il problema semmai è la capsula microfonica abbinata a questi amplificatori, vedo che le breakout usano tutte un microfono a condensatore e sembra omnidirezionale, cioè capta da tutte le direzioni.

Comunque entrambe i chip sono adatti per essere collegati ad altri tipi di microfoni, quindi eventualmente puoi smontare la capsula e saldarci altro.

Per fourier e compagnia bella la cosa è di per se complessa almeno per me, io finora non ho trovato risorse semplici.
Di semplice posso solo dire che il segnale periodico (e quindi una funzione matematica) è scomponibile in armoniche da cui partendo dalla fondamentale es 1000Hz la seconda vale 2000Hz la terza vale 3000 ecc, quindi abbiamo armoniche pari(2, 4, 6 ecc) e dispari. Ogni componente (armonica) avrà la sua intensità, ad esempio un suono reale è sempre composto da più armoniche, un tono puro a 1000Hz è una sinusoide perfetta che non presenta armoniche e mi risulta non possa essere riprodotto (dicono che il diapason produce un tono puro??).

https://www.phys.uniroma1.it/DipWeb/museo/acu003.htm

http://www.elemania.altervista.org/filtri/fourier/fourie8.html

http://pcfarina.eng.unipr.it/dispense00/lodigiani124188/lodigiani124188.htm

PS: se trovi qualche risorsa facile postala, la cosa complicata è ricavare l'analisi armonica da un flusso di dati digitali.

Ciao.

In che senso non può essere riprodotto?...
Il diapason emette un tono puro, sinusoidale, si. Un risuonatore meccanico ad alto "Q" emette un tono puro.

Per Fourier non dovrebbe essere difficile, sapendolo fare. Con Arduino uno, però, credo che si possa arrivare a filtrare i segnali dell'EEG...
Cerca Arduino fft. Ad esempio:
Norwegian creations

Grazie a tutti, purtroppo gli studi di fisica sono molto lontani, ma la curiosità è forte :smiley:

Appena riesco (se riesco) a capire meglio l'argomento, vi aggiorno.

Federico

Grazie. Incuriosisce anche me. Se condividi le tue esperienze mi fa piacere.

Eccomi di nuovo qua, stamattina avevo un po' di tempo, quindi ho cercato materiale didattico, essendo proprio a digiuno sono partito dalle basi.

Questo video, devo dire in maniera molto semplice, introduce lo spettro di frequenza e l'uso della Trasformata di Fourier (Fast), e quindi il campionamento. Per quanto riguarda l'applicazione Arduino, l'unica cosa utile è la libreria utilizzata per i calcoli FFT, che poi ho scoperto essere quella maggiormente utilizzata (arduinoFFT).

Altro link utile in merito alla FFT è quello di Adafruit, che poi rimanda ad un articolo di approfondimento.

Visto che però a me in fondo interessava capire come trasformare il segnale analogico del microfono in qualcosa di utilizzabile da Arduino, ho mirato le ricerche alla libreria arduinoFFT e al suono, e questo mi ha portato a questo video (in russo!) che usa proprio il MAX9814, e ad un altro articolo (tradotto dal russo) sulla trasformata molto semplice ed esplicativo.

Ho seguito il video, quindi collegamenti e programma, e sono riuscito ad ottenere lo stesso risultato, cioè il picco di frequenza campionato da Arduino attraverso il MAX9814 è simile a quello prodotto dallo smartphone!
(Metto programma in altro post)

MAX9814_FFT.png

Questo NON significa che Arduino sia adatto allo scopo vista la poca memoria e la bassa frequenza di campionamento, sarebbe meglio utilizzare altro.

In rete c'è molto materiale, anche in questo forum, ma solitamente si danno per scontate molte nozioni. Per quanto mi riguarda, e per lo scopo della mia ricerca (molto pratico), sono stati molto utili i link qui sopra e quelli forniti da @Maurotec e @Datman.

Grazie a tutti
Federico

PS
.. e pensare che volevo solo inserire un microfono nel mio WordClock per giocare con i led! :wink:

MAX9814_FFT.png

Di seguito il programma che ho utilizzato.
In pratica è l'esempio 3 della libreria, con qualche modifica per raggiungere lo scopo.

#include "arduinoFFT.h"

//Data pin analogico
#define PIN_DATA A0

//Numero di campioni, deve essere sempre una potenza di 2
#define SAMPLES 128

//Frequenza di campionamento in Hz, deve essere inferiore a 10000Hz (limite Arduino ADC 10kHz) 
#define SAMPLING_FREQUENCY 5000.0

//Periodo di campionamento
unsigned int sampling_period_us;
unsigned long microseconds;

arduinoFFT FFT = arduinoFFT();

//Input: campioni letti -> Output: spettro delle frequenze
double vReal[SAMPLES];
//Vettore di appoggio per i calcoli
double vImag[SAMPLES];

#define SCL_INDEX 0x00
#define SCL_TIME 0x01
#define SCL_FREQUENCY 0x02
#define SCL_PLOT 0x03

void setup() {
  //Calcolo del periodo di campionamento
  sampling_period_us = round(1000000 * (1.0 / SAMPLING_FREQUENCY));
  Serial.begin(9600);
  Serial.println("Ready");
}

void loop() {
  //Lettura dei campioni
  microseconds = micros();
  for (int i = 0; i < (int)SAMPLES; i++) {
    vReal[i] = analogRead(PIN_DATA);
    vImag[i] = 0;
    while (micros() - microseconds < sampling_period_us) {};
    microseconds += sampling_period_us;
  }
  //Risultati
  //  Serial.println("Data:");
  //  PrintVector(vReal, SAMPLES, SCL_TIME);
  FFT.Windowing(vReal, SAMPLES, FFT_WIN_TYP_HAMMING, FFT_FORWARD); /* Weigh data */
  //  Serial.println("Weighed data:");
  //  PrintVector(vReal, SAMPLES, SCL_TIME);
  FFT.Compute(vReal, vImag, SAMPLES, FFT_FORWARD); /* Compute FFT */
  //  Serial.println("Computed Real values:");
  //  PrintVector(vReal, SAMPLES, SCL_INDEX);
  //  Serial.println("Computed Imaginary values:");
  //  PrintVector(vImag, SAMPLES, SCL_INDEX);
  FFT.ComplexToMagnitude(vReal, vImag, SAMPLES); /* Compute magnitudes */
  Serial.println("Computed magnitudes (frequenza/ampiezza):");
  PrintVector(vReal, (SAMPLES >> 1), SCL_FREQUENCY);
  double peak = FFT.MajorPeak(vReal, SAMPLES, SAMPLING_FREQUENCY);
  Serial.print("MajorPeak: ");
  Serial.println(peak, 1); //Print out what frequency is the most dominant.
  //while(1); /* Run Once */
  delay(1000); /* Repeat after delay */
}

void PrintVector(double *vData, uint16_t bufferSize, uint8_t scaleType) {
  for (uint16_t i = 0; i < bufferSize; i++) {
    double abscissa;
    /* Print abscissa value */
    switch (scaleType) {
      case SCL_INDEX:
        abscissa = (i * 1.0);
        break;
      case SCL_TIME:
        abscissa = ((i * 1.0) / SAMPLING_FREQUENCY);
        break;
      case SCL_FREQUENCY:
        abscissa = ((i * 1.0 * SAMPLING_FREQUENCY) / SAMPLES);
        break;
    }
    Serial.print(abscissa, 1);
    if (scaleType == SCL_FREQUENCY)
      Serial.print("Hz");
    Serial.print(" ");
    Serial.println(vData[i], 4);
  }
  Serial.println();
}

MAX9814.png

Federico

MAX9814.png

Ho fatto qualche test con una matrice 8x8, ma non è proprio banale!
Naturalmente i dati delle ampiezze vanno "compressi" e mappati, e ho dovuto escludere le bassissime frequenze, perchè valori sono sempre fuori scala!!!

Nel fine settimana, spero di riuscire a provare con una matrice 16x16 :wink:

Comunque, il MAX9814 mi sembra che faccia il suo dovere :slight_smile:

Questo il video di prova

Federico

Entrambi gli assi devono essere logaritmici: l'asse verticale in dB, ad es. 3dB o 1dB, e quello orizzontale in ottave o terzi d'ottava

Datman:
Entrambi gli assi devono essere logaritmici: l'asse verticale in dB, ad es. 3dB o 1dB, e quello orizzontale in ottave o terzi d'ottava

Ok, verifico

Grazie
Federico

Certo, con un convertitore a 10bit hai 60dB di dinamica, contro i 96dB dei classici 16 bit. Comunque, per un analizzatore di spettro è più che sufficiente. Il segnale audio deve avere una componente continua pari a metà della tensione di riferimento del convertitore, che potrà essere 1V per segnali di linea consumer da 300mV efficaci massimi.

Aggiungo anche questo documento Understanding FFTs and Windowing e per un dettaglio sulle varie Funzioni finestra, wikipedia :slight_smile:

Federico

Nuovo video e codice utilizzato, che non è tutta farina del mio sacco, ma l’adattamento di quello che mi sembrava rispondesse meglio tra quelli trovati in rete, ma che non usava arduinoFFT.

#include "arduinoFFT.h"
#include <Max7219_Matrix.h>
//#include <Max7219_Matrix_CharSet.h>

#define PIN_DATA A2

//Numero di campioni, deve essere sempre una potenza di 2
#define SAMPLES 64

//Frequenza di campionamento in Hz, deve essere inferiore a 10000Hz (limite Arduino ADC 10kHz)
#define SAMPLING_FREQUENCY 6000.0

// Colonne sul display (<= SAMPLES/2)
#define LED_COLS    8
// Colonne sul display (<= SAMPLES/2)
#define LED_ROWS    8

//Max7219
#define MAX_NUM 1   // Numero di moduli MAX7219
#define MAX_DIN 11  // o MOSI  DIn del modulo con MAX7219
#define MAX_CLK 13  // o SCK   Clk del modulo con MAX7219
#define MAX_CS  10  // o SS    CS del modulo con MAX7219

uint8_t LED_PATTERN[] = {
  B00000000,  //  0
  B10000000,  //128
  B11000000,  //192
  B11100000,  //224
  B11110000,  //240
  B11111000,  //248
  B11111100,  //252
  B11111110,  //254
  B11111111   //255
};

//Input: Array campioni letti
//Output: Array spettro delle frequenze
double data_real[SAMPLES];
//Array di appoggio per i calcoli
double data_img[SAMPLES];
//Array dei valori medi
double data_avgs[LED_COLS];
//Array dei valori di picco
int8_t data_peak[LED_COLS];
//Periodo di campionamento
uint16_t sampling_period;

Max7219_Matrix m(MAX_CS, MAX_NUM);
arduinoFFT FFT = arduinoFFT(data_real, data_img, SAMPLES, SAMPLING_FREQUENCY);

void setup() {
  m.init();
  m.setIntensity(15);
  m.clear();

  analogReference(EXTERNAL);

  // Calcolo del periodo di campionamento
  sampling_period = round(1000000 * (1.0 / SAMPLING_FREQUENCY));

  delay(50);
}

void loop() {
  // Lettura dei campioni
  uint64_t ms = micros();
  for (uint8_t i = 0; i < SAMPLES; i++) {
    data_real[i] = (analogRead(PIN_DATA) - 512) / 8;
    data_img[i] = 0;
    while (micros() - ms < sampling_period) {};
    ms += sampling_period;
  }

  // FFT
  FFT.Windowing(FFT_WIN_TYP_HAMMING, FFT_FORWARD);
  FFT.Compute(FFT_FORWARD);
  FFT.ComplexToMagnitude();
  data_real[0] = data_real[1] = data_real[2];

  // Riorganizza i dati sulla base delle colonne da visualizzare
  // facendo la media delle ampiezze contigue
  uint8_t step = (SAMPLES / 2) / LED_COLS;
  uint8_t c = 0;
  for (uint8_t i = 0; i < (SAMPLES / 2); i += step) {
    data_avgs[c] = 0;
    for (uint8_t k = 0 ; k < step ; k++) {
      data_avgs[c] = data_avgs[c] + data_real[i + k];
    }
    data_avgs[c] = data_avgs[c] / step;
    c++;
  }

  // Visualizza i dati misurati
  for (uint8_t col = 0; col < LED_COLS; col++) {
    //data_avgs[col] = data_avgs[col] * (col + 1);              // suppress low freq
    //data_avgs[col] = (10) * log(data_avgs[col] + 1);          // logarithm
    data_avgs[col] = constrain(data_avgs[col], 0, 80);        // set max & min values for buckets
    data_avgs[col] = map(data_avgs[col], 0, 80, 0, LED_ROWS); // remap averaged values to LED_ROWS
    uint8_t value = (uint8_t)data_avgs[col];

    data_peak[col] = data_peak[col] - 1;                       // decay by one light
    if (value > data_peak[col]) {
      data_peak[col] = value ;
    }
    value = data_peak[col];

    uint8_t displayvalue = LED_PATTERN[value];
    uint8_t displaycolumn = LED_COLS - 1 - col;
    m.setColumn(displaycolumn, displayvalue);
  }
}

Federico

Interessante! Karma+