Pages: [1]   Go Down
Author Topic: Can I increase the sensitivity of the Sparkfun electret breakout board?  (Read 2399 times)
0 Members and 1 Guest are viewing this topic.
Winnipeg, MB
Offline Offline
Newbie
*
Karma: 0
Posts: 7
I swear nature made them that way.
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I am trying to create a sensor and script that can read and react to the ambient noise level in a room to use in sculpture. I am currently just trying to make it work with an LED with the intention of making more interesting reactions when the sensory issues are ironed out.

I have got the sensor registering, though it still has some random peaks and valleys that make my LED flicker. It will only register noises that are quite loud, and right beside the mic. I would like to eliminate the flickering, and make the range of the sensor much larger. I have several Electret Breakout boards(http://www.sparkfun.com/products/9964 and it seems from browsing the forum that I am not the only one who found out that these really don't seem to be much more than a glorified knock sensor.

Can I boost the signal with an amp, or perhaps the OpAmp breakouthttp://www.sparkfun.com/products/9816 to increase the sensitivity?

 I have added the code I'm using as an attachment, it seems sound, but advice is appreciated.
Code:
// sparkfun electret mic sketch

const int ledPin = 13;
const int middleValue = 512;
const int numberOfSamples = 128;

int sample;
long signal;
long averageReading;

long runningAverage=0;
const int averagedOver= 16;

const int threshold= 450;

void setup() {
  pinMode(ledPin, OUTPUT);
  Serial.begin(9600);
}

void loop(){
  long sumOfSquares = 0;
  for (int i=0; i<numberOfSamples; i++) {
    sample = analogRead(4);
    signal = (sample - middleValue);
    signal *= signal;
    sumOfSquares += signal;
  }
  averageReading = sumOfSquares/numberOfSamples;
  runningAverage=sqrt(((averagedOver-1)*runningAverage)+averageReading);
 
  if (runningAverage>threshold){
    digitalWrite(ledPin,HIGH);
  }else{
    digitalWrite(ledPin, LOW);
  }
  Serial.println(runningAverage);
}
I'm totally new to the forum, and have only been using an Arduino for a month, so bear with me.

* electret_sketch.pde (0.76 KB - downloaded 3 times.)
Logged

SF Bay Area
Offline Offline
Edison Member
*
Karma: 11
Posts: 1244
Arduino Ninja
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Yes...though it already has pretty high gain already (100x?). I guess you're trying to crank it up so high that it can peg the rails at less than room-filling music levels.

What you'll want to add is another op-amp stage with a gain that you determine either experimentally, or discover by simulating the appropriate noise level and watching the microphone output on an oscilloscope.

Another consideration: the Arduino is probably not fast enough to catch every nuance of the audio waveform, therefore making your waveform summation inaccurate. You could use another op-amp (fortunately most op-amp ICs have at least two) in the "precision rectifier" configuration. Then you can put a capacitor on the ADC line, with a bleed resistor to empty the capacitor slowly (how slowly is another experimental determination). That is how the Shifty VU Shield processes audio levels, though it needs a normal audio line level signal input instead of an electret mic.
Logged

Unique RGB LED Modules and Arduino shields: http://www.macetech.com/store

Montreal
Offline Offline
Faraday Member
**
Karma: 30
Posts: 2602
Per aspera ad astra.
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I'm little bit lost in your math:

  averageReading = sumOfSquares/numberOfSamples;

  runningAverage=sqrt(((averagedOver-1)*runningAverage)+averageReading);

You are calculating RMS and running average the same time?
What if I change it to:

averageReading = sqrt (sumOfSquares / numberOfSamples);
 
runningAverage = ((( averagedOver - 1 ) * runningAverage ) + averageReading ) / averagedOver;

Logged

Winnipeg, MB
Offline Offline
Newbie
*
Karma: 0
Posts: 7
I swear nature made them that way.
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Thanks macegr,

Unfortunately, I do not have access top an oscilloscope, and yes, I do want to be able to trigger a response at moderate volume levels.

The Sculpture I am working on is designed to be a contemplative work, and I want to make it so that it will only execute it's function when the room as below a certain volume threshold. Basically, if there is too much talking, then I want the code I'm  adding to this later to shut down. I'm thinking an if runningAverage>400 then skip loop sort of statement should do it.

If there is a better tool for the job I have a modest budget with which to buy further equipment. I looked at the shifty shield, as I recall it was recommend for one of the other posts you responded to, but I am wanting to keep the mic small, and unobtrusive. Will the sparkfun OpAmp breakout do the trick? Or do I simply need to get an LMV 358 and breadboard it? I am not yet a true hardware connoisseur but I do have capacitors and resistors lying around to test what you suggested once I get the amp worked out.

The final project is going to be a self building sculpture. If I can find a good source for electropermanent magnets. . .

Magician,

Thanks, I'll try that code out, it might help stabilise my levels.

The code is adapted from the original code in the Arduino Cook Book, but it didn't work properly, so I am tweaking it myself. The original didn't get the root after squaring the input so the numbers coming in were huge.
Logged

Winnipeg, MB
Offline Offline
Newbie
*
Karma: 0
Posts: 7
I swear nature made them that way.
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

P.S. Magician,

Your code fix worked perfectly! stabilized the numbers, and put it into a more realistic real based on the noise level of the room. And even increased the range a little. Thanks!
« Last Edit: November 24, 2011, 11:19:13 am by MossAndStone » Logged

Montreal
Offline Offline
Faraday Member
**
Karma: 30
Posts: 2602
Per aspera ad astra.
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

You are welcome. Just open a book, and unbelievable, I find your sketch on p. 183, and it really doesn't have sqrt in code. Which is a mistake, RMS value is sqrt of the sum of square divided by number of samples. There only explanation not to do sqrt is get better performance (save time), and better sensitivity, sacrifice mathematical accuracy of results.    But author is right about calculating running average, there is a division by averagedOver, which you skip in your code. You can improve performance of your code by replacing division (slow) with shifting operation:
Code:
runningAverage = ((( averagedOver - 1 ) * runningAverage ) + averageReading ) >> 4 ;
 
Logged

Manchester (England England)
Offline Offline
Brattain Member
*****
Karma: 631
Posts: 34502
Solder is electric glue
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
Basically, if there is too much talking, then I want the code I'm  adding to this later to shut down.
There was a project here a few years ago where someone was doing the opposite, for a school canteen turn on a lit notice saying "be quite" when the general noise was above a certain level. Unfortunately he reported that he found no correlation with the perceived noise and the numbers he was getting. I hope it is better the other way round. Please do report back if you get it working to your satisfaction.
Good luck.
Logged

Winnipeg, MB
Offline Offline
Newbie
*
Karma: 0
Posts: 7
I swear nature made them that way.
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hi Guys,

I had to shelve this project for a while while I worked on some other pieces, but I am back at it.

I managed to fry one of the op-amp breakouts that I bought, and then decided to mess with the math a little rather than cook more boards.

I think I have a working sensor set now I just had to amplify the numbers after the shifting operation.

Code:
// sparkfun electret mic sketch

const int ledPin = 13;
const int middleValue = 512;
const int numberOfSamples = 128;
int micPower = 12;
int sample;
long signal;
long averageReading;

long runningAverage=0;
long output=0;
const int averagedOver= 16;

const int threshold= 350;

void setup() {
  pinMode(ledPin, OUTPUT);
  digitalWrite(micPower,HIGH);
  Serial.begin(9600);
}

void loop(){
  long sumOfSquares = 0;
 
  for (int i=0; i<numberOfSamples; i++) {
    sample = analogRead(4);
    signal = (sample - middleValue);
    signal *= signal;
    sumOfSquares += signal;
  }
  averageReading = sqrt (sumOfSquares / numberOfSamples);
 
  runningAverage = ((( averagedOver - 1 ) * runningAverage ) + averageReading ) >> 4 ;
  output = ((runningAverage)*8);
  if (output>threshold){
    digitalWrite(ledPin,HIGH);
  }else{
    digitalWrite(ledPin, LOW);
  }
  Serial.println(output);
}

Likely very ineffecient, I am an artist, and program scavenger rather than an experienced coder so any advice is welcome.

I have now been trying to get this code integrated with a simple LED mood lamp to try and use the noise reading to affect the way the lights shift. The problem that I am running into is as follows:

While I get reasonably stable values back fromthe independant sensing program (output = between 245 and 310 in a quiet room jumping to over over 500 at moderate room volume), the integrated code provides more eratic readings. The new code is not yet designed to affect the lights, just run concurrently, so it has gaps in the stream of sensor readings while the chip does the counts for the change in lighting. The base line when the serial monitor is first opened is usually normal, (245-330) but the subsequent sensor cycles can have base readings as high as 800.

It appears that the numbers are highest when I have more power running to the LED's(15 Led's running off 3PWM pins), but I have no documented proof. When no LED's are lit the numbers seem to come in between 200-260.

