Teensy 3.2 Sound Level Meter (sound measurement device)

Status
Not open for further replies.

Marcus

Member
Hi, I have been working for some time now on creating a sound level meter using the Teensy 3.2 (since it is perfect for this application). A SLM can be used for measuring sound pressure levels and reporting them an an A-weighted dB(sound pressure level), which is the NIOSH standard for measuring sound. At the moment it seems to be accurate to around 1-3 dB, but I am sure it can be improved (hoping for a little help from all you experts out there). I am hoping that this code will be good enough for people to be able to use for sound measurement with audio equipment, or for safety monitoring. I have built off the FFT library and used a lot of help from an open MIT course (http://alumni.media.mit.edu/~dlanman/courses/decibel_meter.pdf). I have a few questions (and I am sure I have made some mistakes) about my code.
First: Here is my code

Code:
/* This program first computes a 1024 point FFT using the Audio Library provided by Pual Stoffregen. It then applies an a-weighting to the samples, sums them, 
 *  then converts to dB SPL. Here, I have used the ADC for the microphone input instead of the audio shield. The Audio design tool provided by PJRC can be used to set up the 
 *  audio connection. The microphone ciruit I used can be found at http://electronics.stackexchange.com/questions/16595/how-to-make-a-clean-amplified-microphone-analog-to-digital-conversion 
 *  and is designed by Olin Lathrop I replaced R7 and R8 with 47K resistors. I also used the circuit diagram in the Audio design tool on PJRC (under the ADC tab there is a sample circuit). To provide a DC offset of .6V. 
 */
 
#include <Audio.h>
#include <Wire.h> 
#include <SPI.h>
#include <SD.h>
#include <SerialFlash.h>
#define GREEN 10
float n;
int i;
float v[512] = {0};
float magnitude = 0;
float dB_holder;
int db_int;
float a_weight[512] = {0.000491601, 0.007439144, 0.026456683, 0.057237193, 0.097648235, 0.145530499, 0.19895028, 0.256192702, 0.315753433, 0.376341431, 0.436880336, 0.496502258, 0.554533348, 0.610473237, 0.663971116, 0.714800959, 0.762837753, 0.808035908, 0.85041046, 0.890021233, 0.926959868, 0.961339445, 0.993286373, 1.022934171, 1.050418819, 1.075875354, 1.099435459, 1.12122582, 1.141367062, 1.159973138, 1.177151032, 1.193000704, 1.207615207, 1.221080906, 1.233477786, 1.244879798, 1.255355228, 1.264967081, 1.273773452, 1.281827897, 1.289179783, 1.29587462, 1.301954369, 1.307457742, 1.312420463, 1.316875521, 1.320853401, 1.324382291, 1.327488281, 1.330195534, 1.332526449, 1.334501812, 1.336140927, 1.337461742, 1.338480956, 1.339214128, 1.339675764, 1.339879407, 1.33983771, 1.33956251, 1.339064892, 1.338355246, 1.337443324, 1.336338287, 1.33504875, 1.333582824, 1.331948154, 1.330151954, 1.328201037, 1.326101843, 1.323860472, 1.3214827, 1.318974007, 1.316339599, 1.313584419, 1.310713175, 1.307730349, 1.304640214, 1.301446848, 1.298154147, 1.294765835, 1.291285478, 1.28771649, 1.284062146, 1.280325589, 1.276509835, 1.272617788, 1.268652238, 1.264615874, 1.260511287, 1.256340974, 1.252107348, 1.247812737, 1.243459393, 1.239049492, 1.234585143, 1.230068386, 1.2255012, 1.220885501, 1.216223152, 1.211515958, 1.206765674, 1.201974005, 1.19714261, 1.1922731, 1.187367045, 1.182425973, 1.177451372, 1.172444693, 1.167407348, 1.162340715, 1.157246139, 1.152124932, 1.146978373, 1.141807712, 1.136614169, 1.131398936, 1.126163178, 1.120908033, 1.115634612, 1.110344003, 1.105037268, 1.099715447, 1.094379556, 1.08903059, 1.083669521, 1.078297301, 1.072914859, 1.067523108, 1.062122937, 1.05671522, 1.05130081, 1.045880542, 1.040455233, 1.035025683, 1.029592675, 1.024156975, 1.018719333, 1.013280482, 1.00784114, 1.00240201, 0.996963778, 0.991527118, 0.986092686, 0.980661126, 0.975233068, 0.969809127, 0.964389904, 0.958975988, 0.953567954, 0.948166364, 0.942771769, 0.937384705, 0.932005696, 0.926635255, 0.921273883, 0.915922069, 0.91058029, 0.905249011, 0.899928687, 0.894619763, 0.88932267, 0.88403783, 0.878765656, 0.873506548, 0.868260896, 0.863029082, 0.857811477, 0.852608441, 0.847420326, 0.842247473, 0.837090216, 0.831948877, 0.826823771, 0.821715204, 0.816623471, 0.811548862, 0.806491654, 0.80145212, 0.796430522, 0.791427115, 0.786442146, 0.781475853, 0.776528467, 0.771600212, 0.766691304, 0.761801951, 0.756932355, 0.752082709, 0.747253202, 0.742444013, 0.737655316, 0.732887277, 0.728140056, 0.723413808, 0.71870868, 0.714024813, 0.709362343, 0.704721397, 0.700102099, 0.695504567, 0.690928912, 0.686375241, 0.681843653, 0.677334244, 0.672847104, 0.668382317, 0.663939963, 0.659520116, 0.655122846, 0.650748219, 0.646396293, 0.642067124, 0.637760764, 0.633477258, 0.629216649, 0.624978975, 0.620764269, 0.616572561, 0.612403877, 0.608258238, 0.604135661, 0.600036161, 0.595959749, 0.59190643, 0.587876209, 0.583869084, 0.579885053, 0.575924108, 0.571986239, 0.568071433, 0.564179674, 0.560310942, 0.556465216, 0.552642469, 0.548842674, 0.5450658, 0.541311815, 0.537580682, 0.533872363, 0.530186816, 0.526524, 0.522883867, 0.519266371, 0.51567146, 0.512099084, 0.508549187, 0.505021714, 0.501516605, 0.498033801, 0.49457324, 0.491134857, 0.487718587, 0.484324362, 0.480952113, 0.47760177, 0.47427326, 0.47096651, 0.467681443, 0.464417985, 0.461176056, 0.457955577, 0.454756467, 0.451578645, 0.448422028, 0.445286531, 0.442172069, 0.439078556, 0.436005904, 0.432954025, 0.429922829, 0.426912226, 0.423922125, 0.420952434, 0.41800306, 0.41507391, 0.412164889, 0.409275902, 0.406406853, 0.403557647, 0.400728185, 0.397918372, 0.395128108, 0.392357295, 0.389605834, 0.386873625, 0.384160569, 0.381466565, 0.378791512, 0.37613531, 0.373497856, 0.37087905, 0.368278789, 0.36569697, 0.363133492, 0.360588252, 0.358061147, 0.355552074, 0.353060929, 0.35058761, 0.348132012, 0.345694033, 0.343273569, 0.340870517, 0.338484772, 0.336116231, 0.333764791, 0.331430348, 0.329112798, 0.326812038, 0.324527964, 0.322260474, 0.320009464, 0.31777483, 0.315556471, 0.313354282, 0.311168162, 0.308998008, 0.306843717, 0.304705188, 0.302582319, 0.300475007, 0.298383152, 0.296306653, 0.294245408, 0.292199316, 0.290168278, 0.288152193, 0.286150961, 0.284164484, 0.28219266, 0.280235393, 0.278292582, 0.276364131, 0.27444994, 0.272549913, 0.270663953, 0.268791961, 0.266933843, 0.265089501, 0.263258841, 0.261441767, 0.259638183, 0.257847996, 0.256071111, 0.254307435, 0.252556875, 0.250819337, 0.249094729, 0.247382959, 0.245683935, 0.243997567, 0.242323763, 0.240662434, 0.239013489, 0.23737684, 0.235752397, 0.234140071, 0.232539776, 0.230951422, 0.229374924, 0.227810195, 0.226257148, 0.224715697, 0.223185759, 0.221667247, 0.220160077, 0.218664167, 0.217179432, 0.215705789, 0.214243158, 0.212791454, 0.211350598, 0.209920507, 0.208501103, 0.207092304, 0.205694032, 0.204306207, 0.202928752, 0.201561587, 0.200204635, 0.19885782, 0.197521065, 0.196194293, 0.19487743, 0.193570399, 0.192273127, 0.19098554, 0.189707563, 0.188439124, 0.187180149, 0.185930567, 0.184690306, 0.183459294, 0.182237461, 0.181024737, 0.179821051, 0.178626335, 0.177440519, 0.176263535, 0.175095315, 0.173935792, 0.172784898, 0.171642567, 0.170508733, 0.16938333, 0.168266293, 0.167157558, 0.166057059, 0.164964734, 0.163880519, 0.162804351, 0.161736168, 0.160675908, 0.159623508, 0.158578909, 0.157542048, 0.156512867, 0.155491306, 0.154477304, 0.153470803, 0.152471745, 0.151480071, 0.150495724, 0.149518647, 0.148548783, 0.147586076, 0.146630469, 0.145681907, 0.144740336, 0.143805699, 0.142877944, 0.141957016, 0.141042862, 0.140135428, 0.139234663, 0.138340513, 0.137452928, 0.136571854, 0.135697243, 0.134829041, 0.133967201, 0.133111671, 0.132262402, 0.131419345, 0.130582451, 0.129751671, 0.128926959, 0.128108265, 0.127295544, 0.126488747, 0.125687829, 0.124892743, 0.124103444, 0.123319885, 0.122542022, 0.121769811, 0.121003206, 0.120242164, 0.119486641, 0.118736594, 0.117991979, 0.117252754, 0.116518877, 0.115790306, 0.115066999, 0.114348914, 0.113636011, 0.112928249, 0.112225587, 0.111527986, 0.110835406, 0.110147807, 0.109465151, 0.108787398, 0.108114511, 0.10744645, 0.106783179, 0.106124659, 0.105470853, 0.104821725, 0.104177238, 0.103537355, 0.10290204, 0.102271258, 0.101644973, 0.10102315, 0.100405754, 0.09979275, 0.099184104, 0.098579782, 0.09797975, 0.097383975, 0.096792423, 0.096205061, 0.095621857, 0.095042778, 0.094467792, 0.093896867, 0.093329972, 0.092767075, 0.092208144, 0.091653149, 0.09110206, 0.090554845, 0.090011475, 0.08947192, 0.088936151, 0.088404136, 0.087875849, 0.087351259, 0.086830338};

// Sample time in milliseconds
unsigned long Sampletime_ms = 1000;
unsigned long Starttime;
int l = 0;


AudioInputAnalog         adc1;           //xy=155,82
AudioAnalyzeFFT1024      fft1024_1;      //xy=348,95
AudioConnection          patchCord1(adc1, fft1024_1); //created using the Teensy Audio design GUI
//AudioSynthWaveformSine sinewave;// Generate sine wave to analyze, un-comment sinewave.frequency and sinewave.amplitude in setup
//AudioConnection patchCord1(sinewave, 0, fft1024_1, 0); //Generate input signal for test, do not change these #s


void setup() {
  AudioMemory(12);
  Serial.begin(9600);
  Wire.begin(8); //I2c communication w/ Arduino
  Wire.onRequest(requestEvent); //I2C communication with Arduino
  fft1024_1.windowFunction(AudioWindowHanning1024);
  pinMode( GREEN, OUTPUT); //toggle led after each send to arduino
  //sinewave.amplitude(0.4); // From 0 at min to 1 at max
  //sinewave.frequency(1000.0); //Anywhere from 0 to 20kHz
}

void loop() 
{ 
  magnitude = 0;
  dB_holder = 0;
  
  //get the current time;
  Starttime = millis();
  
  while((millis() - Starttime) < Sampletime_ms){
    if (fft1024_1.available()) {
      for (i=0; i<511; i++) {
        n = fft1024_1.read(i);
        n = n * a_weight[i];
        v[i] = n;
        v[i] = 0.001953125 * pow(v[i],2); // 1/512 samples = .0019....
        magnitude = v[i] + magnitude;
      }
      magnitude = db(magnitude);
      dB_holder = dB_holder + magnitude;
      magnitude = 0;
      ++l; 
    }
  }
  dB_holder=dB_holder/l;
  db_int = (int) dB_holder;
  Serial.println(db_int);
  l = 0;
}

float db(float n) {
   return log10f(n) * 10.0f + 125; 
   }
                   
void requestEvent() { //I2C communiation with Arduino. I am using the Arduino as a central hub for attaching many other types of sensors, including this one.
  byte myArray[1]; 
  myArray[0] = db_int;
  Wire.write(myArray, 1);
  digitalWrite(GREEN, HIGH);
  delay(100);
  digitalWrite(GREEN, LOW);
}

As you can see I have made a lookup table for the A-weighting and it is rather long. In the future I will make it a separate header file, but at the moment this works.
My First question I have is what the sample length of the FFT function is. I have assumed that it is 512, because in the Hanning window Paul normalizes with this number (1/512). Is this correct? If this is true would the sample time period be then 512/44.1k = .0116s? I use this number when I am summing the individual magnitudes. The only reason I ask is because I would like to make a "slow" response time of 1s, so instead of changing the FFT sample number, I just run the regular loop over 1 second and average the dB levels over that period. I do not think this is the best way to do the sampling. My second question is whether I am correctly applying the weighting filter. Using the generated sine wave, it seems to respond correctly when changing the frequency while keeping the intensity at the same level. It also seems to respond well with the microphone and a produced noise, until I get into higher frequencies and I begin to see attenuation of the signal, which might very well just be the microphone and amplifying circuit (in which case I will change the A-weighting table to include a linearizing correction factor for the microphone input.) I also decided to sum all the real valued input signals (1/N(magnitude)^2) instead of 1/2 of them because I felt wierd excluding half of the sample data. Any help would be very much appreciated, and if there is something I can do to help make this code more usable for someone else, please let me know.
 
I realize that it may be hard to calibrate to dBspl if you do not use the same microphone I use. I am wondering how accurate it would be to calibrate based off of the microphones given sensitivity in the data sheets. If someone reading this would like to use the same microphone I am using, it is the electret taken off of the Adafruit max4466 breakout board. I decided to use my own amplifying circuit because the Adafruit circuit seems to have a large drop off in gain at any frequency above 8kHz. The microphone itself fairly linear, so I used it.
 
Taken this code and simplified it, made some changes as the SPL calculation was off.. noise floor is a bit higher than I would expect from 13 bit, but otherwise it works great. Trying to make this into a 8x octave band SPL meter, with 1000ms or 125ms averaging options. Comments and tips are highly appreciated:


Code:
/* Uses ADC1 as analog audio input, computes a 1024 point single sided spectrum using FFT1024 in the Audio Library provided by Pual Stoffregen. 
 *  It then applies an a-weighting to the 512 single sided spectum bins, 
 *  It sums the squareroot of the frequency bins, and squares it again after the suming of all freqeuncy bins is complete. 
 *  It then takes the 20 * Log10 to obtaine  dBA SPL figure
 *  For testing I used a Panasonic wm-34a electret, fed from the 3.3V, through a 4k7 resistor. Signal output was taken from the 4k7 resitor via a 1uF
 *  capacitor to pin 16 (a.k.a A2). It callibrated to 94.04dB and 113.97dB with a B&K type 4231 callibrator, settles to 69.2dB without sound (noise floor)
 *  Thijs Schrama®04-05-2019
 */
 
#include <Audio.h>
#include <Wire.h> 
#include <SD.h> 

int i;
float v[512] = {0};
float magnitude = 0;
float dB_holder;
float a_weight[512] = {0.000491601, 0.007439144, 0.026456683, 0.057237193, 0.097648235, 0.145530499, 0.19895028, 0.256192702, 0.315753433, 0.376341431, 0.436880336, 0.496502258, 0.554533348, 0.610473237, 0.663971116, 0.714800959, 0.762837753, 0.808035908, 0.85041046, 0.890021233, 0.926959868, 0.961339445, 0.993286373, 1.022934171, 1.050418819, 1.075875354, 1.099435459, 1.12122582, 1.141367062, 1.159973138, 1.177151032, 1.193000704, 1.207615207, 1.221080906, 1.233477786, 1.244879798, 1.255355228, 1.264967081, 1.273773452, 1.281827897, 1.289179783, 1.29587462, 1.301954369, 1.307457742, 1.312420463, 1.316875521, 1.320853401, 1.324382291, 1.327488281, 1.330195534, 1.332526449, 1.334501812, 1.336140927, 1.337461742, 1.338480956, 1.339214128, 1.339675764, 1.339879407, 1.33983771, 1.33956251, 1.339064892, 1.338355246, 1.337443324, 1.336338287, 1.33504875, 1.333582824, 1.331948154, 1.330151954, 1.328201037, 1.326101843, 1.323860472, 1.3214827, 1.318974007, 1.316339599, 1.313584419, 1.310713175, 1.307730349, 1.304640214, 1.301446848, 1.298154147, 1.294765835, 1.291285478, 1.28771649, 1.284062146, 1.280325589, 1.276509835, 1.272617788, 1.268652238, 1.264615874, 1.260511287, 1.256340974, 1.252107348, 1.247812737, 1.243459393, 1.239049492, 1.234585143, 1.230068386, 1.2255012, 1.220885501, 1.216223152, 1.211515958, 1.206765674, 1.201974005, 1.19714261, 1.1922731, 1.187367045, 1.182425973, 1.177451372, 1.172444693, 1.167407348, 1.162340715, 1.157246139, 1.152124932, 1.146978373, 1.141807712, 1.136614169, 1.131398936, 1.126163178, 1.120908033, 1.115634612, 1.110344003, 1.105037268, 1.099715447, 1.094379556, 1.08903059, 1.083669521, 1.078297301, 1.072914859, 1.067523108, 1.062122937, 1.05671522, 1.05130081, 1.045880542, 1.040455233, 1.035025683, 1.029592675, 1.024156975, 1.018719333, 1.013280482, 1.00784114, 1.00240201, 0.996963778, 0.991527118, 0.986092686, 0.980661126, 0.975233068, 0.969809127, 0.964389904, 0.958975988, 0.953567954, 0.948166364, 0.942771769, 0.937384705, 0.932005696, 0.926635255, 0.921273883, 0.915922069, 0.91058029, 0.905249011, 0.899928687, 0.894619763, 0.88932267, 0.88403783, 0.878765656, 0.873506548, 0.868260896, 0.863029082, 0.857811477, 0.852608441, 0.847420326, 0.842247473, 0.837090216, 0.831948877, 0.826823771, 0.821715204, 0.816623471, 0.811548862, 0.806491654, 0.80145212, 0.796430522, 0.791427115, 0.786442146, 0.781475853, 0.776528467, 0.771600212, 0.766691304, 0.761801951, 0.756932355, 0.752082709, 0.747253202, 0.742444013, 0.737655316, 0.732887277, 0.728140056, 0.723413808, 0.71870868, 0.714024813, 0.709362343, 0.704721397, 0.700102099, 0.695504567, 0.690928912, 0.686375241, 0.681843653, 0.677334244, 0.672847104, 0.668382317, 0.663939963, 0.659520116, 0.655122846, 0.650748219, 0.646396293, 0.642067124, 0.637760764, 0.633477258, 0.629216649, 0.624978975, 0.620764269, 0.616572561, 0.612403877, 0.608258238, 0.604135661, 0.600036161, 0.595959749, 0.59190643, 0.587876209, 0.583869084, 0.579885053, 0.575924108, 0.571986239, 0.568071433, 0.564179674, 0.560310942, 0.556465216, 0.552642469, 0.548842674, 0.5450658, 0.541311815, 0.537580682, 0.533872363, 0.530186816, 0.526524, 0.522883867, 0.519266371, 0.51567146, 0.512099084, 0.508549187, 0.505021714, 0.501516605, 0.498033801, 0.49457324, 0.491134857, 0.487718587, 0.484324362, 0.480952113, 0.47760177, 0.47427326, 0.47096651, 0.467681443, 0.464417985, 0.461176056, 0.457955577, 0.454756467, 0.451578645, 0.448422028, 0.445286531, 0.442172069, 0.439078556, 0.436005904, 0.432954025, 0.429922829, 0.426912226, 0.423922125, 0.420952434, 0.41800306, 0.41507391, 0.412164889, 0.409275902, 0.406406853, 0.403557647, 0.400728185, 0.397918372, 0.395128108, 0.392357295, 0.389605834, 0.386873625, 0.384160569, 0.381466565, 0.378791512, 0.37613531, 0.373497856, 0.37087905, 0.368278789, 0.36569697, 0.363133492, 0.360588252, 0.358061147, 0.355552074, 0.353060929, 0.35058761, 0.348132012, 0.345694033, 0.343273569, 0.340870517, 0.338484772, 0.336116231, 0.333764791, 0.331430348, 0.329112798, 0.326812038, 0.324527964, 0.322260474, 0.320009464, 0.31777483, 0.315556471, 0.313354282, 0.311168162, 0.308998008, 0.306843717, 0.304705188, 0.302582319, 0.300475007, 0.298383152, 0.296306653, 0.294245408, 0.292199316, 0.290168278, 0.288152193, 0.286150961, 0.284164484, 0.28219266, 0.280235393, 0.278292582, 0.276364131, 0.27444994, 0.272549913, 0.270663953, 0.268791961, 0.266933843, 0.265089501, 0.263258841, 0.261441767, 0.259638183, 0.257847996, 0.256071111, 0.254307435, 0.252556875, 0.250819337, 0.249094729, 0.247382959, 0.245683935, 0.243997567, 0.242323763, 0.240662434, 0.239013489, 0.23737684, 0.235752397, 0.234140071, 0.232539776, 0.230951422, 0.229374924, 0.227810195, 0.226257148, 0.224715697, 0.223185759, 0.221667247, 0.220160077, 0.218664167, 0.217179432, 0.215705789, 0.214243158, 0.212791454, 0.211350598, 0.209920507, 0.208501103, 0.207092304, 0.205694032, 0.204306207, 0.202928752, 0.201561587, 0.200204635, 0.19885782, 0.197521065, 0.196194293, 0.19487743, 0.193570399, 0.192273127, 0.19098554, 0.189707563, 0.188439124, 0.187180149, 0.185930567, 0.184690306, 0.183459294, 0.182237461, 0.181024737, 0.179821051, 0.178626335, 0.177440519, 0.176263535, 0.175095315, 0.173935792, 0.172784898, 0.171642567, 0.170508733, 0.16938333, 0.168266293, 0.167157558, 0.166057059, 0.164964734, 0.163880519, 0.162804351, 0.161736168, 0.160675908, 0.159623508, 0.158578909, 0.157542048, 0.156512867, 0.155491306, 0.154477304, 0.153470803, 0.152471745, 0.151480071, 0.150495724, 0.149518647, 0.148548783, 0.147586076, 0.146630469, 0.145681907, 0.144740336, 0.143805699, 0.142877944, 0.141957016, 0.141042862, 0.140135428, 0.139234663, 0.138340513, 0.137452928, 0.136571854, 0.135697243, 0.134829041, 0.133967201, 0.133111671, 0.132262402, 0.131419345, 0.130582451, 0.129751671, 0.128926959, 0.128108265, 0.127295544, 0.126488747, 0.125687829, 0.124892743, 0.124103444, 0.123319885, 0.122542022, 0.121769811, 0.121003206, 0.120242164, 0.119486641, 0.118736594, 0.117991979, 0.117252754, 0.116518877, 0.115790306, 0.115066999, 0.114348914, 0.113636011, 0.112928249, 0.112225587, 0.111527986, 0.110835406, 0.110147807, 0.109465151, 0.108787398, 0.108114511, 0.10744645, 0.106783179, 0.106124659, 0.105470853, 0.104821725, 0.104177238, 0.103537355, 0.10290204, 0.102271258, 0.101644973, 0.10102315, 0.100405754, 0.09979275, 0.099184104, 0.098579782, 0.09797975, 0.097383975, 0.096792423, 0.096205061, 0.095621857, 0.095042778, 0.094467792, 0.093896867, 0.093329972, 0.092767075, 0.092208144, 0.091653149, 0.09110206, 0.090554845, 0.090011475, 0.08947192, 0.088936151, 0.088404136, 0.087875849, 0.087351259, 0.086830338};

AudioInputAnalog         adc1;
AudioAnalyzeFFT1024      fft1024_1;
AudioConnection          patchCord1(adc1, fft1024_1); //created using the Teensy Audio design GUI, comment out for testing a simulated signal

//prepare simulated signal, uncomment for testing a simulated signal
//AudioSynthWaveformSine sinewave;
//AudioConnection patchCord1(sinewave, 0, fft1024_1, 0); 

void setup() {
  analogReadResolution(16);
  AudioMemory(12);
  Serial.begin(115200);
  fft1024_1.windowFunction(AudioWindowHanning1024);

  //generate simulated signal, uncomment for testing a simulated signal
  //sinewave.amplitude(0.05);        //  0 min to 1  max
  //sinewave.frequency(1000.0);     //  Anywhere from 0 to 20000
}

void loop() 
{ 
  if (fft1024_1.available()) {
      magnitude = 0;
      dB_holder = 0;
      float v[512] = {0};
      
      for (i=0; i<512; i++) {
        v[i] = fft1024_1.read(i) * a_weight[i];
        magnitude = magnitude + sq(v[i]);
      }
      magnitude = sqrt(magnitude);
      
      
      dB_holder = log10f(magnitude) * 20  + 125.05;
      Serial.println(dB_holder,2); // f[23] = 1kHz, f[82] = 3.5kHz, f[252] = 12kHz
  }
}
 
Got the octaveband SPL meter working usethe spectrum BIN weigthing factors for each octave band. These BIN weigthing factor BTW, were squared by the OP; they were way off! So I had the sqrt them again, or type in 512 individual numbers :(

Especially in the higher bands, there is an elevated noise floor. This seems to be gereated by the FFT routine, as the floor floor is also present when I use a AudioSynthWaveformSineHires. Too bad I cann't make a 1/3rd octave SPL meter; that would require a longer FFT length.

I hope some people will try out this code and give me some feedback. these are my first step in TeensyLand :D


Code:
/* Uses ADC1 as analog audio input, computes a 1024 point single sided spectrum using FFT1024 in the Audio Library provided by Pual Stoffregen. 
 *  It then applies an a-weighting to the 512 single sided spectum bins, 
 *  It sums the squareroot of the frequency bins, and squares it again after the suming of all freqeuncy bins is complete. 
 *  It then takes the 20 * Log10 to obtain  the dBA SPL figure
 *  For testing I used a Panasonic wm-34a electret, fed from the 3.3V, through a 4k7 resistor. Signal output was taken from the 4k7 resitor via a 1uF
 *  capacitor to pin 16 (a.k.a A2). It callibrated to 94.04dB and 113.97dB with a B&K type 4231 callibrator, settles to 69.2dB without sound (noise floor)
 *    
 *  octaveband BIN numbers (@ fft1024, fs=44.1kHz) could be improve by fractional BIN weigthing:  
 *  2, 3/4, 5/8, 9/16, 17/32, 33/65 , 66/131, 132/262
 *   
 *  Thijs Schrama®04-05-2019
 */
 
#include <Audio.h>
#include <Wire.h>
#include <SPI.h>
#include <SD.h>
#include <SerialFlash.h>

// GUItool: begin automatically generated code
AudioSynthWaveformSineHires sine_hires1;    //xy=167,294
AudioInputAnalog         adc1;           //xy=191,184
AudioMixer4              mixer1;         //xy=373,182
AudioAnalyzeFFT1024      fft1024_1;      //xy=421,292
AudioConnection          patchCord1(sine_hires1, 0, mixer1, 1);
AudioConnection          patchCord2(adc1, 0, mixer1, 0);
AudioConnection          patchCord3(mixer1, fft1024_1);
// GUItool: end automatically generated code

float a_weight[] = {0.000491601, 0.007439144, 0.026456683, 0.057237193, 0.097648235, 0.145530499, 0.19895028, 0.256192702, 0.315753433, 0.376341431, 0.436880336, 0.496502258, 0.554533348, 0.610473237, 0.663971116, 0.714800959, 0.762837753, 0.808035908, 0.85041046, 0.890021233, 0.926959868, 0.961339445, 0.993286373, 1.022934171, 1.050418819, 1.075875354, 1.099435459, 1.12122582, 1.141367062, 1.159973138, 1.177151032, 1.193000704, 1.207615207, 1.221080906, 1.233477786, 1.244879798, 1.255355228, 1.264967081, 1.273773452, 1.281827897, 1.289179783, 1.29587462, 1.301954369, 1.307457742, 1.312420463, 1.316875521, 1.320853401, 1.324382291, 1.327488281, 1.330195534, 1.332526449, 1.334501812, 1.336140927, 1.337461742, 1.338480956, 1.339214128, 1.339675764, 1.339879407, 1.33983771, 1.33956251, 1.339064892, 1.338355246, 1.337443324, 1.336338287, 1.33504875, 1.333582824, 1.331948154, 1.330151954, 1.328201037, 1.326101843, 1.323860472, 1.3214827, 1.318974007, 1.316339599, 1.313584419, 1.310713175, 1.307730349, 1.304640214, 1.301446848, 1.298154147, 1.294765835, 1.291285478, 1.28771649, 1.284062146, 1.280325589, 1.276509835, 1.272617788, 1.268652238, 1.264615874, 1.260511287, 1.256340974, 1.252107348, 1.247812737, 1.243459393, 1.239049492, 1.234585143, 1.230068386, 1.2255012, 1.220885501, 1.216223152, 1.211515958, 1.206765674, 1.201974005, 1.19714261, 1.1922731, 1.187367045, 1.182425973, 1.177451372, 1.172444693, 1.167407348, 1.162340715, 1.157246139, 1.152124932, 1.146978373, 1.141807712, 1.136614169, 1.131398936, 1.126163178, 1.120908033, 1.115634612, 1.110344003, 1.105037268, 1.099715447, 1.094379556, 1.08903059, 1.083669521, 1.078297301, 1.072914859, 1.067523108, 1.062122937, 1.05671522, 1.05130081, 1.045880542, 1.040455233, 1.035025683, 1.029592675, 1.024156975, 1.018719333, 1.013280482, 1.00784114, 1.00240201, 0.996963778, 0.991527118, 0.986092686, 0.980661126, 0.975233068, 0.969809127, 0.964389904, 0.958975988, 0.953567954, 0.948166364, 0.942771769, 0.937384705, 0.932005696, 0.926635255, 0.921273883, 0.915922069, 0.91058029, 0.905249011, 0.899928687, 0.894619763, 0.88932267, 0.88403783, 0.878765656, 0.873506548, 0.868260896, 0.863029082, 0.857811477, 0.852608441, 0.847420326, 0.842247473, 0.837090216, 0.831948877, 0.826823771, 0.821715204, 0.816623471, 0.811548862, 0.806491654, 0.80145212, 0.796430522, 0.791427115, 0.786442146, 0.781475853, 0.776528467, 0.771600212, 0.766691304, 0.761801951, 0.756932355, 0.752082709, 0.747253202, 0.742444013, 0.737655316, 0.732887277, 0.728140056, 0.723413808, 0.71870868, 0.714024813, 0.709362343, 0.704721397, 0.700102099, 0.695504567, 0.690928912, 0.686375241, 0.681843653, 0.677334244, 0.672847104, 0.668382317, 0.663939963, 0.659520116, 0.655122846, 0.650748219, 0.646396293, 0.642067124, 0.637760764, 0.633477258, 0.629216649, 0.624978975, 0.620764269, 0.616572561, 0.612403877, 0.608258238, 0.604135661, 0.600036161, 0.595959749, 0.59190643, 0.587876209, 0.583869084, 0.579885053, 0.575924108, 0.571986239, 0.568071433, 0.564179674, 0.560310942, 0.556465216, 0.552642469, 0.548842674, 0.5450658, 0.541311815, 0.537580682, 0.533872363, 0.530186816, 0.526524, 0.522883867, 0.519266371, 0.51567146, 0.512099084, 0.508549187, 0.505021714, 0.501516605, 0.498033801, 0.49457324, 0.491134857, 0.487718587, 0.484324362, 0.480952113, 0.47760177, 0.47427326, 0.47096651, 0.467681443, 0.464417985, 0.461176056, 0.457955577, 0.454756467, 0.451578645, 0.448422028, 0.445286531, 0.442172069, 0.439078556, 0.436005904, 0.432954025, 0.429922829, 0.426912226, 0.423922125, 0.420952434, 0.41800306, 0.41507391, 0.412164889, 0.409275902, 0.406406853, 0.403557647, 0.400728185, 0.397918372, 0.395128108, 0.392357295, 0.389605834, 0.386873625, 0.384160569, 0.381466565, 0.378791512, 0.37613531, 0.373497856, 0.37087905, 0.368278789, 0.36569697, 0.363133492, 0.360588252, 0.358061147, 0.355552074, 0.353060929, 0.35058761, 0.348132012, 0.345694033, 0.343273569, 0.340870517, 0.338484772, 0.336116231, 0.333764791, 0.331430348, 0.329112798, 0.326812038, 0.324527964, 0.322260474, 0.320009464, 0.31777483, 0.315556471, 0.313354282, 0.311168162, 0.308998008, 0.306843717, 0.304705188, 0.302582319, 0.300475007, 0.298383152, 0.296306653, 0.294245408, 0.292199316, 0.290168278, 0.288152193, 0.286150961, 0.284164484, 0.28219266, 0.280235393, 0.278292582, 0.276364131, 0.27444994, 0.272549913, 0.270663953, 0.268791961, 0.266933843, 0.265089501, 0.263258841, 0.261441767, 0.259638183, 0.257847996, 0.256071111, 0.254307435, 0.252556875, 0.250819337, 0.249094729, 0.247382959, 0.245683935, 0.243997567, 0.242323763, 0.240662434, 0.239013489, 0.23737684, 0.235752397, 0.234140071, 0.232539776, 0.230951422, 0.229374924, 0.227810195, 0.226257148, 0.224715697, 0.223185759, 0.221667247, 0.220160077, 0.218664167, 0.217179432, 0.215705789, 0.214243158, 0.212791454, 0.211350598, 0.209920507, 0.208501103, 0.207092304, 0.205694032, 0.204306207, 0.202928752, 0.201561587, 0.200204635, 0.19885782, 0.197521065, 0.196194293, 0.19487743, 0.193570399, 0.192273127, 0.19098554, 0.189707563, 0.188439124, 0.187180149, 0.185930567, 0.184690306, 0.183459294, 0.182237461, 0.181024737, 0.179821051, 0.178626335, 0.177440519, 0.176263535, 0.175095315, 0.173935792, 0.172784898, 0.171642567, 0.170508733, 0.16938333, 0.168266293, 0.167157558, 0.166057059, 0.164964734, 0.163880519, 0.162804351, 0.161736168, 0.160675908, 0.159623508, 0.158578909, 0.157542048, 0.156512867, 0.155491306, 0.154477304, 0.153470803, 0.152471745, 0.151480071, 0.150495724, 0.149518647, 0.148548783, 0.147586076, 0.146630469, 0.145681907, 0.144740336, 0.143805699, 0.142877944, 0.141957016, 0.141042862, 0.140135428, 0.139234663, 0.138340513, 0.137452928, 0.136571854, 0.135697243, 0.134829041, 0.133967201, 0.133111671, 0.132262402, 0.131419345, 0.130582451, 0.129751671, 0.128926959, 0.128108265, 0.127295544, 0.126488747, 0.125687829, 0.124892743, 0.124103444, 0.123319885, 0.122542022, 0.121769811, 0.121003206, 0.120242164, 0.119486641, 0.118736594, 0.117991979, 0.117252754, 0.116518877, 0.115790306, 0.115066999, 0.114348914, 0.113636011, 0.112928249, 0.112225587, 0.111527986, 0.110835406, 0.110147807, 0.109465151, 0.108787398, 0.108114511, 0.10744645, 0.106783179, 0.106124659, 0.105470853, 0.104821725, 0.104177238, 0.103537355, 0.10290204, 0.102271258, 0.101644973, 0.10102315, 0.100405754, 0.09979275, 0.099184104, 0.098579782, 0.09797975, 0.097383975, 0.096792423, 0.096205061, 0.095621857, 0.095042778, 0.094467792, 0.093896867, 0.093329972, 0.092767075, 0.092208144, 0.091653149, 0.09110206, 0.090554845, 0.090011475, 0.08947192, 0.088936151, 0.088404136, 0.087875849, 0.087351259, 0.086830338};
int oct             = 0;                                   // octaveband counter
int i               = 0;                                   // freq bin counter
int n               = 0;                                   // averaging counter
int ave             = 11;                                  // nr of averages
float v[511]        = {0};                                 // bin magnitude values
float magn[]        = {0,0,0,0,0,0,0,0};                   // temporaly magnitude of 8 bands 
float magn_f[]      = {0,0,0,0,0,0,0,0};                   // final magnitude of 8 bands after averaging 
float dB_oct[]      = {0,0,0,0,0,0,0,0};                   // dB converted value of 8 bands after averaging 
int bin_low[]       = {0, 2, 5, 10, 22, 41,  83, 166 };    // lowest  BIN number to include for 8 octavebands
int bin_high[]      = {1, 3, 6, 12, 25, 50, 102, 204 };    // highest BIN number to include for 8 octavebands
float mes = 0.00;

void setup() { 
  sine_hires1.amplitude(1);     // generate a high resolution sine for testing
  sine_hires1.frequency(1000);   // set the frequency
  mixer1.gain(0, 1);            // mix in the the ADC Microphone
  mixer1.gain(1, 0);            // or mix the generated sine for testing
  fft1024_1.windowFunction(AudioWindowHanning1024); // Hanning for best, broadband, out of band, attenuation
  AudioMemory(12);
  Serial.begin(115200);
}

void loop() { 
  if (fft1024_1.available()) {
    magn[0]  = 0;                                          //reset the temporaly octavebands magnitue values to zero
    magn[1]  = 0; 
    magn[2]  = 0; 
    magn[3]  = 0; 
    magn[4]  = 0; 
    magn[5]  = 0; 
    magn[6]  = 0;
    magn[7]  = 0;
    for (oct=0; oct<8; oct++) {                               // repeat 8 times for 8 octave bands          
      for (i=bin_low[oct]; i<bin_high[oct]; i++) {            // retreive this octave BIN values and multiply each with their a_weigthing factor 
        v[i] = fft1024_1.read(i) * sqrt(a_weight[i]);
        magn[oct] = magn[oct] + sq(v[i]);                     // sum their squared value, since they are uncorrelated signals
      }
      magn[oct]   = sqrt(magn[oct]);                          // squareroot the SUM value, since they are uncorrelated signals
      magn_f[oct] = magn_f[oct] + magn[oct];                  // add value to average holder
    }    
    n      = n+1;                                             // keep track of number of averages = n
    if (n == ave) {                                           // once number of averages is reached
      Serial.println(999.99,2); // debug thingie
      for (oct=0; oct<8; oct++) {                             // repeat 8 times for 8 octave bands
        magn_f[oct]  = magn_f[oct]/ave;                       // divide by number of averages      
        dB_oct[oct]  = log10f(magn_f[oct]) * 20  + 120.20;    // convert to dB
        Serial.println(dB_oct[oct],2);
        magn_f[oct] = 0;
        dB_oct[oct] = 0;
      }
      n         = 0;                                          // reset averaging counter
    }
  }
}

and a Matlab visualistion routine :

Code:
% MATLAB code for octaveband SPL meter, works with teensy 3.6 via serial com port connection, adjust COM port for your system

clearvars
close all

dBoct = 60*ones(1,8);

figure(1)
clf
set(gcf,'Position',[317         349        1418         650])
bh1 = bar(dBoct);
grid on; grid minor;
ylim([10 121])
xlim([0.5 8.5])
ylabel 'dB]'
xlabel 'octaveband'
title 'Octaveband meter met Teensy 3.6'
set(gca,'FontSize',24)
hold on
plot([0 9],[94 94])
for n=1:8
    th(n)=text(n,100,num2str(dBoct(n)),'FontSize',20)
end
drawnow

%seriallist
s = serial('COM6', 'BaudRate', 115200);
fopen(s);
formatSpec = '%f';
disp('serial port connected')

global KEY_IS_PRESSED
KEY_IS_PRESSED = 0;
gcf
set(gcf, 'KeyPressFcn', @myKeyPressFcn)

while ~KEY_IS_PRESSED
    mes = fscanf(s,formatSpec);
    if mes == 999.99
      for n=1:8
            dBoct(n) = fscanf(s,formatSpec);
            th(n).String = num2str(dBoct(n));
      end             
      bh1.YData = dBoct;
      drawnow
    end
end

disp 'closing serial connection'
fclose(s);
clear s
disp 'closed'

function myKeyPressFcn(hObject, event)
global KEY_IS_PRESSED
KEY_IS_PRESSED  = 1;
disp('key is pressed')
end
 
Here's the Matlab figure I use to visualize the octaveband SPL meter. Note the high noisefloor for the high freq bands. The high noisefloor is also present when using a software simulated sine signal .. how's that possible?

teenst octave band SPL meter.jpg
 
Well, I found out through some measurement of raw spectra that is putout by the AudioAnalyzeFFT1024 , that it puts out a 16bit value. Now I understand that the ADC uses 16bit data, but why would the output of an FFT not be a float? Since a 1024 point FFT spreads the energy over 512 frequency bins, and the broadbandinput it 16bit, atleast 16+9=25bits are needed to avoid throwing away usefull resolution.

can the output of AudioAnalyzeFFT1024 be set to float?
 
Looking into the .cpp file that is called from the library, I see that the output of the CMSIS fft is a UNIT32, but it is squarerooted just before assigning it to the output. If I am not mistaken, if you squareroot a 32bit interger, you are left with 16bit.. hence the 16bit resolution of the AudioAnalyzeFFT1024 :(
 
I am building a wearable sound level meter for some International Year of Sound events (in 2020), sponsored by ASA. I tried out some of the code above, but couldn't get it to reliably track my Class 1 SLM, so I started from scratch with a different approach. I thought it may be of interest to you guys, even though this thread has been dormant for a few months.

First, I'm using a MEMS microphone with I2S output.

I used the GUI to build a filter bank with octave-band filters from 31.5 Hz to 8 kHz. These are fed to RMS detectors. The outputs of the RMS detectors are scaled for the A-weighting corrections, and accumulated. These are then log averaged over the measurement interval (500 ms in the code below) to produce LAeq over this interval.

I've done some experiments with the filters to check linearity with the pink noise source, and it's good enough for what I'm doing. It tracks very well with the real SLM from the low 20s up to over 100 dBA. Within 1 dB.

This will be connected to a large display that a person will be able to wear in various environments to raise awareness of sound levels, both high and low.

Code:
#include <Arduino.h>

#include <Audio.h>
#include <Wire.h>
#include <SPI.h>
#include <SD.h>
#include <SerialFlash.h>

// GUItool: begin automatically generated code
AudioSynthNoisePink      pink1;          //xy=117,268
AudioInputI2S            i2s1;           //xy=118,193
AudioMixer4              mixer1;         //xy=260,240
AudioFilterStateVariable filter31;       //xy=456,195
AudioFilterStateVariable filter63;       //xy=456,235
AudioFilterStateVariable filter125;      //xy=456,275
AudioFilterStateVariable filter250;      //xy=456,315
AudioFilterStateVariable filter500;      //xy=456,355
AudioFilterStateVariable filter1000;     //xy=456,395
AudioFilterStateVariable filter2000;     //xy=456,435
AudioFilterStateVariable filter4000;     //xy=456,475
AudioFilterStateVariable filter8000;     //xy=459,528
AudioAnalyzeRMS          rms31;          //xy=630,195
AudioAnalyzeRMS          rms63;          //xy=630,235
AudioAnalyzeRMS          rms125;         //xy=630,275
AudioAnalyzeRMS          rms250;         //xy=630,315
AudioAnalyzeRMS          rms500;         //xy=630,355
AudioAnalyzeRMS          rms1000;        //xy=630,395
AudioAnalyzeRMS          rms2000;        //xy=630,435
AudioAnalyzeRMS          rms4000;        //xy=630,475
AudioAnalyzeRMS          rms8000;        //xy=630,515
AudioConnection          patchCord1(pink1, 0, mixer1, 1);
AudioConnection          patchCord2(i2s1, 0, mixer1, 0);
AudioConnection          patchCord3(mixer1, 0, filter31, 0);
AudioConnection          patchCord4(mixer1, 0, filter63, 0);
AudioConnection          patchCord5(mixer1, 0, filter125, 0);
AudioConnection          patchCord6(mixer1, 0, filter250, 0);
AudioConnection          patchCord7(mixer1, 0, filter500, 0);
AudioConnection          patchCord8(mixer1, 0, filter1000, 0);
AudioConnection          patchCord9(mixer1, 0, filter2000, 0);
AudioConnection          patchCord10(mixer1, 0, filter4000, 0);
AudioConnection          patchCord11(mixer1, 0, filter8000, 0);
AudioConnection          patchCord12(filter31, 1, rms31, 0);
AudioConnection          patchCord13(filter63, 1, rms63, 0);
AudioConnection          patchCord14(filter125, 1, rms125, 0);
AudioConnection          patchCord15(filter250, 1, rms250, 0);
AudioConnection          patchCord16(filter500, 1, rms500, 0);
AudioConnection          patchCord17(filter1000, 1, rms1000, 0);
AudioConnection          patchCord18(filter2000, 1, rms2000, 0);
AudioConnection          patchCord19(filter4000, 1, rms4000, 0);
AudioConnection          patchCord20(filter8000, 1, rms8000, 0);
// GUItool: end automatically generated code

uint8_t prescale = 20;  // Prescaler for RMS detector output
float offset = 91;    // Microphone calibration
float Awt = 0;
float AwtAccum = 0;
float LAeq = 0;
uint8_t n = 0; // number of measurements to average
unsigned long sampletime = 500;  // Sampling interval
unsigned long starttime;

void setup(){

  AudioMemory(20);
  Serial.begin(115200);

  pink1.amplitude(0.01);  // for testing filters
  mixer1.gain(0,1);  // microphone level
  mixer1.gain(1,0);  // pink noise level


// Setup filter center frequencies and Q (1 octave)
  filter31.frequency(31.5);
  filter31.resonance(1.414);
  filter63.frequency(63);
  filter63.resonance(1.414);
  filter125.frequency(125);
  filter125.resonance(1.414);
  filter250.frequency(250);
  filter250.resonance(1.414);
  filter500.frequency(500);
  filter500.resonance(1.414);
  filter1000.frequency(1000);
  filter1000.resonance(1.414);
  filter2000.frequency(2000);
  filter2000.resonance(1.414);
  filter4000.frequency(4000);
  filter4000.resonance(1.414);
  filter8000.frequency(8000);
  filter8000.resonance(1.414);
}

void loop(){

  n = 0;
  AwtAccum = 0;
  starttime = millis();  // Get initial time

  // Loop and accumulate values during sampling interval
  while((millis() - starttime) < sampletime){

    // Wait untl data avaiable from all octave-band filters
    if (
            rms31.available() &&
            rms63.available() &&
            rms125.available() &&
            rms250.available() &&
            rms500.available() &&
            rms1000.available() &&
            rms2000.available() &&
            rms4000.available() &&
            rms8000.available()
        ){

// Apply A-weighting and accumulate squared Vrms values from each band
        Awt = 0;
        Awt += sq(rms31.read()   * prescale * 0.01071519 );  //squared Vrms
        Awt += sq(rms63.read()   * prescale * 0.04897788 );
        Awt += sq(rms125.read()  * prescale * 0.15667510 );
        Awt += sq(rms250.read()  * prescale * 0.37153523 );
        Awt += sq(rms500.read()  * prescale * 0.69183097 );
        Awt += sq(rms1000.read() * prescale              );
        Awt += sq(rms2000.read() * prescale * 1.1481536  );
        Awt += sq(rms4000.read() * prescale * 1.1220185  );
        Awt += sq(rms8000.read() * prescale * 0.8810489  );

// At this point, Awt is a sum of squared voltages.  Total voltage
// would be sqrt of this value.

        AwtAccum += Awt;  // Accumulates sums of sqaured voltages from each loop
        n++;  // Increment average counter for later averaging
      }
      delay(1);  // Won't loop without this for some reason
    }

// Power is proportional to V^2.  AwtAccum is a sum of V^2 values.
// Average power is sigma(P)/n, equivalent to sigma(V^2)/n.
// 10Log(sigma(V^2)/n) = average SPL
// offset = mic calibration

    LAeq = round(10 * log10f(AwtAccum / n) + offset);
    Serial.println(LAeq,0);  // Report 0 decimal places
}
 
The code looks elegant and simple. Do you run this on a Teensy 4? How much processor time % are you using?

Could you tell me what discrepenties you encoutered with my FFT approach?
 
It's running on a 3.2. AudioProcessorUsage() reports 25.8.

With your code, I just couldn't get linearity between levels. I didn't make notes, but if I calibrated to, say, 40 dBA and then increased the signal to 80, it didn't track well. I'm not sure why. One concern I had is that the bin size of 43 Hz is pretty course at low frequencies. I also couldn't figure out if an RMS level is calculated. Lp is of course based on RMS pressure, and thus RMS voltage. Maybe I'm just missing that in the code.

BTW, the A-weighting multipliers I'm using are 10^(L/20) where L is the standard correction in dB for each octave band.
 
The set up looks tidy. And nice to have class 1 meter.

I will go through my code again.. might have made an eroor somewhere.

Thanks for showing your project!
 
I'm part of the team that makes Tympan, which at its heart is a Teensy 3.6 with an audio codec (and bluetooth module, and LiPo battery plus charger circuit). I did a single-channel and two-channel sould level meter:

* One Chan: https://github.com/Tympan/Tympan_Library/tree/master/examples/02-Utility/SoundLevelMeter

* Two Chan: https://github.com/Tympan/Tympan_Library/tree/master/examples/02-Utility/SoundLevelMeter_2Chan

My example code uses audio classes in the Tympan_Library. You can use these classes to do A-weighting or C-weighting. You can also choose between SLOW or FAST time averaging. As a result, you've got a bit of flexibility. Do be aware, however, that these audio classes use floating point arithmetic (hence the "_F32" at the end of the class names), so you would have to use a Teensy 3.5/3.6 or 4.0.

Perhaps you'll find the software library (or the Tympan hardware) helpful as you implement your own SLM.

Chip
 
However it is that you implement the software for your sound level meter, the hard part (IMO) is calibrating the device. There are many choices:

* You can decide to use a single-point pure-tone calibration (1kHz tone at a known SPL)
* Or, you can do a single-point filtered-noise calibration (1/3rd octave filtered noise centered at 1 kHz, at a known SPL)
* Or, you could do a frequency-dependent calibration in octaves or in 1/3rd octaves (at known SPL)

Note that the enclosure that you use to house your mics will likely change the frequency response and sensitivity of the mics (and sensitivity versus angle of incidence), so be sure to calibrate the device in its final packaging.

Chip
 
Thanks, Chip. I'm an acoustics professor and consultant, and have several Class 1 SLMs and calibrators at my disposal.

Also, thanks for the link to the library. I'll take a look.
 
>> I'm an acoustics professor and consultant, and have several Class 1 SLMs and calibrators at my disposal.

Great! I have this kind of equipment, too. With this equipment, I thought that calibration would be trivial. I was wrong. My simple enclosure caused a lot of problems. Acoustic resonances and shadowing. Even once I figured out those issues, the noise generated by handling my device (or by wind on my device) was really hard to manage.

So, I'm sure that you know all this....I guess that this message is merely a gentle reminder that seemingly-simple things can be the most challenging. In my case, the SLM algorithm/software was the easy part and the enclosure/calibration proved to be the hard part. YMMV.

Chip
 
Cheers for prompt answer, I wrote a python script to generate a_weight[] variable.

Code:
import math

coefficients_number = 512
step = 43
start = 43
end = coefficients_number * step
results_array = []

print '// this file is generatet by phyton script a-curve-gen.py'
print '// a-weight curve size ',coefficients_number,' coefficients with ',step, 'Hz resolution'
print '// start: ', start, ' end: ', end, 'step: ', step
print ''

i = 0
for f in range(start, end+1, step):
    coeff = (12194**2 * f**4) / ( (f**2 + 20.6**2) * math.sqrt( (f**2 + 107.7**2) * (f**2 + 737.9**2) ) * (f**2 + 12194**2) )
    results_array.append(coeff)
    i = i + 1

# convert array to string
results_string = ', '.join([str(elem) for elem in results_array])

print 'float a_weighting_curve[512] = {'
print results_string
print '};'
 
Hello,

Just some comment from my side.

I'm not sure of what the specification are for a SLM today but have used many for over 20 years. Nowaday most are Digital, but the old A-weighting originated as an approximation to human hearing response average and then they used an LRC circuit to enable the A-weighting to be added to the old Analogue + Meter type SLMs which prevailed until 30 years back. Octave band filtering then was an analogue affair with a bolt on attachment.

I highly recommend Anders Brandts' book and free code available at his website in matlab format for all manner of acoustic calculations and DSP.
See Abravibe toolbox. http://www.abravibe.com/

It may be that your values are diverging from the commercial SLM is that the calculations method could be different.

I think that the filtering is done on a time basis, not FFT based, one problem with the Sample->FFT>A-Weight>sum method is that the weighting values are acting on the centre frequencies of the octave bands, which can deiviate significantly from a specific frequency so the weighting can be incorrect at that specific frequency.

Maybe you can do the A-weighting in a digital time filter based on the Poles-zeros transfer function of the A-weighting

So your calculation chain would be Sample->A-weight>FFT>Sum

I also usually use commercially available Acoustic calibrator with a 1kHz tone at 114dB, and 3D print a coupler for specific microphones, the calibrators are designed to compensate for the differences in the cavity volume and maintain the 114dB.

The digital microphones are widely used in industry in large mic arrays and are stable so only need an annual calibration check, they usually have a special coupler to attach to the calibrator.

Good luck with getting alignment :)
 
Status
Not open for further replies.
Back
Top