Uploaded by Basit Raza

ESD Project Report

advertisement
Objective:
The primary objective of this project is to design and implement a system that is
able to detect the presence of a fire alarm in the surroundings through the analysis
of audio data. This is achieved by using the ESP32 microcontroller to sample analog
audio data coming from a microphone, and then using digital signal processing
techniques to analyze the frequency components contained within the audio data.
By analyzing the frequency spectrum of the audio data, we can determine if a fire
alarm is present, and subsequently send an alert through Wi-Fi to a webpage that
updates in real time. This allows for the rapid detection of fires, which can help to
minimize the potential damage caused by the fire and potentially save lives.
Software/Hardware Used:
Hardware:
1. ESP32: The ESP32 is a low-cost, low-power system-on-chip (SoC)
microcontroller with integrated Wi-Fi and dual-mode Bluetooth. It is used
in this project to collect data from the INMP441 I2S microphone, process
the data, and send it to the Arduino IDE for further analysis.
2. INMP441 I2S microphone: The INMP441 is a high-performance, low-power,
digital output omnidirectional MEMS microphone. It is used in this project
to collect audio data and send it to the ESP32 for processing.
Software:
1. Arduino IDE: The Arduino Integrated Development Environment (IDE) is a
free, open-source software platform used for programming
microcontrollers. It is used in this project to write and upload code to the
ESP32 and to analyze the data collected by the INMP441 microphone.
Design and Methodology:
The variables were initialized and the Wi-Fi connection was set up. The I2S port was
then set up and configured to read 1024 samples at a time. Using FreeRTOS, two
tasks were created: one for performing Fast Fourier Transform (FFT) on the noise
data, and another (pinned to core 1) for transmitting alerts via Wi-Fi.
In the FFT task, the program continuously read data from the I2S port and
converted it to floating point values. The FFT was then performed on the data to
calculate the energy in different frequency bins. The energy was summed up in
each octave and converted to a logarithmic scale using the A-weighting curve. The
loudness of the noise in decibels was calculated. If the loudness exceeded a
threshold, an alert was sent via the Wi-Fi task. This process was repeated
indefinitely.
Overall, the program used FreeRTOS to concurrently handle the tasks of performing
FFT on noise data and transmitting alerts via Wi-Fi, allowing for efficient and
effective monitoring of noise levels.
CODE:
#include
#include
#include
#include
#include
<Arduino.h>
<driver/i2s.h>
"arduinoFFT.h"
<WiFi.h>
<WiFiClient.h>
// Define the size of the noise sample as 1024
#define SAMPLES 1024
//Specify the I2S port and block size as the size of the noise sample.
const i2s_port_t I2S_PORT = I2S_NUM_0;
const int BLOCK_SIZE = SAMPLES;
//Declare variables for, WiFi network
const char* host = "maker.ifttt.com";
const int httpsPort = 80;
const char* ssid = "Galaxy A10";
const char* password = "00282651";
#define OCTAVES 9
// FFT data
static float real[SAMPLES];
static float imag[SAMPLES];
static arduinoFFT fft(real, imag, SAMPLES, SAMPLES);
static float energy[OCTAVES];
// A-weighting curve from 31.5 Hz ... 8000 Hz
static const float aweighting[] = {-39.4, -26.2, -16.1, -8.6, -3.2, 0.0, 1.2,
1.0, -1.1};
static
static
static
static
static
static
unsigned
unsigned
unsigned
unsigned
unsigned
unsigned
int bell = 0;
int fireAlarm = 0;
long ts = millis();
long last = micros();
int sum = 0;
int mn = 9999;
static unsigned int mx = 0;
static unsigned int cnt = 0;
static unsigned long lastTrigger[2] = {0, 0};
unsigned int peak;
static void integerToFloat(int32_t *integer, float *vReal, float *vImag,
uint16_t samples)
{
for (uint16_t i = 0; i < samples; i++)
{
vReal[i] = (integer[i] >> 16) / 10.0;
vImag[i] = 0.0;
}
}
// calculates energy from Re and Im parts and places it back in the Re part (Im
part is zeroed)
static void calculateEnergy(float *vReal, float *vImag, uint16_t samples)
{
for (uint16_t i = 0; i < samples; i++)
{
vReal[i] = sq(vReal[i]) + sq(vImag[i]);
vImag[i] = 0.0;
}
}
// sums up energy in bins per octave
static void sumEnergy(const float *bins, float *energies, int bin_size, int
num_octaves)
{
// skip the first bin
int bin = bin_size;
for (int octave = 0; octave < num_octaves; octave++)
{
float sum = 0.0;
for (int i = 0; i < bin_size; i++)
{
sum += real[bin++];
}
energies[octave] = sum;
bin_size *= 2;
}
}
static float decibel(float v)
{
return 10.0 * log(v) / log(10);
}
// converts energy to logaritmic, returns A-weighted sum
static float calculateLoudness(float *energies, const float *weights, int
num_octaves, float scale)
{
float sum = 0.0;
for (int i = 0; i < num_octaves; i++)
{
float energy = scale * energies[i];
sum += energy * pow(10, weights[i] / 10.0);
energies[i] = decibel(energy);
}
return decibel(sum);
}
void setup(void)
{
Serial.begin(115200);
Serial.print("Connecting to ");
Serial.println(ssid);
//WiFi.mode(WIFI_STA);
WiFi.begin(ssid,password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("");
Serial.println("IP address: ");
Serial.println(WiFi.localIP());
Serial.println("Configuring I2S...");
esp_err_t err;
// The I2S config as per the example
const i2s_config_t i2s_config = {
.mode = i2s_mode_t(I2S_MODE_MASTER | I2S_MODE_RX), // Receive, not
transfer
.sample_rate = 22627,
.bits_per_sample = I2S_BITS_PER_SAMPLE_32BIT,
.channel_format = I2S_CHANNEL_FMT_ONLY_LEFT, // for old esp-idf
versions use RIGHT
.communication_format = i2s_comm_format_t(I2S_COMM_FORMAT_I2S |
I2S_COMM_FORMAT_I2S_MSB),
.intr_alloc_flags = ESP_INTR_FLAG_LEVEL1, // Interrupt level 1
.dma_buf_count = 8,
// number of buffers
.dma_buf_len = BLOCK_SIZE,
// samples per buffer
.use_apll = true};
// The pin config as per the setup
const i2s_pin_config_t pin_config = {
.bck_io_num = 14,
// BCKL
.ws_io_num = 15,
// LRCL
.data_out_num = -1, // not used (only for speakers)
.data_in_num = 32
// DOUTESP32-INMP441 wiring
};
// Configuring the I2S driver and pins.
// This function must be called before any I2S driver read/write
operations.
err = i2s_driver_install(I2S_PORT, &i2s_config, 0, NULL);
if (err != ESP_OK)
{
Serial.printf("Failed installing driver: %d\n", err);
while (true)
;
}
err = i2s_set_pin(I2S_PORT, &pin_config);
if (err != ESP_OK)
{
Serial.printf("Failed setting pin: %d\n", err);
while (true)
;
}
Serial.println("I2S driver installed.");
xTaskCreatePinnedToCore(vFFTTask, "FFT Task", 9000, NULL, 3, NULL,1);
xTaskCreatePinnedToCore(vWiFiTask, "WiFi Task", 9000, NULL,
tskIDLE_PRIORITY, NULL,0);
}
void vWiFiTask(void *pvParameters)
{
for(;;)
{
WiFiClient client;
const int httpPort = 80;
if (!client.connect(host, httpPort)) {
Serial.println("connection failed");
break;}
if (detectFrequency(&bell, 15, peak, 45, 68, true))
{
String url =
"/trigger/FIRE/with/key/mw_ASHRKX8_oxxAhQzYTQiUYA18i4VUJQpwBY3iZA7N";
Serial.print("Requesting URL: ");
Serial.println(url);
client.print(String("POST ") + url + " HTTP/1.1\r\n" + "Host: " + host +
"\r\n" + "Connection: close\r\n\r\n");
vTaskDelay(pdMS_TO_TICKS(5000));
}
else
{
vTaskDelay(10);
}
}
vTaskDelete(NULL);
}
void vFFTTask(void *pvParameters)
{
for(;;)
{
if (micros() - last < 45200) {
// send mqtt metrics every 10s while waiting and no trigger is detected
if (millis() - ts >= 10000 && bell == 0 && fireAlarm == 0)
{
sendMetrics("home/noise", mn, mx, sum / cnt);
cnt = 0;
sum = 0;
mn = 9999;
mx = 0;
ts = millis();
}
//return;
}
last = micros();
static int32_t samples[BLOCK_SIZE];
// Read multiple samples at once and calculate the sound pressure
size_t num_bytes_read;
esp_err_t err = i2s_read(I2S_PORT,
(char *)samples,
BLOCK_SIZE, // the doc says bytes, but its
elements.
&num_bytes_read,
portMAX_DELAY); // no timeout
int samples_read = num_bytes_read / 8;
// integer to float
integerToFloat(samples, real, imag, SAMPLES);
// apply flat top window, optimal for energy calculations
fft.Windowing(FFT_WIN_TYP_FLT_TOP, FFT_FORWARD);
fft.Compute(FFT_FORWARD);
// calculate energy in each bin
calculateEnergy(real, imag, SAMPLES);
// sum up energy in bin for each octave
sumEnergy(real, energy, 1, OCTAVES);
// calculate loudness per octave + A weighted loudness
float loudness = calculateLoudness(energy, aweighting, OCTAVES, 1.0);
peak = (int)floor(fft.MajorPeak());
//Serial.println(peak);
// detecting 1kHz and 1.5kHz
if (detectFrequency(&bell, 15, peak, 45, 68, true))
{
Serial.println("Detected Alarm.");
sendAlarm(0, "home/alarm/doorbell", 2000);
vTaskDelay(pdMS_TO_TICKS(2000));
}
//detecting frequencies around 3kHz
/*if (detectFrequency(&fireAlarm, 15, peak, 140, 141, true))
{
Serial.println("Detected fire alarm");
sendAlarm(1, "home/alarm/fire", 10000);
}*/
calculateMetrics(loudness);
}
vTaskDelete(NULL);
}
unsigned int countSetBits(unsigned int n)
{
unsigned int count = 0;
while (n)
{
count += n & 1;
n >>= 1;
}
return count;
}
//detecting 2 frequencies. Set wide to true to match the previous and next bin
as well
bool detectFrequency(unsigned int *mem, unsigned int minMatch, double peak,
unsigned int bin1, unsigned int bin2, bool wide)
{
*mem = *mem << 1;
if (peak == bin1 || peak == bin2 || (wide && (peak == bin1 + 1 || peak ==
bin1 - 1 || peak == bin2 + 1 || peak == bin2 - 1)))
{
*mem |= 1;
}
if (countSetBits(*mem) >= minMatch)
{
return true;
}
return false;
}
void sendAlarm(unsigned int index, char *topic, unsigned int timeout)
{
// do not publish if last trigger was earlier than timeout ms
if (abs(millis() - lastTrigger[index]) < timeout)
{
return;
}
lastTrigger[index] = millis();
//publish to mqtt
//publish(topic, "1");
}
void sendMetrics(char * topic, unsigned int mn, unsigned int mx, unsigned int
avg)
{
String payload = "{\"min\": ";
payload += mn;
payload += ", \"max\":";
payload += mx;
payload += ", \"value\":";
payload += avg;
payload += "}";
Serial.println(payload);
//publish to mqtt
//publish(topic, (char *)payload.c_str());
}
void calculateMetrics(int val) {
cnt++;
sum += val;
if (val > mx)
{
mx = val;
}
if (val < mn)
{
mn = val;
}
}
void loop(void)
{
}
Output and results
Conclusion:
In conclusion, this project implemented a noise monitoring system using an
Arduino board and FreeRTOS to create two tasks. The first task was responsible
for performing Fast Fourier Transform (FFT) on the noise data to calculate the
energy in different frequency bins and summing up the energy in each octave.
The second task was responsible for transmitting alerts via Wi-Fi whenever the
loudness of the noise exceeded a certain threshold. This system could be used in
a variety of applications where noise levels need to be monitored, such as in
residential areas or at construction sites. By utilizing FreeRTOS and dividing the
program into tasks, the system was able to efficiently handle the data processing
and alert transmission concurrently.
Download