Wron readings using max9814

Hello everyone, I am using esp32 wroom 32D and max9814 the wiring is as follows
ESP32 3.3v --> Breadboard positive rail
Esp32 GND --> Breadboard negative rail
ESP32 D35 --> MAX9814 OUT
MAX9814 VDD --> Breadboard positive rail
MAX9814 GND -> Breadboard negative rail

The issue is that i have wrong reading using the following code:

#include <WiFi.h>
#include <ESPAsyncWebServer.h>
#include <ArduinoJson.h>
#include <arduinoFFT.h>

// Wi-Fi credentials
const char* ssid = "Monitor Sound";
const char* password = "12345678";

AsyncWebServer server(80);
AsyncWebSocket ws("/ws");

// Sampling and FFT configuration
const int sampleRate = 512;             // Number of samples
const double samplingFrequency = 20000; // Sampling frequency (20 kHz)
unsigned long samplingInterval;         // Microseconds per sample
double vReal[sampleRate];
double vImag[sampleRate];
ArduinoFFT FFT = ArduinoFFT(vReal, vImag, sampleRate, samplingFrequency);

// Microphone calibration (example values)
const double micSensitivity = -42;       // Sensitivity in V/Pa
const double referencePressure = 20e-6;  // Reference pressure in Pascals

// HTML page for WebSocket visualization
String htmlPage = R"rawliteral(
<!DOCTYPE html>
<html>
<head>
    <title>Sound Amplitude Graph</title>
    <script>
        let socket;
        let amplitude = 0, spl = 0, rt60 = 0, frequency = 0;

        function initWebSocket() {
            socket = new WebSocket(ws://${location.hostname}/ws);
            socket.onmessage = function (event) {
                const data = JSON.parse(event.data);
                amplitude = data.amplitude;
                spl = data.spl;
                rt60 = data.rt60;
                frequency = data.frequency;

                document.getElementById("amplitude").innerText = amplitude.toFixed(2);
                document.getElementById("spl").innerText = spl.toFixed(2);
                document.getElementById("rt60").innerText = rt60.toFixed(2);
                document.getElementById("frequency").innerText = frequency.toFixed(2);

                updateGraph(amplitude);
            };
        }

        let graphData = [];
        function updateGraph(newValue) {
            const canvas = document.getElementById("graph");
            const ctx = canvas.getContext("2d");

            const maxAmplitude = 50000; // Adjust this based on expected input
            const normalizedValue = Math.min(canvas.height, canvas.height * (newValue / maxAmplitude));

            graphData.push(normalizedValue);
            if (graphData.length > canvas.width) {
                graphData.shift();
            }

            ctx.clearRect(0, 0, canvas.width, canvas.height);
            ctx.beginPath();
            ctx.moveTo(0, canvas.height - graphData[0]);
            graphData.forEach((val, index) => {
                ctx.lineTo(index, canvas.height - val);
            });
            ctx.stroke();
        }

        window.onload = function () {
            initWebSocket();
        };
    </script>
</head>
<body>
    <h1>Sound Amplitude Graph</h1>
    <p>Amplitude: <span id="amplitude">0</span></p>
    <p>SPL: <span id="spl">0</span> dB</p>
    <p>RT60: <span id="rt60">0</span> seconds</p>
    <p>Frequency: <span id="frequency">0</span> Hz</p>
    <canvas id="graph" width="500" height="300" style="border: 1px solid black;"></canvas>
</body>
</html>
)rawliteral";

