audio input values

When I measure audio (VU) inputs there are a lot of 'zero values' when they are not suposed to be there, is there a way to replace the zero by the last input value or just to ignore them all?

Example:
inputPin = 1
inputPin = 3
inputPin = 0
inputPin = 0
inputPin = 249
inputPin = 0
inputPin = 447
inputPin = 64
inputPin = 608
inputPin = 0
inputPin = 0
inputPin = 0
inputPin = 671
inputPin = 501
inputPin = 0
inputPin = 440
inputPin = 415
inputPin = 0
inputPin = 655
inputPin = 0
inputPin = 0
inputPin = 0
inputPin = 513
inputPin = 0
inputPin = 0
inputPin = 0
inputPin = 0
inputPin = 0
inputPin = 684
inputPin = 0
inputPin = 15
inputPin = 0
inputPin = 2
inputPin = 5

I tried to average the numbers, but the values then do not really compare with reality (for example when there is no sound it, the values say there is.)
What I eventually want to do is pwm a motor, but with the zero values in it, it is not correct enough
I tried several audio input setups and mics and different arduino and they all have it. Also I tried to find examples of people with simular problems but could not find it.

Needs more context.

These are the values I get when i make a lot of noise in the microphone, but as you can see I get a lot of zero's in my analog imput even though i am making a lot of noise. So if there is a way to just ignore the zero's the values would be alright.

inputPin = 447
inputPin = 64
inputPin = 608
inputPin = 0
inputPin = 0
inputPin = 0
inputPin = 671
inputPin = 501
inputPin = 0
inputPin = 440
inputPin = 415
inputPin = 0
inputPin = 655

What I am eventually making is a new version of an installation i made before, which puts sounds into a wave form: Soundwave2.0 - YouTube
Only before we used max/msp to convert the audio signal into a pwm signal.

Really, your posts so far a bit detail-deficient.

..it depends how the audio is connected to the arduino analog input. When you are using a capacitor, the negative "halfvawes" are below zero, thus you read zero. Try to keep the analog input in the middle of the analog range - ie with two 10kohm resistors - connect first from gnd to the analog input and the second one from the analog input to +5V (provided you have 5V arduino). Then, when connecting your audio via capacitor, the values will be between 0 and 1023, with 511 if no sound there (all shall work fine when input not overloaded - do not make too much noise) :slight_smile:
PS - overloading - you may see your signal does fit into the adc when you see only very few "0" and "1023" values, better none..

audioinput.jpg

Alright thnx adding that did indeed add the value to around 512. But the values I received then are still not as steady as i hope them to be. What I want is just to see I steady difference between when I talk soft and hard in the mic, and with these values I then can control a motor.

The code I have so far:

/*
Volume Unit meter
Mapping to 4 engine speeds
Adjustable engine speed triggers
*/



int inputPin = A0;
int inputLowThreshold = A1;
int inputMediumThreshold = A2;
int inputHighThreshold = A3;

int green1Led = 6;
int green2Led = 7;
int yellowLed = 8;
int redLed = 9;

//groter dan
int minimumThreshold = -1;

// **** average ***
const int numReadings = 5;     // van hoeveel die het gemiddelde neemt !!!!!!!!!
int readings[numReadings];      // the readings from the analog input
int index = 0;                  // the index of the current reading
int total = 0;                  // the running total
int average = 0;                // the average

int motorSpeed = 0;



//__________VOID SETUP__________
void setup() {
  pinMode(green1Led, OUTPUT);
  pinMode(green2Led, OUTPUT);
  pinMode(yellowLed, OUTPUT);
  pinMode(redLed, OUTPUT);  

  Serial.begin(9600);
  delay(10);  

  }


//__________VOID LOOP___________