Below is the code I have integrated, again, likely a mess sorry. Any Ideas what I am doing wrong?
Code:
// noise reactive sculpture
const int ledPin = 13;
const int middleValue = 512;
const int numberOfSamples = 128;
int count;
int micPower = 12;
int sample;
long signal;
long averageReading;

long runningAverage=0;
long output=0;
const int averagedOver= 16;

const int threshold= 550;
float RGB1[3];
float RGB2[3];
float INC[3];

int red, green, blue=0;

int RedPin = 11;
int GreenPin = 10;
int BluePin = 9;

void setup()
{
   pinMode(ledPin, OUTPUT);
   digitalWrite(micPower,HIGH);
   Serial.begin(9600);
  randomSeed(analogRead(0));
 
  RGB1[0] = 0;
        RGB1[1] = 0;
  RGB1[2] = 0;
 
  RGB2[0] = random(256);
  RGB2[1] = random(256);
  RGB2[2] = random(256); 
}
 
void loop()
{
  for(count=400; count>0; count--)// take 400 readings per loop to establish a common base line.
  {
    {
   
      long sumOfSquares = 0;
 
      for (int i=0; i<numberOfSamples; i++)
      {
        sample = analogRead(4);
        signal = (sample - middleValue);
        signal *= signal;
        sumOfSquares += signal;
      }
      averageReading = sqrt (sumOfSquares / numberOfSamples);
 
      runningAverage = ((( averagedOver - 1 ) * runningAverage ) + averageReading ) >> 4 ;//running average
      output = ((runningAverage)*8);//boost the numbers so the difference is larger, and easier to use
      if (output>threshold)//code remnant that will be changed later when the Mic values will affect the action of the lighting.
      {
        digitalWrite(ledPin,HIGH);
      }
      else{
        digitalWrite(ledPin, LOW);
      }
      Serial.println(output);
      count = (count-1); 
  }
   
  }
  randomSeed(analogRead(0));//nothing hooked to 0 the rest of the code deals with the shifting patterns in the lights.
 
  for (int x=0; x<3; x++) {
    INC[x] = (RGB1[x] - RGB2[x]) / 256; }
 
  for (int x=0; x<256; x++) {
    red = int(RGB1[0]);
    green = int(RGB1[1]);
    blue = int(RGB1[2]);

    analogWrite (RedPin, red); 
    analogWrite (GreenPin, green);   
    analogWrite (BluePin, blue);     
    delay(10);   
   
    RGB1[0] -= INC[0];
    RGB1[1] -= INC[1];   
    RGB1[2] -= INC[2];   
  }
  for (int x=0; x<3; x++) {
  RGB2[x] = random(556)-300;
  RGB2[x] = constrain(RGB2[x], 0, 255);
  delay(100);
  }
}

