Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

Detect Noise Level Audio Decibels in MXChip Azure IoT DevKit

DZone's Guide to

Detect Noise Level Audio Decibels in MXChip Azure IoT DevKit

Play around with the Azure IoT DevKiT MXChip and explore its many capabilities, which include the ability to detect noise levels.

· IoT Zone ·
Free Resource

Digi-Key Electronics’ Internet of Things (IoT) Resource Center Inspires the Future: Read More

Introduction

Playing with Azure IoT DevKit MXChip is always fun; the device has many capabilities. For the past few days, I have been working with some of the capabilities of this device like atmospheric pressure, temperature, and humidity through its sensors. In this article, I will show you how you can calculate noise level using the microphone of AZ3166 IoT Device. Now, let’s get started!

Background

In our last article, we have already seen how to read the temperature, humidity, atmospheric pressure from the MXChip AZ3166 sensors and send those to our Azure IoT Hub. In this article, we will perform the following tasks.

  1. Find the noise level using the AudioClassV2 class
  2. Send the values to our IoT Hub

Source Code

Please feel free to play around with this repository.

Using the Code

Once you have your own workspace, we can open the solution in VSCode and start coding.

main.ino

This is our solution starting point — every project must have its own sketch file. Usually, this file will contain the functions loop() and setup().

Before we get started, let’s include the header files we are going to use.

//Header files - Start//
#include "AZ3166WiFi.h"
#include "AzureIotHub.h"
#include "DevKitMQTTClient.h"
#include "config.h"
#include "utility.h"
#include "SystemTickCounter.h"
#include "RingBuffer.h"
#include "parson.h"
#include "EEPROMInterface.h"
#include "http_client.h"
#include <Arduino.h>
#include <stdio.h>
#include <math.h>
#include "OledDisplay.h"
#include "AudioClassV2.h"
#include "stm32412g_discovery_audio.h"
#include "RGB_LED.h"
#include <stdint.h>

#define MFCC_WRAPPER_DEFINED
#include "featurizer.h"
//Header files - End//
//**********************//


Now, we can declare our constants and variables.

//Constants and variables- Start//
enum AppState
{
APPSTATE_Init,
APPSTATE_Error,
APPSTATE_Recording
};

static AppState appstate;
// These numbers need to match the compiled ELL models.
const int SAMPLE_RATE = 16000;
const int SAMPLE_BIT_DEPTH = 16;
const int FEATURIZER_INPUT_SIZE = 512;
const int FRAME_RATE = 33; // assumes a "shift" of 512 and 512/16000 = 0.032ms per frame.
const int FEATURIZER_OUTPUT_SIZE = 80;
const int CLASSIFIER_OUTPUT_SIZE = 31;
const float THRESHOLD = 0.9;
static int scaled_input_buffer_pos = 0;
static float scaled_input_buffer[FEATURIZER_INPUT_SIZE]; // raw audio converted to float
const int MAX_FEATURE_BUFFERS = 10; // set to buffer up to 1 second of audio in circular buffer
static float featurizer_input_buffers[MAX_FEATURE_BUFFERS][FEATURIZER_INPUT_SIZE]; // input to featurizer
static int featurizer_input_buffer_read = -1; // next read pos
static int featurizer_input_buffer_write = 0; // next write pos
static int dropped_frames = 0;
static float featurizer_output_buffer[FEATURIZER_OUTPUT_SIZE]; // 40 channels
static float classifier_output_buffer[CLASSIFIER_OUTPUT_SIZE]; // 31 classes
static int raw_audio_count = 0;
static char raw_audio_buffer[AUDIO_CHUNK_SIZE];
static int prediction_count = 0;
static int last_prediction = 0;
static int last_confidence = 0; // as a percentage between 0 and 100.
static uint8_t maxGain = 0;
static uint8_t minGain = 0;
int decibels = 0;
float min_level = 100;
float max_level = 0;
RGB_LED rgbLed;
static bool hasWifi = false;
static bool messageSending = true;
static uint64_t send_interval_ms;
int messageCount = 0; // holds ID
bool messageReceived = false;
char device_id[6];
AudioClass &Audio = AudioClass::getInstance();
//Constants and variables- End//
//************************************//


Now, we can add the codes for the configuration. Usually, you wouldn’t have to edit any codes in this section.