void loop() {

  //*********** THRESHOLD MAPPINGs ***********
  //The thresholds that trigger the leds and motorspeeds, these are mapped so you can turn the pot meter getting a better detailed result.
  int val = analogRead(inputLowThreshold);
  int lowThreshold = map(val, 0 , 1024, 0, 600);   
  int val1 = analogRead(inputMediumThreshold);
  int mediumThreshold = map(val1, 0, 1024, 50, 800);  
  int val2 = analogRead(inputHighThreshold);
  int highThreshold = map(val2, 0, 1024, 100, 1000);
   
  // *********** AVERAGE CALCULATIONs ********** 
  total= total - readings[index];          // subtract the last reading:          
  readings[index] = analogRead(inputPin);  // read from the sensor:
  total= total + readings[index];          // add the reading to the total:          
  index = index + 1;                       // advance to the next position in the array:                  
  if (index >= numReadings)                // if we're at the end of the array...              
  index = 1;                               // ...wrap around to the beginning:    //// normaal 0                     
  average = total / numReadings;           // calculate the average:    
  
  //************
  val = analogRead(inputPin);
  //This will trigger the leds and the motorspeed when the average(or direct analog input) hits the threshold
  // change ("this">threshold )to average to use average or val for direct input
  if(average > highThreshold) { 
    motorSpeed = 255;
    digitalWrite(redLed, HIGH);
    digitalWrite(yellowLed, HIGH);   
    digitalWrite(green1Led, HIGH);
    digitalWrite(green2Led, HIGH);
    //delay (10);
  } else if(average > mediumThreshold) {
    motorSpeed = 170;
    digitalWrite(redLed, LOW); 
    digitalWrite(yellowLed, HIGH);  
    digitalWrite(green1Led, HIGH); 
    digitalWrite(green2Led, HIGH);   
    //delay (10);
  } else if(average > lowThreshold) {
    motorSpeed = 110;
    digitalWrite(redLed, LOW); 
    digitalWrite(yellowLed, LOW);  
    digitalWrite(green1Led, HIGH); 
    digitalWrite(green2Led, HIGH);  
    //delay (10);
  } else if(average > minimumThreshold) {
    motorSpeed = 60;
    digitalWrite(redLed, LOW); 
    digitalWrite(yellowLed, LOW);  
    digitalWrite(green2Led, LOW); 
    digitalWrite(green1Led, HIGH);  
    
  }
  
  
  //************* SERIAL PRINT ***************
  int s1 = analogRead(inputPin); // 
  Serial.print("inputPin = ");
  Serial.print(s1);
  Serial.print(" \t Average = ");
  Serial.print(average); 
  Serial.print(" \t motorSpeed = ");
  Serial.print(motorSpeed);
  Serial.print(" \t low = ");
  Serial.print(lowThreshold);
  Serial.print(" \t medium = ");
  Serial.print(mediumThreshold);
  Serial.print(" \t high = ");
  Serial.println(highThreshold);
  //delay(50); 
}

if (index >= numReadings) // if we're at the end of the array...
index = 1; // ...wrap around to the beginning: //// normaal 0
average = total / numReadings;

If numReadings is 5, but you're only summing four values, doesn't that skew your result?

..Frankly I do not know what you are doing with the signal actually, but you have to understand that the average of that signal is always 511 (the middle value). You are sampling a signal symmetrical around ~511, where the stronger the voice amplitude, the bigger the peaks around the center. See the picture with your voice envelope (in time). So you have to think how to evaluate the amplitudes then (not so easy) :slight_smile:

speech.jpg

Thanks, adding pito's scheme and fixing the code did gave me a much more stable and correct audio input!

Instead of doing 5 (4) readings and averaging why not just calculate a running average...

Put the below line in Setup() to pre-load the running average else it will slowly ramp up from zero

average  = analogRead(inputPin);

Then in your main loop put

average  = (average + analogRead(inputPin))/2;  // read from the sensor and average
delay(20);  // Delay to prevent hammering read if it's a fast loop

In my opinion you are simply using the wrong method to try and arrive at a specific measurement, average sound level. You should be externally rectifying (diode) and filtering (cap/resistor) the audio signal and then measuring the resulting DC voltage as a indication of the audio signal's average amplitude, a simple measurement well within the arduino's capabilities. The Arduino analog inputs are simply not fast enough nor is there enough SRAM to store enough samples to analyze and measure the signals average amplitude from the raw AC voltages in a audio signal.

Lefty

What about using one of these chips Graphic Equalizer Display Filter - MSGEQ7 - COM-10468 - SparkFun Electronics?

The seven band graphic equalizer IC is a CMOS chip that divides the audio spectrum into seven bands. 63Hz, 160Hz, 400Hz, 1kHz, 2.5kHz, 6.25kHz and 16kHz. The seven frequencies are peak detected and multiplexed to the output to provide a DC representation of the amplitude of each band.

Riva:
What about using one of these chips Graphic Equalizer Display Filter - MSGEQ7 - COM-10468 - SparkFun Electronics?

The seven band graphic equalizer IC is a CMOS chip that divides the audio spectrum into seven bands. 63Hz, 160Hz, 400Hz, 1kHz, 2.5kHz, 6.25kHz and 16kHz. The seven frequencies are peak detected and multiplexed to the output to provide a DC representation of the amplitude of each band.

Yes, that would simplify the task, however you would have to keep looking at all 8 'channels' of information and sum their values. Below is a device that is a true log amp that outputs a DC voltage proportional to the log of the total input signal, and as such gives a true and very wide range of sound level, which in nature is better measured in a log scale then in a simple linear voltage range. Not the cheapest chip, but when one understands the true difficulty of the task, a real value in amplitude range and accuracy.

Lefty