Please pardon the Novel and thanks again.
Logged

Manchester (England England)
Offline Offline
Brattain Member
*****
Karma: 631
Posts: 34502
Solder is electric glue
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
It appears that the numbers are highest when I have more power running to the LED's(15 Led's running off 3PWM pins),
How have you got that wired? Assuming it is 5 LEDs per pin and each LED has its own current limiting resistor then the total current out of each pin must be less than 40mA. That only gives you 8mA per LED. Have you designed it like this?
If not then it could be that the over driving of the digital pins is affecting the stability of the analogue reading.
Logged

Winnipeg, MB
Offline Offline
Newbie
*
Karma: 0
Posts: 7
I swear nature made them that way.
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I had the same thought, The resistors are 670 ohm on each array.

I wondered if the draw of the LED's was such that it might affect the reading and am now trying to make it so that the LED's are powered by a separate 9v battery. By removing the LED's from the power supply of the arduino, the numbers appear to have stabilized. I tested with my multimeter, and the current passing through each of the Led arrays is between 9 and 11 mA. Is it possible to use the PWM to sink voltage from the 9v, or do I need to use transistors as switches?

If it is transistors, which ones are best for this type of application? All I have on hand are 2907A and they have some serious gain to them.
Logged

Manchester (England England)
Offline Offline
Brattain Member
*****
Karma: 631
Posts: 34502
Solder is electric glue
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
Is it possible to use the PWM to sink voltage from the 9v
No, when it is off, that is not sinking there will be 9V applied to the output and that will zap the arduino.

Quote
All I have on hand are 2907A
They are fine but remember they are PNP so you will have to wire them accordingly.

Quote
The resistors are 670 ohm on each array.
Not sure what you mean by array, can you post a sketch of how it is wired.
Logged

Winnipeg, MB
Offline Offline
Newbie
*
Karma: 0
Posts: 7
I swear nature made them that way.
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

here is a quick mockup of my LED arrays, all the resistors are 670ohm
I was thinking that the transistors might work inserted at the end of the array, but I'm not certain how to use them in this context, it's kinda new to me.


* schematic of LED array.jpg (111.96 KB, 784x529 - viewed 16 times.)
Logged

Manchester (England England)
Offline Offline
Brattain Member
*****
Karma: 631
Posts: 34502
Solder is electric glue
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

No that is a bad circuit you can not have LEDs in parallel like that. Each one needs it's own resistor. This is because they will not shair current equally.
Logged