//Configuration functions - Start//
static void initWifi()
{
Screen.print(2, "Connecting...");

if (WiFi.begin() == WL_CONNECTED)
{
IPAddress ip = WiFi.localIP();
Screen.print(1, ip.get_address());
hasWifi = true;
Screen.print(2, "Running... \r\n");
}
else
{
hasWifi = false;
Screen.print(1, "No Wi-Fi\r\n ");
}
}

static void sendConfirmationCallback(IOTHUB_CLIENT_CONFIRMATION_RESULT result)
{
if (result == IOTHUB_CLIENT_CONFIRMATION_OK)
{
blinkSendConfirmation();
}
}

static void messageCallback(const char *payLoad, int size)
{
blinkLED();
Screen.print(1, payLoad, true);
}

static void deviceTwinCallback(DEVICE_TWIN_UPDATE_STATE updateState, const unsigned char *payLoad, int size)
{
char *temp = (char *)malloc(size + 1);
if (temp == NULL)
{
return;
}

memcpy(temp, payLoad, size);
temp[size] = '\0';
parseTwinMessage(updateState, temp);
free(temp);
}

static int deviceMethodCallback(const char *methodName, const unsigned char *payload, int size, unsigned char **response, int *response_size)
{
LogInfo("Try to invoke method %s", methodName);
const char *responseMessage = "\"Successfully invoke device method\"";
int result = 200;

if (strcmp(methodName, DIRECT_METHOD_NAME) == 0)
{
messageReceived = true;

char *temp = (char *)malloc(size + 1);
memcpy(temp, payload, size);
temp[size] = '\0';

if (temp != NULL)
{
Screen.init();
Screen.print(0, "NEW MESSAGE!");
Screen.print(2, temp);
}

free(temp);
}
else
{
LogInfo("No method %s found", methodName);
responseMessage = "\"No method found\"";
result = 404;
}

*response_size = strlen(responseMessage);
*response = (unsigned char *)malloc(*response_size);
strncpy((char *)(*response), responseMessage, *response_size);

return result;
}
//Configuration functions - End//
//***********************************//


As I mentioned earlier, every INO file will have its own setup() and loop() function. We can modify our setup() function as below.

void setup()
{
Screen.init();
Screen.print(0, "IoT Device Demo");
Screen.print(2, "Initializing...");

Screen.print(3, " > Serial");
Serial.begin(115200);

// Initialize the WiFi module
Screen.print(3, " > WiFi");
hasWifi = false;
initWifi();
if (!hasWifi)
{
return;
}

Screen.print(3, " > Sensors");
sensorInit();

Screen.print(3, " > IoT Hub");
DevKitMQTTClient_Init(true);
DevKitMQTTClient_SetOption(OPTION_MINI_SOLUTION_NAME, "mlIoTPlatformDevice");
DevKitMQTTClient_SetSendConfirmationCallback(sendConfirmationCallback);
DevKitMQTTClient_SetMessageCallback(messageCallback);
DevKitMQTTClient_SetDeviceTwinCallback(deviceTwinCallback);
DevKitMQTTClient_SetDeviceMethodCallback(deviceMethodCallback);

appstate = APPSTATE_Init;
Serial.begin(115200);

int filter_size = mfcc_GetInputSize(0);
if (filter_size != FEATURIZER_INPUT_SIZE)
{
Serial.printf("Featurizer input size %d is not equal to %d\n", filter_size, FEATURIZER_INPUT_SIZE);
show_error("Featurizer Error");
}

if (appstate != APPSTATE_Error)
{
::memset(featurizer_input_buffers[0], 0, FEATURIZER_INPUT_SIZE);

// give it a whirl !!
mfcc_Filter(nullptr, featurizer_input_buffers[0], featurizer_output_buffer);

// check audio gain and print the result.
uint32_t id = Audio.readRegister(nau88c10_CHIPID_ADDR);
if (id == NAU88C10_ID)
{
Serial.printf("Found audio device: NAU88C10\r\n");
}
else
{
Serial.printf("Found audio device: 0x%x\r\n", id);
}

// a default gain level of 4 seems to work pretty well.
start_recording();

Screen.clean();

Screen.print(0, "Listening...");
Screen.print(1, "A = min gain");
Screen.print(2, "B = max gain");

minGain = 0;
maxGain = 7;

set_gain();
display_gain();
}

send_interval_ms = SystemTickCounterRead();
}


The function loop() will be called each five seconds, as I had set the INTERVAL as 5000 milliseconds.

// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license.

// Interval time(ms) for sending message to IoT Hub
#define INTERVAL 5000

#define MESSAGE_MAX_LEN 256

#define TEMPERATURE_ALERT 30

#define DIRECT_METHOD_NAME "message"

// How many messages get sent to the hub before user has to press A to continue
#define MESSAGE_SEND_COUNT_LIMIT 350


Now, we can edit our code of the loop() function, as shown below.

void loop()
{
if (hasWifi)
{
if (messageSending && (int)(SystemTickCounterRead() - send_interval_ms) >= getInterval())
{
if (appstate != APPSTATE_Error)
{
if (dropped_frames > 0)
{
Serial.printf("%d dropped frames\n", dropped_frames);
dropped_frames = 0;
}
// process all the buffered input frames
featurizer_input_buffer_read = next(featurizer_input_buffer_read);
decibels = get_prediction(featurizer_input_buffers[featurizer_input_buffer_read]);
}

// Send data
char messagePayload[MESSAGE_MAX_LEN];
float *newValues;

newValues = setMessage(messageCount++, messagePayload, decibels);

if (!messageReceived)
{
// Update display
char buff[128];
sprintf(buff, "ID: %s \r\n Temp:%s°C \r\n Humidity:%s%% \r\n Pres:%smb \r\n", device_id, f2s(*(newValues), 1), f2s(*(newValues + 1), 1), f2s(*(newValues + 2), 1));
Screen.print(buff);
}

EVENT_INSTANCE *message = DevKitMQTTClient_Event_Generate(messagePayload, MESSAGE);
DevKitMQTTClient_SendEventInstance(message);
send_interval_ms = SystemTickCounterRead();
}
else
{
DevKitMQTTClient_Check();
}
}

delay(10);
}


utility.cpp

As you can see, once we get the values from the function get_prediction (), we are passing the decibels values to our setMessage() function, which we have defined in the file utility.cpp. Inside the setMessage() function, we will add the decibels value to JSON object using the function  json_object_set_number ().

// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license.

#include "HTS221Sensor.h"
#include "AzureIotHub.h"
#include "Arduino.h"
#include "parson.h"
#include <assert.h>
#include "config.h"
#include "RGB_LED.h"
#include "Sensor.h"
#include "LIS2MDLSensor.h"

#define RGB_LED_BRIGHTNESS 32

DevI2C *i2c;
HTS221Sensor *ht_sensor;
LPS22HBSensor *pressureSensor;
LSM6DSLSensor *acc_gyro;
LIS2MDLSensor *lis2mdl;

int gAxes[3];
int mAxes[3];

static RGB_LED rgbLed;
static int interval = INTERVAL;

int getInterval()
{
return interval;
}

void blinkLED()
{
rgbLed.turnOff();
rgbLed.setColor(RGB_LED_BRIGHTNESS, 0, 0);
delay(500);
rgbLed.turnOff();
}

void blinkSendConfirmation()
{
rgbLed.turnOff();
rgbLed.setColor(0, 0, RGB_LED_BRIGHTNESS);
delay(500);
rgbLed.turnOff();
}

void parseTwinMessage(DEVICE_TWIN_UPDATE_STATE updateState, const char *message)
{
JSON_Value *root_value;
root_value = json_parse_string(message);
if (json_value_get_type(root_value) != JSONObject)
{
if (root_value != NULL)
{
json_value_free(root_value);
}
LogError("parse %s failed", message);
return;
}

JSON_Object *root_object = json_value_get_object(root_value);

double val = 0;
if (updateState == DEVICE_TWIN_UPDATE_COMPLETE)
{
JSON_Object *desired_object = json_object_get_object(root_object, "desired");
if (desired_object != NULL)
{
val = json_object_get_number(desired_object, "interval");
}
}
else
{
val = json_object_get_number(root_object, "interval");
}

if (val > 500)
{
interval = (int)val;
LogInfo(">>> Device twin updated: set interval to %d", interval);
}

json_value_free(root_value);
}

void sensorInit()
{
i2c = new DevI2C(D14, D15);

ht_sensor = new HTS221Sensor(*i2c);
ht_sensor->init(NULL);

pressureSensor = new LPS22HBSensor(*i2c);
pressureSensor -> init(NULL);

acc_gyro = new LSM6DSLSensor(*i2c, D4, D5);
acc_gyro->init(NULL);
acc_gyro->enableAccelerator();

lis2mdl = new LIS2MDLSensor(*i2c);
lis2mdl->init(NULL);
}

float readTemperature()
{
ht_sensor->reset();

float temperature = 0;
ht_sensor->getTemperature(&temperature);

return temperature;
}

float readHumidity()
{
ht_sensor->reset();

float humidity = 0;
ht_sensor->getHumidity(&humidity);

return humidity;
}

float readPressure()
{
float pressure = 0;
pressureSensor->getPressure(&pressure);

return pressure;
}

void setAccelAxes()
{
acc_gyro->getXAxes(gAxes);
}

void setMagAxes()
{
lis2mdl->getMAxes(mAxes);
}

float * setMessage(int messageId, char *payload, int decibels)
{
static float newValues[3];

JSON_Value *root_value = json_value_init_object();
JSON_Object *root_object = json_value_get_object(root_value);
char *serialized_string = NULL;

json_object_set_number(root_object, "messageId", messageId);
json_object_set_number(root_object, "decibels", decibels);

// Obtain values
float temperature = readTemperature();
float humidity = readHumidity();
float pressure = readPressure();
setAccelAxes();
setMagAxes();

// Set new values
newValues[0] = temperature;
newValues[1] = humidity;
newValues[2] = pressure;

bool temperatureAlert = false;

// Set temp json
json_object_set_number(root_object, "temperature", temperature);

// Set humidity json
json_object_set_number(root_object, "humidity", humidity);

// Set pressure json
json_object_set_number(root_object, "pressure", pressure);

// Set gyro axes
json_object_set_number(root_object, "accelX", gAxes[0]);
json_object_set_number(root_object, "accelY", gAxes[1]);
json_object_set_number(root_object, "accelZ", gAxes[2]);

// Set mag axes
json_object_set_number(root_object, "magX", mAxes[0]);
json_object_set_number(root_object, "magY", mAxes[1]);
json_object_set_number(root_object, "magZ", mAxes[2]);

serialized_string = json_serialize_to_string_pretty(root_value);

snprintf(payload, MESSAGE_MAX_LEN, "%s", serialized_string);
json_free_serialized_string(serialized_string);
json_value_free(root_value);

return newValues;
}


You should also add the files featurizer.h and featurizer.s to get it working. You can get those files from the source code repository mentioned above.

Compile and Upload to the Device

As we have already made the needed changes, it is time to compile the device solution and upload the same to our device. Press F1 and select Azure IoT Device Workbench: Compile Device Code. If you ever get an error as “error: utility.h: No such file or directory,” please compile the device code again. If you are facing any unexpected errors, please delete the “.build” folder and compile again.

Once you get a message as ” [Done] Finished verify sketch – Main.ino ” in your Output window, you can upload the solution to your device. To do so, press F1 again and select ” Azure IoT Device Workbench: Upload Device Code.” Please make sure that the device is been connected to your machine. If everything goes well, you will be getting a message as ” [Done] Uploaded the sketch: Main.ino.”

Please remember to see the GitHub repository for the full code.

Device to Cloud Messages

Now, your device will be sending the Decibels data to the Azure IoT Hub. Let’s see that in the D2C Monitoring window.

Send MXChip Data to Cloud


{
"messageId": 119,
"decibels": 94,
"temperature": 26.4,
"humidity": 34.400002,
"pressure": 994.585693,
"accelX": -9,
"accelY": -12,
"accelZ": 993,
"magX": -156,
"magY": -5,
"magZ": -253
}


Conclusion

Wow! Now, we have learned:

  • How to detect the noise level in MXChip
  • How to use AudioClassV2
  • How to send device data to the Azure IoT Hub

Please consider reading my IoT articles here for the continuation.

Digi-Key’s IoT Component Selector is your one-stop-shop for the IoT

Topics:
iot ,tutorial ,audio ,noise detector ,azure ,azure iot devkit ,mxchip

Published at DZone with permission of

Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}