void processFFT() {
    unsigned long currentTime = micros(); // Start timing for sampling
    samplingInterval = 1e6 / samplingFrequency; // Calculate interval (microseconds per sample)

    // Read analog samples precisely
    for (int i = 0; i < sampleRate; i++) {
        vReal[i] = analogRead(35);  // Read analog input
        vImag[i] = 0;

        while (micros() - currentTime < samplingInterval) {
            // Wait for the correct sampling interval
        }
        currentTime += samplingInterval;
    }

    // Apply FFT
    FFT.windowing(FFT_WIN_TYP_HAMMING, FFT_FORWARD);
    FFT.compute(FFT_FORWARD);
    FFT.complexToMagnitude();

    // Find the dominant frequency bin
    double maxAmplitude = 0;
    int maxIndex = 0;
    for (int i = 2; i < sampleRate / 2; i++) { // Ignore DC and low frequencies
        if (vReal[i] > maxAmplitude) {
            maxAmplitude = vReal[i];
            maxIndex = i;
        }
    }

    // Refine frequency estimation
    double leftBin = vReal[maxIndex - 1];
    double centerBin = vReal[maxIndex];
    double rightBin = vReal[maxIndex + 1];

    double interpolation = (rightBin - leftBin) / (2 * (2 * centerBin - leftBin - rightBin));
    double refinedIndex = maxIndex + interpolation;
    double dominantFrequency = (refinedIndex * samplingFrequency) / sampleRate;

    // Convert ADC value to voltage
    double amplitudeVoltage = maxAmplitude * (3.3 / 4095.0);  // Convert ADC value to voltage (12-bit ADC)

    // Convert the microphone's sensitivity from dBV/Pa to linear scale (V/Pa)
    double sensitivityLinear = pow(10, -42 / 20.0);  // Sensitivity in V/Pa for -42 dBV/Pa

    // Compute sound pressure (Pa) from voltage using microphone sensitivity
    double soundPressure = amplitudeVoltage / sensitivityLinear;

    // Reference sound pressure is 20 μPa (0.00002 Pa)
    double referencePressure = 20e-6;

    // SPL Calculation
    double spl = 20 * log10(soundPressure / referencePressure);  // Calculate SPL in dB

    // Debugging data for Serial Monitor
    Serial.print("Frequency: ");
    Serial.print(dominantFrequency, 2);
    Serial.print(" Hz, SPL: ");
    Serial.print(spl, 2);
    Serial.print(" dB, Amplitude: ");
    Serial.println(maxAmplitude);

    // Send data via WebSocket
    StaticJsonDocument<200> jsonDoc;
    jsonDoc["amplitude"] = maxAmplitude;
    jsonDoc["spl"] = spl;
    jsonDoc["frequency"] = dominantFrequency;

    String jsonString;
    serializeJson(jsonDoc, jsonString);
    ws.textAll(jsonString);
}

void onWebSocketEvent(AsyncWebSocket *server, AsyncWebSocketClient *client, 
                      AwsEventType type, void *arg, uint8_t *data, size_t len) {
    if (type == WS_EVT_CONNECT) {
        Serial.printf("Client connected: %u\n", client->id());
    } else if (type == WS_EVT_DISCONNECT) {
        Serial.printf("Client disconnected: %u\n", client->id());
    }
}

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

    // Start Wi-Fi Access Point
    WiFi.softAP(ssid, password);
    IPAddress IP = WiFi.softAPIP();
    Serial.print("Access Point started. IP address: ");
    Serial.println(IP);

    ws.onEvent(onWebSocketEvent);
    server.addHandler(&ws);

    server.on("/", HTTP_GET, [](AsyncWebServerRequest *request) {
        request->send_P(200, "text/html", htmlPage.c_str());
    });

    server.on("/favicon.ico", HTTP_GET, [](AsyncWebServerRequest *request) {
        request->send(404);
    });

    server.begin();
    Serial.println("Server started.");
}

void loop() {
    processFFT(); // Run FFT processing
    delay(1000);  // Adjust update interval as needed
}

The frequency is nearly accuarate (440HZ outputs 437.sth) but the SPL and RT60 are majorly wrong because the SPL for instance outputs 130+ in a queit room with 35 dB.

Can anyone help with this issue ?

Your topic does not indicate a problem with the IDE and therefore has been moved to a more suitable location on the forum.

Most likely, one or more of the assumptions made in the SPL calculation are incorrect.

1 Like

Sorry, I don’t follow your wiring. Please post an annotated schematic showing your connections clearly. You are missing 11 connections. If I’m mistaken, please share a reference or link explaining how it works with just three connections.

My Reference: MAX9814 Datasheet.


that is the schematic design, also it works because it calculates the frequency correctly

Sorry I do not have that part and without a schematic I cannot be of further assistance.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.