Winnipeg, MB
Offline Offline
Newbie
*
Karma: 0
Posts: 7
I swear nature made them that way.
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Attached is the new layout, I am required to do 2 LED's in series due to lack of resistors, and I might need lower value resistors. I had to do the Blue LED's in parallel pairs to get them to work at the appropriate brightness in series, they barely glowed. They must have a higher resistance/consumption than the other LEDS. The transistors seem to be working as PWM switches, now the code is sort of working, but not yet as responsive as I would like. It is posted below.

Code:
// noise reactive sculpture
const int ledPin = 13;
const int middleValue = 512;
const int numberOfSamples = 128;
int count;
int micPower = 12;
int sample;
int brightness;
int whiteBright = 0;
int lastwhite = 0;
long signal;
long averageReading;
long runningAverage=0;
long output = 0;
const int averagedOver= 16;
int y = 0;
const int threshold= 550;
float RGB1[3];
float RGB2[3];
float INC[3];

int red, green, blue, white=0;

int RedPin = 11;
int GreenPin = 10;
int BluePin = 9;
int WhitePin = 6;

void setup()
{
   pinMode(ledPin, OUTPUT);
   digitalWrite(micPower,HIGH);
   Serial.begin(9600);
  randomSeed(analogRead(0));
 
  RGB1[0] = 0;
        RGB1[1] = 0;
  RGB1[2] = 0;
 
  RGB2[0] = random(256);
  RGB2[1] = random(256);
  RGB2[2] = random(256); 
}
 
void loop()
{
  output = 0;
  for(count=128; count>0; count--)// take 128 readings per loop to establish a common base line.
  {
    {
   
      long sumOfSquares = 0;
 
      for (int i=0; i<numberOfSamples; i++)
      {
        sample = analogRead(4);
        signal = (sample - middleValue);
        signal *= signal;
        sumOfSquares += signal;
      }
      averageReading = sqrt (sumOfSquares / numberOfSamples);
 
      runningAverage = ((( averagedOver - 1 ) * runningAverage ) + averageReading ) >> 4 ;//running average
      output = ((runningAverage)*8);//boost the numbers so the difference is larger, and easier to use
     
      Serial.println(output);
     
      count = (count-1); 
  }
  }
  if (output >= 250 && output <= 399)
  {
    brightness = 200;
    whiteBright = 50;
  }
if (output >= 400 && output <= 499)
  {
    brightness = 150;
    whiteBright = 100;
  }
if (output >= 500 && output <= 599)
  {
    brightness = 100;
    whiteBright = 150;
  }
if (output >= 600 && output <= 699)
  {
    brightness = 50;
    whiteBright = 200;
  }
if (output >= 700)
  {
    brightness = 0;
    whiteBright = 255;
  }
else
  {
  brightness = 255;
  whiteBright = 0;
  }
 

  randomSeed(analogRead(0));//nothing hooked to 0 the rest of the code deals with the shifting patterns in the lights.
 
  for (y = lastwhite; y < whiteBright; y++)
         {
           analogWrite (WhitePin,(256 - y));
           delay (10);
         }
         for (y = lastwhite; y > whiteBright; y--)
         {
           analogWrite (WhitePin, (256 - y));
           delay (10);
         }
 
        for (int x=0; x<3; x++)
        {
    INC[x] = (RGB1[x] - RGB2[x]) / (brightness);
        }
 
  for (int x=0; x<(brightness); x++)
        {
    red = int(255-(RGB1[0]));
    green = int(255-(RGB1[1]));
    blue = int(255-(RGB1[2]));

    analogWrite (RedPin, red); 
    analogWrite (GreenPin, green);   
    analogWrite (BluePin, blue);     
    delay(10);   
   
    RGB1[0] -= INC[0];
    RGB1[1] -= INC[1];   
    RGB1[2] -= INC[2];   
  }
  for (int x=0; x<3; x++ )
        {
  RGB2[x] = random((brightness + 300)-300);
  RGB2[x] = constrain(RGB2[x], 0, (brightness - 1));
  delay(100);
        }
        lastwhite = whiteBright;
        y = lastwhite;
 
}


* new LED array.jpg (78.18 KB, 620x497 - viewed 5 times.)
« Last Edit: March 02, 2012, 07:01:09 pm by MossAndStone » Logged

Manchester (England England)
Offline Offline
Brattain Member
*****
Karma: 631
Posts: 34502
Solder is electric glue
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
I had to do the Blue LED's in parallel pairs to get them to work at the appropriate brightness in series
This is because there is not enough voltage from an arduino to power two blue LEDs in seriese. Make the resistor smaller to allow more current through the LED.
Logged

Pages: [1]   Go Up
Jump to: