Basic implementation of sampling+FFT+dBV/Hz calculation
This commit is contained in:
commit
1a9ac19d60
11
.gitignore
vendored
Normal file
11
.gitignore
vendored
Normal file
|
@ -0,0 +1,11 @@
|
|||
.cache/
|
||||
.pio/
|
||||
.vscode/.browse.c_cpp.db*
|
||||
.vscode/c_cpp_properties.json
|
||||
.vscode/launch.json
|
||||
.vscode/ipch
|
||||
|
||||
data/etc/*
|
||||
!data/etc/.*
|
||||
|
||||
compile_commands.json
|
5
Makefile
Normal file
5
Makefile
Normal file
|
@ -0,0 +1,5 @@
|
|||
.pio/: src
|
||||
pio run
|
||||
|
||||
compile_commands.json: src
|
||||
pio run -t compiledb
|
0
data/etc/.keep
Normal file
0
data/etc/.keep
Normal file
68
gen_lut.py
Executable file
68
gen_lut.py
Executable file
|
@ -0,0 +1,68 @@
|
|||
#!/usr/bin/env python3
|
||||
|
||||
import sys
|
||||
from math import *
|
||||
|
||||
preamble = """// This file was auto-generated using gen_lut.py
|
||||
|
||||
#include "lut.h"
|
||||
|
||||
"""
|
||||
|
||||
postamble = """
|
||||
|
||||
value_type lookup_sin(int layer, int element) {
|
||||
return sin_lut[layer][element];
|
||||
}
|
||||
|
||||
value_type lookup_cos(int layer, int element) {
|
||||
return cos_lut[layer][element];
|
||||
}
|
||||
"""
|
||||
|
||||
if len(sys.argv) < 2:
|
||||
print("Argument required: FFT_EXPONENT")
|
||||
exit(1)
|
||||
|
||||
fft_exponent = int(sys.argv[1])
|
||||
|
||||
with open("src/lut.c", "w") as ofile:
|
||||
ofile.write(preamble)
|
||||
|
||||
# generate the sin() lookup table
|
||||
for layer in range(0, fft_exponent):
|
||||
num_elements = (1 << layer)
|
||||
ofile.write("value_type sin_lut%i[%i] = {" % (layer, num_elements))
|
||||
|
||||
ofile.write("0")
|
||||
|
||||
for element in range(1, num_elements):
|
||||
ofile.write(", %.10f" % sin(-pi * element / num_elements));
|
||||
|
||||
ofile.write("};\n\n")
|
||||
|
||||
ofile.write("value_type *sin_lut[%i] = {sin_lut0" % fft_exponent);
|
||||
|
||||
for i in range(1, fft_exponent):
|
||||
ofile.write(", sin_lut" + str(i));
|
||||
ofile.write("};\n");
|
||||
|
||||
# generate the cos() lookup table
|
||||
for layer in range(0, fft_exponent):
|
||||
num_elements = (1 << layer)
|
||||
ofile.write("value_type cos_lut%i[%i] = {" % (layer, num_elements))
|
||||
|
||||
ofile.write("1")
|
||||
|
||||
for element in range(1, num_elements):
|
||||
ofile.write(", %.10f" % cos(-pi * element / num_elements));
|
||||
|
||||
ofile.write("};\n\n")
|
||||
|
||||
ofile.write("value_type *cos_lut[%i] = {cos_lut0" % fft_exponent);
|
||||
|
||||
for i in range(1, fft_exponent):
|
||||
ofile.write(", cos_lut" + str(i));
|
||||
ofile.write("};\n");
|
||||
|
||||
ofile.write(postamble)
|
34
platformio.ini
Normal file
34
platformio.ini
Normal file
|
@ -0,0 +1,34 @@
|
|||
;PlatformIO Project Configuration File
|
||||
;
|
||||
; Build options: build flags, source filter
|
||||
; Upload options: custom upload port, speed and extra flags
|
||||
; Library options: dependencies, extra library storages
|
||||
; Advanced options: extra scripting
|
||||
;
|
||||
; Please visit documentation for the other options and examples
|
||||
; https://docs.platformio.org/page/projectconf.html
|
||||
|
||||
[env:nodemcu-32s]
|
||||
platform = espressif32
|
||||
board = nodemcu-32s
|
||||
framework = arduino
|
||||
|
||||
monitor_speed = 115200
|
||||
|
||||
lib_deps =
|
||||
AutoAnalogAudio
|
||||
|
||||
build_flags = -std=c++11
|
||||
|
||||
#[env:esp32-evb]
|
||||
#platform = espressif32
|
||||
#board = esp32-evb
|
||||
#framework = arduino
|
||||
#
|
||||
#monitor_speed = 115200
|
||||
#
|
||||
#lib_deps =
|
||||
# AutoAnalogAudio
|
||||
#
|
||||
#build_flags = -std=c++11
|
||||
#board_build.filesystem = littlefs
|
44
src/Config.cpp
Normal file
44
src/Config.cpp
Normal file
|
@ -0,0 +1,44 @@
|
|||
#include <SPIFFS.h>
|
||||
|
||||
#include "Config.h"
|
||||
|
||||
Config::Config()
|
||||
{}
|
||||
|
||||
void Config::load(void)
|
||||
{
|
||||
// load WLANs
|
||||
File wlanFile = SPIFFS.open("/etc/wlan", "r");
|
||||
|
||||
while(wlanFile.available()) {
|
||||
String ssid = wlanFile.readStringUntil('\n');
|
||||
|
||||
if(!wlanFile.available()) {
|
||||
Serial.println("/etc/wlan terminated early. Last entry ignored.");
|
||||
break;
|
||||
}
|
||||
|
||||
String passwd = wlanFile.readStringUntil('\n');
|
||||
|
||||
m_wlans.emplace_back(WLAN{ssid.c_str(), passwd.c_str()});
|
||||
}
|
||||
|
||||
wlanFile.close();
|
||||
|
||||
// load Challenge-Response data
|
||||
File authFile = SPIFFS.open("/etc/auth", "r");
|
||||
|
||||
if(authFile.available()) {
|
||||
String passwd = authFile.readStringUntil('\n');
|
||||
m_crPassword = passwd.c_str();
|
||||
|
||||
if(!authFile.available()) {
|
||||
m_crSalt = "";
|
||||
} else {
|
||||
String salt = authFile.readStringUntil('\n');
|
||||
m_crSalt = salt.c_str();
|
||||
}
|
||||
}
|
||||
|
||||
authFile.close();
|
||||
}
|
36
src/Config.h
Normal file
36
src/Config.h
Normal file
|
@ -0,0 +1,36 @@
|
|||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
class Config
|
||||
{
|
||||
public:
|
||||
struct WLAN
|
||||
{
|
||||
std::string ssid;
|
||||
std::string password;
|
||||
};
|
||||
|
||||
typedef std::vector<WLAN> WLANList;
|
||||
|
||||
static Config &instance()
|
||||
{
|
||||
static Config theConfig;
|
||||
return theConfig;
|
||||
}
|
||||
|
||||
void load(void);
|
||||
|
||||
const WLANList& getWLANList(void) { return m_wlans; }
|
||||
|
||||
const std::string& getCRPassword(void) { return m_crPassword; }
|
||||
const std::string& getCRSalt(void) { return m_crSalt; }
|
||||
|
||||
private:
|
||||
Config();
|
||||
|
||||
WLANList m_wlans;
|
||||
std::string m_crPassword;
|
||||
std::string m_crSalt;
|
||||
};
|
155
src/fft.c
Normal file
155
src/fft.c
Normal file
|
@ -0,0 +1,155 @@
|
|||
#include <math.h>
|
||||
|
||||
#include "fft_config.h"
|
||||
|
||||
#include "lut.h"
|
||||
#include "fft.h"
|
||||
|
||||
value_type hanning_buffer[BLOCK_LEN];
|
||||
int lookup_table[BLOCK_LEN];
|
||||
|
||||
void init_fft(void) {
|
||||
int i = 0;
|
||||
int ri, b;
|
||||
|
||||
for(i = 0; i < BLOCK_LEN; i++) {
|
||||
hanning_buffer[i] = 0.5 * (1 - cos(2 * M_PI * i / BLOCK_LEN));
|
||||
}
|
||||
|
||||
for(i = 0; i < BLOCK_LEN; i++) {
|
||||
ri = 0;
|
||||
|
||||
for(b = 0; b < FFT_EXPONENT; b++)
|
||||
ri |= ((i >> b) & 1) << (FFT_EXPONENT - b - 1);
|
||||
|
||||
lookup_table[i] = ri;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void complex_to_absolute(value_type *re, value_type *im, value_type *result) {
|
||||
int i;
|
||||
|
||||
for(i = 0; i < DATALEN; i++)
|
||||
{
|
||||
result[i] = sqrt( re[i]*re[i] + im[i]*im[i] );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void apply_hanning(value_type *dftinput) {
|
||||
int i;
|
||||
|
||||
for(i = 0; i < BLOCK_LEN; i++)
|
||||
dftinput[i] *= hanning_buffer[i];
|
||||
}
|
||||
|
||||
|
||||
|
||||
void fft_transform(value_type *samples, value_type *resultRe, value_type *resultIm) {
|
||||
int i;
|
||||
int layer, part, element;
|
||||
int num_parts, num_elements;
|
||||
|
||||
int left, right;
|
||||
|
||||
value_type x_left_re, x_left_im, x_right_re, x_right_im;
|
||||
value_type sinval, cosval;
|
||||
|
||||
// re-arrange the input array according to the lookup table
|
||||
// and store it into the real output array (as the input is obviously real).
|
||||
// zero the imaginary output
|
||||
for(i = 0; i < BLOCK_LEN; i++)
|
||||
{
|
||||
resultRe[lookup_table[i]] = samples[i];
|
||||
resultIm[i] = 0;
|
||||
}
|
||||
|
||||
// walk layers
|
||||
for(layer = 0; layer < FFT_EXPONENT; layer++)
|
||||
{
|
||||
// number of parts in current layer
|
||||
num_parts = 1 << (FFT_EXPONENT - layer - 1);
|
||||
|
||||
// walk parts of layer
|
||||
for(part = 0; part < num_parts; part++)
|
||||
{
|
||||
// number of elements in current part
|
||||
num_elements = (1 << layer);
|
||||
|
||||
// walk elements in part
|
||||
for(element = 0; element < num_elements; element++)
|
||||
{
|
||||
// calculate index of element in left and right half of part
|
||||
left = (1 << (layer + 1)) * part + element;
|
||||
right = left + (1 << layer);
|
||||
|
||||
// buffer the elements for the calculation
|
||||
x_left_re = resultRe[left];
|
||||
x_left_im = resultIm[left];
|
||||
x_right_re = resultRe[right];
|
||||
x_right_im = resultIm[right];
|
||||
|
||||
// use lookup table to get sinus and cosinus values for param
|
||||
//param = -M_PI * element / (1 << layer);
|
||||
sinval = lookup_sin(layer, element);
|
||||
cosval = lookup_cos(layer, element);
|
||||
|
||||
// combine the values according to a butterfly diagram
|
||||
resultRe[left] = x_right_re + x_left_re * cosval - x_left_im * sinval;
|
||||
resultIm[left] = x_right_im + x_left_im * cosval + x_left_re * sinval;
|
||||
resultRe[right] = x_right_re - x_left_re * cosval + x_left_im * sinval;
|
||||
resultIm[right] = x_right_im - x_left_im * cosval - x_left_re * sinval;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t find_loudest_frequency(value_type *absFFT) {
|
||||
int maxPos = 0;
|
||||
value_type maxVal = 0;
|
||||
int i;
|
||||
|
||||
for(i = 0; i < BLOCK_LEN; i++) {
|
||||
if(absFFT[i] > maxVal) {
|
||||
maxPos = i;
|
||||
maxVal = absFFT[i];
|
||||
}
|
||||
}
|
||||
|
||||
return (value_type)maxPos * SAMPLE_RATE / BLOCK_LEN;
|
||||
}
|
||||
|
||||
value_type get_energy_in_band(value_type *fft, uint32_t minFreq, uint32_t maxFreq) {
|
||||
int firstBlock = minFreq * BLOCK_LEN / SAMPLE_RATE;
|
||||
int lastBlock = maxFreq * BLOCK_LEN / SAMPLE_RATE;
|
||||
int i;
|
||||
|
||||
value_type energy = 0;
|
||||
for(i = firstBlock; i < lastBlock; i++) {
|
||||
energy += fft[i];
|
||||
}
|
||||
|
||||
return energy;
|
||||
}
|
||||
|
||||
value_type get_energy_density_in_band(value_type *fft, uint32_t minFreq, uint32_t maxFreq) {
|
||||
int firstBlock = minFreq * BLOCK_LEN / SAMPLE_RATE;
|
||||
int lastBlock = maxFreq * BLOCK_LEN / SAMPLE_RATE;
|
||||
int i;
|
||||
|
||||
value_type energy = 0;
|
||||
for(i = firstBlock; i < lastBlock; i++) {
|
||||
energy += fft[i];
|
||||
}
|
||||
|
||||
if(firstBlock != lastBlock) {
|
||||
energy /= (lastBlock - firstBlock);
|
||||
}
|
||||
|
||||
energy *= (float)BLOCK_LEN / (float)SAMPLE_RATE; // normalze to Hz
|
||||
|
||||
return energy;
|
||||
}
|
16
src/fft.h
Normal file
16
src/fft.h
Normal file
|
@ -0,0 +1,16 @@
|
|||
#ifndef FFT_H
|
||||
#define FFT_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "fft_config.h"
|
||||
|
||||
void init_fft(void);
|
||||
void complex_to_absolute(value_type *re, value_type *im, value_type *result);
|
||||
void apply_hanning(value_type *dftinput);
|
||||
void fft_transform(value_type *samples, value_type *resultRe, value_type *resultIm);
|
||||
uint32_t find_loudest_frequency(value_type *absFFT);
|
||||
value_type get_energy_in_band(value_type *fft, uint32_t minFreq, uint32_t maxFreq);
|
||||
value_type get_energy_density_in_band(value_type *fft, uint32_t minFreq, uint32_t maxFreq);
|
||||
|
||||
#endif // FFT_H
|
12
src/fft_config.h
Normal file
12
src/fft_config.h
Normal file
|
@ -0,0 +1,12 @@
|
|||
#ifndef CONFIG_H
|
||||
#define CONFIG_H
|
||||
|
||||
// FFT transformation parameters
|
||||
#define FFT_EXPONENT 9 // ATTENTION: when you change this, run gen_lut.py with this value as argument
|
||||
#define BLOCK_LEN (1 << FFT_EXPONENT) // 2^FFT_EXPONENT
|
||||
#define SAMPLE_RATE 48000
|
||||
#define DATALEN (BLOCK_LEN / 2)
|
||||
|
||||
typedef float value_type;
|
||||
|
||||
#endif // CONFIG_H
|
51
src/lut.c
Normal file
51
src/lut.c
Normal file
|
@ -0,0 +1,51 @@
|
|||
// This file was auto-generated using gen_lut.py
|
||||
|
||||
#include "lut.h"
|
||||
|
||||
value_type sin_lut0[1] = {0};
|
||||
|
||||
value_type sin_lut1[2] = {0, -1.0000000000};
|
||||
|
||||
value_type sin_lut2[4] = {0, -0.7071067812, -1.0000000000, -0.7071067812};
|
||||
|
||||
value_type sin_lut3[8] = {0, -0.3826834324, -0.7071067812, -0.9238795325, -1.0000000000, -0.9238795325, -0.7071067812, -0.3826834324};
|
||||
|
||||
value_type sin_lut4[16] = {0, -0.1950903220, -0.3826834324, -0.5555702330, -0.7071067812, -0.8314696123, -0.9238795325, -0.9807852804, -1.0000000000, -0.9807852804, -0.9238795325, -0.8314696123, -0.7071067812, -0.5555702330, -0.3826834324, -0.1950903220};
|
||||
|
||||
value_type sin_lut5[32] = {0, -0.0980171403, -0.1950903220, -0.2902846773, -0.3826834324, -0.4713967368, -0.5555702330, -0.6343932842, -0.7071067812, -0.7730104534, -0.8314696123, -0.8819212643, -0.9238795325, -0.9569403357, -0.9807852804, -0.9951847267, -1.0000000000, -0.9951847267, -0.9807852804, -0.9569403357, -0.9238795325, -0.8819212643, -0.8314696123, -0.7730104534, -0.7071067812, -0.6343932842, -0.5555702330, -0.4713967368, -0.3826834324, -0.2902846773, -0.1950903220, -0.0980171403};
|
||||
|
||||
value_type sin_lut6[64] = {0, -0.0490676743, -0.0980171403, -0.1467304745, -0.1950903220, -0.2429801799, -0.2902846773, -0.3368898534, -0.3826834324, -0.4275550934, -0.4713967368, -0.5141027442, -0.5555702330, -0.5956993045, -0.6343932842, -0.6715589548, -0.7071067812, -0.7409511254, -0.7730104534, -0.8032075315, -0.8314696123, -0.8577286100, -0.8819212643, -0.9039892931, -0.9238795325, -0.9415440652, -0.9569403357, -0.9700312532, -0.9807852804, -0.9891765100, -0.9951847267, -0.9987954562, -1.0000000000, -0.9987954562, -0.9951847267, -0.9891765100, -0.9807852804, -0.9700312532, -0.9569403357, -0.9415440652, -0.9238795325, -0.9039892931, -0.8819212643, -0.8577286100, -0.8314696123, -0.8032075315, -0.7730104534, -0.7409511254, -0.7071067812, -0.6715589548, -0.6343932842, -0.5956993045, -0.5555702330, -0.5141027442, -0.4713967368, -0.4275550934, -0.3826834324, -0.3368898534, -0.2902846773, -0.2429801799, -0.1950903220, -0.1467304745, -0.0980171403, -0.0490676743};
|
||||
|
||||
value_type sin_lut7[128] = {0, -0.0245412285, -0.0490676743, -0.0735645636, -0.0980171403, -0.1224106752, -0.1467304745, -0.1709618888, -0.1950903220, -0.2191012402, -0.2429801799, -0.2667127575, -0.2902846773, -0.3136817404, -0.3368898534, -0.3598950365, -0.3826834324, -0.4052413140, -0.4275550934, -0.4496113297, -0.4713967368, -0.4928981922, -0.5141027442, -0.5349976199, -0.5555702330, -0.5758081914, -0.5956993045, -0.6152315906, -0.6343932842, -0.6531728430, -0.6715589548, -0.6895405447, -0.7071067812, -0.7242470830, -0.7409511254, -0.7572088465, -0.7730104534, -0.7883464276, -0.8032075315, -0.8175848132, -0.8314696123, -0.8448535652, -0.8577286100, -0.8700869911, -0.8819212643, -0.8932243012, -0.9039892931, -0.9142097557, -0.9238795325, -0.9329927988, -0.9415440652, -0.9495281806, -0.9569403357, -0.9637760658, -0.9700312532, -0.9757021300, -0.9807852804, -0.9852776424, -0.9891765100, -0.9924795346, -0.9951847267, -0.9972904567, -0.9987954562, -0.9996988187, -1.0000000000, -0.9996988187, -0.9987954562, -0.9972904567, -0.9951847267, -0.9924795346, -0.9891765100, -0.9852776424, -0.9807852804, -0.9757021300, -0.9700312532, -0.9637760658, -0.9569403357, -0.9495281806, -0.9415440652, -0.9329927988, -0.9238795325, -0.9142097557, -0.9039892931, -0.8932243012, -0.8819212643, -0.8700869911, -0.8577286100, -0.8448535652, -0.8314696123, -0.8175848132, -0.8032075315, -0.7883464276, -0.7730104534, -0.7572088465, -0.7409511254, -0.7242470830, -0.7071067812, -0.6895405447, -0.6715589548, -0.6531728430, -0.6343932842, -0.6152315906, -0.5956993045, -0.5758081914, -0.5555702330, -0.5349976199, -0.5141027442, -0.4928981922, -0.4713967368, -0.4496113297, -0.4275550934, -0.4052413140, -0.3826834324, -0.3598950365, -0.3368898534, -0.3136817404, -0.2902846773, -0.2667127575, -0.2429801799, -0.2191012402, -0.1950903220, -0.1709618888, -0.1467304745, -0.1224106752, -0.0980171403, -0.0735645636, -0.0490676743, -0.0245412285};
|
||||
|
||||
value_type sin_lut8[256] = {0, -0.0122715383, -0.0245412285, -0.0368072229, -0.0490676743, -0.0613207363, -0.0735645636, -0.0857973123, -0.0980171403, -0.1102222073, -0.1224106752, -0.1345807085, -0.1467304745, -0.1588581433, -0.1709618888, -0.1830398880, -0.1950903220, -0.2071113762, -0.2191012402, -0.2310581083, -0.2429801799, -0.2548656596, -0.2667127575, -0.2785196894, -0.2902846773, -0.3020059493, -0.3136817404, -0.3253102922, -0.3368898534, -0.3484186802, -0.3598950365, -0.3713171940, -0.3826834324, -0.3939920401, -0.4052413140, -0.4164295601, -0.4275550934, -0.4386162385, -0.4496113297, -0.4605387110, -0.4713967368, -0.4821837721, -0.4928981922, -0.5035383837, -0.5141027442, -0.5245896827, -0.5349976199, -0.5453249884, -0.5555702330, -0.5657318108, -0.5758081914, -0.5857978575, -0.5956993045, -0.6055110414, -0.6152315906, -0.6248594881, -0.6343932842, -0.6438315429, -0.6531728430, -0.6624157776, -0.6715589548, -0.6806009978, -0.6895405447, -0.6983762494, -0.7071067812, -0.7157308253, -0.7242470830, -0.7326542717, -0.7409511254, -0.7491363945, -0.7572088465, -0.7651672656, -0.7730104534, -0.7807372286, -0.7883464276, -0.7958369046, -0.8032075315, -0.8104571983, -0.8175848132, -0.8245893028, -0.8314696123, -0.8382247056, -0.8448535652, -0.8513551931, -0.8577286100, -0.8639728561, -0.8700869911, -0.8760700942, -0.8819212643, -0.8876396204, -0.8932243012, -0.8986744657, -0.9039892931, -0.9091679831, -0.9142097557, -0.9191138517, -0.9238795325, -0.9285060805, -0.9329927988, -0.9373390119, -0.9415440652, -0.9456073254, -0.9495281806, -0.9533060404, -0.9569403357, -0.9604305194, -0.9637760658, -0.9669764710, -0.9700312532, -0.9729399522, -0.9757021300, -0.9783173707, -0.9807852804, -0.9831054874, -0.9852776424, -0.9873014182, -0.9891765100, -0.9909026354, -0.9924795346, -0.9939069700, -0.9951847267, -0.9963126122, -0.9972904567, -0.9981181129, -0.9987954562, -0.9993223846, -0.9996988187, -0.9999247018, -1.0000000000, -0.9999247018, -0.9996988187, -0.9993223846, -0.9987954562, -0.9981181129, -0.9972904567, -0.9963126122, -0.9951847267, -0.9939069700, -0.9924795346, -0.9909026354, -0.9891765100, -0.9873014182, -0.9852776424, -0.9831054874, -0.9807852804, -0.9783173707, -0.9757021300, -0.9729399522, -0.9700312532, -0.9669764710, -0.9637760658, -0.9604305194, -0.9569403357, -0.9533060404, -0.9495281806, -0.9456073254, -0.9415440652, -0.9373390119, -0.9329927988, -0.9285060805, -0.9238795325, -0.9191138517, -0.9142097557, -0.9091679831, -0.9039892931, -0.8986744657, -0.8932243012, -0.8876396204, -0.8819212643, -0.8760700942, -0.8700869911, -0.8639728561, -0.8577286100, -0.8513551931, -0.8448535652, -0.8382247056, -0.8314696123, -0.8245893028, -0.8175848132, -0.8104571983, -0.8032075315, -0.7958369046, -0.7883464276, -0.7807372286, -0.7730104534, -0.7651672656, -0.7572088465, -0.7491363945, -0.7409511254, -0.7326542717, -0.7242470830, -0.7157308253, -0.7071067812, -0.6983762494, -0.6895405447, -0.6806009978, -0.6715589548, -0.6624157776, -0.6531728430, -0.6438315429, -0.6343932842, -0.6248594881, -0.6152315906, -0.6055110414, -0.5956993045, -0.5857978575, -0.5758081914, -0.5657318108, -0.5555702330, -0.5453249884, -0.5349976199, -0.5245896827, -0.5141027442, -0.5035383837, -0.4928981922, -0.4821837721, -0.4713967368, -0.4605387110, -0.4496113297, -0.4386162385, -0.4275550934, -0.4164295601, -0.4052413140, -0.3939920401, -0.3826834324, -0.3713171940, -0.3598950365, -0.3484186802, -0.3368898534, -0.3253102922, -0.3136817404, -0.3020059493, -0.2902846773, -0.2785196894, -0.2667127575, -0.2548656596, -0.2429801799, -0.2310581083, -0.2191012402, -0.2071113762, -0.1950903220, -0.1830398880, -0.1709618888, -0.1588581433, -0.1467304745, -0.1345807085, -0.1224106752, -0.1102222073, -0.0980171403, -0.0857973123, -0.0735645636, -0.0613207363, -0.0490676743, -0.0368072229, -0.0245412285, -0.0122715383};
|
||||
|
||||
value_type *sin_lut[9] = {sin_lut0, sin_lut1, sin_lut2, sin_lut3, sin_lut4, sin_lut5, sin_lut6, sin_lut7, sin_lut8};
|
||||
value_type cos_lut0[1] = {1};
|
||||
|
||||
value_type cos_lut1[2] = {1, 0.0000000000};
|
||||
|
||||
value_type cos_lut2[4] = {1, 0.7071067812, 0.0000000000, -0.7071067812};
|
||||
|
||||
value_type cos_lut3[8] = {1, 0.9238795325, 0.7071067812, 0.3826834324, 0.0000000000, -0.3826834324, -0.7071067812, -0.9238795325};
|
||||
|
||||
value_type cos_lut4[16] = {1, 0.9807852804, 0.9238795325, 0.8314696123, 0.7071067812, 0.5555702330, 0.3826834324, 0.1950903220, 0.0000000000, -0.1950903220, -0.3826834324, -0.5555702330, -0.7071067812, -0.8314696123, -0.9238795325, -0.9807852804};
|
||||
|
||||
value_type cos_lut5[32] = {1, 0.9951847267, 0.9807852804, 0.9569403357, 0.9238795325, 0.8819212643, 0.8314696123, 0.7730104534, 0.7071067812, 0.6343932842, 0.5555702330, 0.4713967368, 0.3826834324, 0.2902846773, 0.1950903220, 0.0980171403, 0.0000000000, -0.0980171403, -0.1950903220, -0.2902846773, -0.3826834324, -0.4713967368, -0.5555702330, -0.6343932842, -0.7071067812, -0.7730104534, -0.8314696123, -0.8819212643, -0.9238795325, -0.9569403357, -0.9807852804, -0.9951847267};
|
||||
|
||||
value_type cos_lut6[64] = {1, 0.9987954562, 0.9951847267, 0.9891765100, 0.9807852804, 0.9700312532, 0.9569403357, 0.9415440652, 0.9238795325, 0.9039892931, 0.8819212643, 0.8577286100, 0.8314696123, 0.8032075315, 0.7730104534, 0.7409511254, 0.7071067812, 0.6715589548, 0.6343932842, 0.5956993045, 0.5555702330, 0.5141027442, 0.4713967368, 0.4275550934, 0.3826834324, 0.3368898534, 0.2902846773, 0.2429801799, 0.1950903220, 0.1467304745, 0.0980171403, 0.0490676743, 0.0000000000, -0.0490676743, -0.0980171403, -0.1467304745, -0.1950903220, -0.2429801799, -0.2902846773, -0.3368898534, -0.3826834324, -0.4275550934, -0.4713967368, -0.5141027442, -0.5555702330, -0.5956993045, -0.6343932842, -0.6715589548, -0.7071067812, -0.7409511254, -0.7730104534, -0.8032075315, -0.8314696123, -0.8577286100, -0.8819212643, -0.9039892931, -0.9238795325, -0.9415440652, -0.9569403357, -0.9700312532, -0.9807852804, -0.9891765100, -0.9951847267, -0.9987954562};
|
||||
|
||||
value_type cos_lut7[128] = {1, 0.9996988187, 0.9987954562, 0.9972904567, 0.9951847267, 0.9924795346, 0.9891765100, 0.9852776424, 0.9807852804, 0.9757021300, 0.9700312532, 0.9637760658, 0.9569403357, 0.9495281806, 0.9415440652, 0.9329927988, 0.9238795325, 0.9142097557, 0.9039892931, 0.8932243012, 0.8819212643, 0.8700869911, 0.8577286100, 0.8448535652, 0.8314696123, 0.8175848132, 0.8032075315, 0.7883464276, 0.7730104534, 0.7572088465, 0.7409511254, 0.7242470830, 0.7071067812, 0.6895405447, 0.6715589548, 0.6531728430, 0.6343932842, 0.6152315906, 0.5956993045, 0.5758081914, 0.5555702330, 0.5349976199, 0.5141027442, 0.4928981922, 0.4713967368, 0.4496113297, 0.4275550934, 0.4052413140, 0.3826834324, 0.3598950365, 0.3368898534, 0.3136817404, 0.2902846773, 0.2667127575, 0.2429801799, 0.2191012402, 0.1950903220, 0.1709618888, 0.1467304745, 0.1224106752, 0.0980171403, 0.0735645636, 0.0490676743, 0.0245412285, 0.0000000000, -0.0245412285, -0.0490676743, -0.0735645636, -0.0980171403, -0.1224106752, -0.1467304745, -0.1709618888, -0.1950903220, -0.2191012402, -0.2429801799, -0.2667127575, -0.2902846773, -0.3136817404, -0.3368898534, -0.3598950365, -0.3826834324, -0.4052413140, -0.4275550934, -0.4496113297, -0.4713967368, -0.4928981922, -0.5141027442, -0.5349976199, -0.5555702330, -0.5758081914, -0.5956993045, -0.6152315906, -0.6343932842, -0.6531728430, -0.6715589548, -0.6895405447, -0.7071067812, -0.7242470830, -0.7409511254, -0.7572088465, -0.7730104534, -0.7883464276, -0.8032075315, -0.8175848132, -0.8314696123, -0.8448535652, -0.8577286100, -0.8700869911, -0.8819212643, -0.8932243012, -0.9039892931, -0.9142097557, -0.9238795325, -0.9329927988, -0.9415440652, -0.9495281806, -0.9569403357, -0.9637760658, -0.9700312532, -0.9757021300, -0.9807852804, -0.9852776424, -0.9891765100, -0.9924795346, -0.9951847267, -0.9972904567, -0.9987954562, -0.9996988187};
|
||||
|
||||
value_type cos_lut8[256] = {1, 0.9999247018, 0.9996988187, 0.9993223846, 0.9987954562, 0.9981181129, 0.9972904567, 0.9963126122, 0.9951847267, 0.9939069700, 0.9924795346, 0.9909026354, 0.9891765100, 0.9873014182, 0.9852776424, 0.9831054874, 0.9807852804, 0.9783173707, 0.9757021300, 0.9729399522, 0.9700312532, 0.9669764710, 0.9637760658, 0.9604305194, 0.9569403357, 0.9533060404, 0.9495281806, 0.9456073254, 0.9415440652, 0.9373390119, 0.9329927988, 0.9285060805, 0.9238795325, 0.9191138517, 0.9142097557, 0.9091679831, 0.9039892931, 0.8986744657, 0.8932243012, 0.8876396204, 0.8819212643, 0.8760700942, 0.8700869911, 0.8639728561, 0.8577286100, 0.8513551931, 0.8448535652, 0.8382247056, 0.8314696123, 0.8245893028, 0.8175848132, 0.8104571983, 0.8032075315, 0.7958369046, 0.7883464276, 0.7807372286, 0.7730104534, 0.7651672656, 0.7572088465, 0.7491363945, 0.7409511254, 0.7326542717, 0.7242470830, 0.7157308253, 0.7071067812, 0.6983762494, 0.6895405447, 0.6806009978, 0.6715589548, 0.6624157776, 0.6531728430, 0.6438315429, 0.6343932842, 0.6248594881, 0.6152315906, 0.6055110414, 0.5956993045, 0.5857978575, 0.5758081914, 0.5657318108, 0.5555702330, 0.5453249884, 0.5349976199, 0.5245896827, 0.5141027442, 0.5035383837, 0.4928981922, 0.4821837721, 0.4713967368, 0.4605387110, 0.4496113297, 0.4386162385, 0.4275550934, 0.4164295601, 0.4052413140, 0.3939920401, 0.3826834324, 0.3713171940, 0.3598950365, 0.3484186802, 0.3368898534, 0.3253102922, 0.3136817404, 0.3020059493, 0.2902846773, 0.2785196894, 0.2667127575, 0.2548656596, 0.2429801799, 0.2310581083, 0.2191012402, 0.2071113762, 0.1950903220, 0.1830398880, 0.1709618888, 0.1588581433, 0.1467304745, 0.1345807085, 0.1224106752, 0.1102222073, 0.0980171403, 0.0857973123, 0.0735645636, 0.0613207363, 0.0490676743, 0.0368072229, 0.0245412285, 0.0122715383, 0.0000000000, -0.0122715383, -0.0245412285, -0.0368072229, -0.0490676743, -0.0613207363, -0.0735645636, -0.0857973123, -0.0980171403, -0.1102222073, -0.1224106752, -0.1345807085, -0.1467304745, -0.1588581433, -0.1709618888, -0.1830398880, -0.1950903220, -0.2071113762, -0.2191012402, -0.2310581083, -0.2429801799, -0.2548656596, -0.2667127575, -0.2785196894, -0.2902846773, -0.3020059493, -0.3136817404, -0.3253102922, -0.3368898534, -0.3484186802, -0.3598950365, -0.3713171940, -0.3826834324, -0.3939920401, -0.4052413140, -0.4164295601, -0.4275550934, -0.4386162385, -0.4496113297, -0.4605387110, -0.4713967368, -0.4821837721, -0.4928981922, -0.5035383837, -0.5141027442, -0.5245896827, -0.5349976199, -0.5453249884, -0.5555702330, -0.5657318108, -0.5758081914, -0.5857978575, -0.5956993045, -0.6055110414, -0.6152315906, -0.6248594881, -0.6343932842, -0.6438315429, -0.6531728430, -0.6624157776, -0.6715589548, -0.6806009978, -0.6895405447, -0.6983762494, -0.7071067812, -0.7157308253, -0.7242470830, -0.7326542717, -0.7409511254, -0.7491363945, -0.7572088465, -0.7651672656, -0.7730104534, -0.7807372286, -0.7883464276, -0.7958369046, -0.8032075315, -0.8104571983, -0.8175848132, -0.8245893028, -0.8314696123, -0.8382247056, -0.8448535652, -0.8513551931, -0.8577286100, -0.8639728561, -0.8700869911, -0.8760700942, -0.8819212643, -0.8876396204, -0.8932243012, -0.8986744657, -0.9039892931, -0.9091679831, -0.9142097557, -0.9191138517, -0.9238795325, -0.9285060805, -0.9329927988, -0.9373390119, -0.9415440652, -0.9456073254, -0.9495281806, -0.9533060404, -0.9569403357, -0.9604305194, -0.9637760658, -0.9669764710, -0.9700312532, -0.9729399522, -0.9757021300, -0.9783173707, -0.9807852804, -0.9831054874, -0.9852776424, -0.9873014182, -0.9891765100, -0.9909026354, -0.9924795346, -0.9939069700, -0.9951847267, -0.9963126122, -0.9972904567, -0.9981181129, -0.9987954562, -0.9993223846, -0.9996988187, -0.9999247018};
|
||||
|
||||
value_type *cos_lut[9] = {cos_lut0, cos_lut1, cos_lut2, cos_lut3, cos_lut4, cos_lut5, cos_lut6, cos_lut7, cos_lut8};
|
||||
|
||||
|
||||
value_type lookup_sin(int layer, int element) {
|
||||
return sin_lut[layer][element];
|
||||
}
|
||||
|
||||
value_type lookup_cos(int layer, int element) {
|
||||
return cos_lut[layer][element];
|
||||
}
|
9
src/lut.h
Normal file
9
src/lut.h
Normal file
|
@ -0,0 +1,9 @@
|
|||
#ifndef LUT_H
|
||||
#define LUT_H
|
||||
|
||||
#include "fft_config.h"
|
||||
|
||||
value_type lookup_sin(int layer, int element);
|
||||
value_type lookup_cos(int layer, int element);
|
||||
|
||||
#endif // LUT_H
|
222
src/main.cpp
Normal file
222
src/main.cpp
Normal file
|
@ -0,0 +1,222 @@
|
|||
#include <Arduino.h>
|
||||
|
||||
#include <WiFi.h>
|
||||
#include <WiFiMulti.h>
|
||||
|
||||
#include <AutoAnalogAudio.h>
|
||||
|
||||
#include <ArduinoOTA.h>
|
||||
|
||||
#include <SPIFFS.h>
|
||||
|
||||
#include "Config.h"
|
||||
#include "fft_config.h"
|
||||
//#include "httpserver.h"
|
||||
|
||||
extern "C" {
|
||||
#include "fft.h"
|
||||
}
|
||||
|
||||
#define ENDLESS_LOOP() while(true) { delay(100); }
|
||||
|
||||
#define OUTPUT_INTERVAL 1000 // milliseconds
|
||||
|
||||
#define SAMPLES_PER_BLOCK 512
|
||||
|
||||
static WiFiMulti wiFiMulti;
|
||||
static bool wiFiConnectedToStation;
|
||||
|
||||
static AutoAnalog recorder;
|
||||
|
||||
// too large for the stack
|
||||
static value_type timedomain[SAMPLES_PER_BLOCK];
|
||||
static value_type fft_re[BLOCK_LEN], fft_im[BLOCK_LEN], fft_abs[BLOCK_LEN];
|
||||
|
||||
void wifi_setup(void)
|
||||
{
|
||||
// Connect the WiFi network (or start an AP if that doesn't work)
|
||||
for (auto &net : Config::instance().getWLANList())
|
||||
{
|
||||
Serial.print(F("Adding network "));
|
||||
Serial.println(net.ssid.c_str());
|
||||
wiFiMulti.addAP(net.ssid.c_str(), net.password.c_str());
|
||||
}
|
||||
|
||||
Serial.println(F("Trying to connect for 5 Minutes..."));
|
||||
|
||||
WiFi.setHostname("loudness");
|
||||
WiFi.mode(WIFI_STA);
|
||||
//WiFi.setSleepMode(WIFI_MODEM_SLEEP);
|
||||
|
||||
wiFiConnectedToStation = true; // assume the best
|
||||
|
||||
bool led_on = true;
|
||||
for(size_t tries = 0; tries < 3000; tries++)
|
||||
{
|
||||
if(wiFiMulti.run() == WL_CONNECTED) {
|
||||
Serial.println(F(""));
|
||||
Serial.println(F("WiFi connected"));
|
||||
Serial.println(F("IP address: "));
|
||||
Serial.println(WiFi.localIP());
|
||||
break;
|
||||
}
|
||||
|
||||
led_on = !led_on;
|
||||
digitalWrite(LED_BUILTIN, led_on);
|
||||
delay(100);
|
||||
|
||||
Serial.print(F("."));
|
||||
}
|
||||
|
||||
if(WiFi.status() != WL_CONNECTED) {
|
||||
Serial.println(F("Connection failed, setting up access point..."));
|
||||
|
||||
wiFiConnectedToStation = false;
|
||||
|
||||
IPAddress apIP(192, 168, 42, 1);
|
||||
|
||||
WiFi.mode(WIFI_AP);
|
||||
WiFi.softAPConfig(apIP, apIP, IPAddress(255, 255, 255, 0));
|
||||
WiFi.softAP("loudness", "dB(A)");
|
||||
WiFi.enableAP(true);
|
||||
|
||||
digitalWrite(LED_BUILTIN, false); // LED ON (active low)
|
||||
} else {
|
||||
digitalWrite(LED_BUILTIN, true); // LED OFF (active low)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(115200);
|
||||
|
||||
pinMode(LED_BUILTIN, OUTPUT);
|
||||
|
||||
Serial.println(F("Hello World!"));
|
||||
|
||||
Serial.println(F("Initializing LittleFS…"));
|
||||
|
||||
if(!SPIFFS.begin()) {
|
||||
Serial.println(F("LittleFS setup failed!"));
|
||||
ENDLESS_LOOP();
|
||||
}
|
||||
|
||||
Config::instance().load();
|
||||
|
||||
Serial.println(F("Initializing WiFi…"));
|
||||
|
||||
wifi_setup();
|
||||
|
||||
//Serial.println(F("Initializing HTTP Server…"));
|
||||
|
||||
//httpserver_setup();
|
||||
|
||||
//Serial.println(F("Testing display…"));
|
||||
|
||||
//epaper_test();
|
||||
|
||||
Serial.println(F("Initialization routine complete."));
|
||||
|
||||
init_fft();
|
||||
|
||||
// start sampling
|
||||
recorder.enableAdcChannel(6);
|
||||
recorder.begin(true, false);
|
||||
recorder.autoAdjust = 0; //Disable auto adjust of timers
|
||||
recorder.adcBitsPerSample = 12;
|
||||
recorder.setSampleRate(48000, false);
|
||||
|
||||
recorder.getADC(SAMPLES_PER_BLOCK);
|
||||
}
|
||||
|
||||
void loop() {
|
||||
static uint32_t last_output_time = 0;
|
||||
static uint32_t nsamples = 0;
|
||||
|
||||
static value_type total_energy_0_to_200_hz = 0.0f;
|
||||
static value_type total_energy_200_to_3500_hz = 0.0f;
|
||||
static value_type total_energy_3500_to_8000_hz = 0.0f;
|
||||
static value_type total_energy_8000_to_20000_hz = 0.0f;
|
||||
|
||||
wiFiMulti.run(); // maintain the WiFi connection
|
||||
|
||||
recorder.getADC(SAMPLES_PER_BLOCK);
|
||||
|
||||
// convert to Volt (float)
|
||||
for(size_t i = 0; i < SAMPLES_PER_BLOCK; i++) {
|
||||
timedomain[i] = (value_type)recorder.adcBuffer16[i] / 4096.0f * 3.30f;
|
||||
}
|
||||
|
||||
// calculate average value
|
||||
value_type avg = 0;
|
||||
for(size_t i = 0; i < SAMPLES_PER_BLOCK; i++) {
|
||||
avg += timedomain[i];
|
||||
}
|
||||
|
||||
avg /= SAMPLES_PER_BLOCK;
|
||||
|
||||
// and remove it from the data
|
||||
for(size_t i = 0; i < SAMPLES_PER_BLOCK; i++) {
|
||||
timedomain[i] -= avg;
|
||||
}
|
||||
|
||||
apply_hanning(timedomain);
|
||||
fft_transform(timedomain, fft_re, fft_im);
|
||||
complex_to_absolute(fft_re, fft_im, fft_abs);
|
||||
|
||||
value_type energy_0_to_200_hz = get_energy_density_in_band(fft_abs, 0, 200);
|
||||
value_type energy_200_to_3500_hz = get_energy_density_in_band(fft_abs, 200, 3500);
|
||||
value_type energy_3500_to_8000_hz = get_energy_density_in_band(fft_abs, 3500, 8000);
|
||||
value_type energy_8000_to_20000_hz = get_energy_density_in_band(fft_abs, 8000, 20000);
|
||||
|
||||
total_energy_0_to_200_hz += energy_0_to_200_hz;
|
||||
total_energy_200_to_3500_hz += energy_200_to_3500_hz;
|
||||
total_energy_3500_to_8000_hz += energy_3500_to_8000_hz;
|
||||
total_energy_8000_to_20000_hz += energy_8000_to_20000_hz;
|
||||
nsamples++;
|
||||
|
||||
uint32_t now = millis();
|
||||
if(now - last_output_time > OUTPUT_INTERVAL) {
|
||||
total_energy_0_to_200_hz /= nsamples;
|
||||
total_energy_200_to_3500_hz /= nsamples;
|
||||
total_energy_3500_to_8000_hz /= nsamples;
|
||||
total_energy_8000_to_20000_hz /= nsamples;
|
||||
|
||||
// calculate dBV
|
||||
value_type dBV_per_Hz_0_to_200_hz = 20*log10(total_energy_0_to_200_hz);
|
||||
value_type dBV_per_Hz_200_to_3500_hz = 20*log10(total_energy_200_to_3500_hz);
|
||||
value_type dBV_per_Hz_3500_to_8000_hz = 20*log10(total_energy_3500_to_8000_hz);
|
||||
value_type dBV_per_Hz_8000_to_20000_hz = 20*log10(total_energy_8000_to_20000_hz);
|
||||
|
||||
Serial.print(" 0 - 200 Hz [dBV/Hz]: ");
|
||||
Serial.println(dBV_per_Hz_0_to_200_hz);
|
||||
Serial.print(" 200 - 3500 Hz [dBV/Hz]: ");
|
||||
Serial.println(dBV_per_Hz_200_to_3500_hz);
|
||||
Serial.print(" 3500 - 8000 Hz [dBV/Hz]: ");
|
||||
Serial.println(dBV_per_Hz_3500_to_8000_hz);
|
||||
Serial.print(" 8000 - 20000 Hz [dBV/Hz]: ");
|
||||
Serial.println(dBV_per_Hz_8000_to_20000_hz);
|
||||
|
||||
Serial.println();
|
||||
|
||||
// TODO: send the data to graphite
|
||||
|
||||
total_energy_0_to_200_hz = 0.0f;
|
||||
total_energy_200_to_3500_hz = 0.0f;
|
||||
total_energy_3500_to_8000_hz = 0.0f;
|
||||
total_energy_8000_to_20000_hz = 0.0f;
|
||||
nsamples = 0;
|
||||
|
||||
last_output_time = now;
|
||||
}
|
||||
|
||||
//Serial.println(analogRead(A6));
|
||||
|
||||
/*unsigned long now = millis();
|
||||
if((now - displayLastUpdateTime) >= DISPLAY_UPDATE_INTERVAL) {
|
||||
Serial.println(F("Sending HTTP request…"));
|
||||
|
||||
displayLastUpdateTime = now;
|
||||
}*/
|
||||
}
|
Loading…
Reference in a new issue