filtering analog data

Post here about your Arduino projects, get help - for Adafruit customers!

Moderators: adafruit_support_bill, adafruit

Please be positive and constructive with your questions and comments.
keithg
 
Posts: 82
Joined: Thu Oct 30, 2008 8:30 pm

Re: filtering analog data

Post by keithg »

I understand what you are suggesting but not quite how to put it in code. Also, I have used this circuit,http://itp.nyu.edu/physcomp/sensors/Rep ... icrophones which includes rectifyng diodes but "Physical Computing" describes the same circuit without rectification. Which do you feel best suits our application?
We thank you for the advise.

keithg
 
Posts: 82
Joined: Thu Oct 30, 2008 8:30 pm

Re: filtering analog data

Post by keithg »

Is this example appropriate?


void loop() {
val=0;
for (count = 0; count < 10; count++) { //loops 10 times
val = val + analogRead(0); //adds the pot readings together
}

val = (val / 100)*1.18; // finds average of readings and scales from 0-1020 to 0-120
if (val < (oldVal - hyst)) // if variance is less than hyst
{
oldVal = val; //set oldVal to val
LCDBarGraph();
}
else if (val > (oldVal + hyst)) // if variance is more than hyst
{
oldVal = val; // set oldVal to val
LCDBarGraph();
}
else { // variance is below hyst IS THIS ELSE NEEDED
val = oldVal; // keep oldVal
}

User avatar
adafruit_support_bill
 
Posts: 88086
Joined: Sat Feb 07, 2009 10:11 am

Re: filtering analog data

Post by adafruit_support_bill »

I don't know a lot about condenser mics, but I don't think the diodes would be a problem in this application. You are just measuring the magnitude of the noise.

You might try to reduce the LM386 gain so that your blue threshold is closer to the low-range of the A/D. That should give you more usable A/D resolution between the blue and red thresholds.

As for the code, you need to apply the hysteresis to the state, not to the last value:

The following code implements a simple state machine. It transitions from GREEN_STATE to BLUE_STATE to RED_STATE and back based on the threshold values. On each iteration, once the state is determined, the LEDs are illuminated accordingly.

Code: Select all

#define RED_STATE 1
#define BLUE_STATE 2
#define GREEN_STATE 3

// Tune threshold values for sensor response
#define RED_THRESH 100
#define BLUE_THRESH 80

// Tune hysteresis for stable transitions
#define HYST 2

float val;
int state;

void setup()
{
  state = GREEN_STATE; // initial state value
  
  // TODO - initialize LEDS and other stuff here

}


void loop() 
{
  // TODO - read and filter microphone input value as 'val'
  
  switch(state)
  {
    case RED_STATE:  // Red LED is currently illumuminated
      if (val < RED_THRESH - HYST)  // Only change state if we are clearly below the threshold.
      {
        state = BLUE_STATE;  // the value is clearly below the red threshold.
      }
      break;
    case BLUE_STATE:  // Blue LED is currently illumuminated
      if (val > (RED_THRESH + HYST))
      {
        state = RED_STATE; // the value is clearly above the red threshold.
      }
      else if (val < BLUE_THRESH - HYST)
      {
        state = GREEN_STATE;// the value is clearly below the blue threshold.
      }    
      break;
    case GREEN_STATE:  // Green LED is currently illumuminated
      if (val > BLUE_THRESH + HYST)
      {
        state = BLUE_STATE; // the value is clearly above the blue threshold.
      }
    break;
    default:
    break;
  }
  
  // TODO - illuminate LEDs based on state.
  
}

keithg
 
Posts: 82
Joined: Thu Oct 30, 2008 8:30 pm

Re: filtering analog data

Post by keithg »

Wow! Thank you so much. I have been hacking away at this hardware/software for two months, every single day after work and weekends. Amazing how much can be learned without solving the problem.

keithg
 
Posts: 82
Joined: Thu Oct 30, 2008 8:30 pm

Re: filtering analog data

Post by keithg »

I have managed to butcher your code so that the sketch only cycles through the led's without changing state. Initially, I wrote the LED, HIGH to each STATE but that didn't work either.

#define FILTER_SHIFT 3
int32_t filter_reg;
int16_t filter_input;
int16_t filter_output;



#define RED_STATE 1
#define BLUE_STATE 2
#define GREEN_STATE 3

// Tune threshold values for sensor response
#define RED_THRESH 720
#define BLUE_THRESH 700

// Tune hysteresis for stable transitions
#define HYST 2


int state;
int redLED = 13;
int blueLED = 12;
int greenLED = 11;


void setup()
{

Serial.begin(9600);
pinMode(redLED,OUTPUT);
pinMode(blueLED,OUTPUT);
pinMode(greenLED,OUTPUT);
state = GREEN_STATE; // initial state value

// TODO - initialize LEDS and other stuff here

}


void loop()
{

filter_input = analogRead(1); // read ADC

// low pass filter to get rid of noise
filter_reg = filter_reg - (filter_reg >> FILTER_SHIFT) + filter_input;
filter_output = filter_reg >> FILTER_SHIFT;
delay(100);
// TODO - read and filter microphone input value as 'val'
//val = analogRead(1);
switch(state)
{
case RED_STATE: // Red LED is currently illumuminated
if (filter_output < RED_THRESH - HYST) // Only change state if we are clearly below the threshold.
{
state = BLUE_STATE; // the value is clearly below the red threshold.
digitalWrite(blueLED,HIGH);
}
break;
case BLUE_STATE: // Blue LED is currently illumuminated
if (filter_output > (RED_THRESH + HYST))
{
state = RED_STATE; // the value is clearly above the red threshold.
digitalWrite(redLED,HIGH);
}
else if (filter_output < BLUE_THRESH - HYST)
{
state = GREEN_STATE;// the value is clearly below the blue threshold.
digitalWrite(greenLED,HIGH);
}
break;
case GREEN_STATE: // Green LED is currently illumuminated
if (filter_output > BLUE_THRESH + HYST)
{
state = BLUE_STATE; // the value is clearly above the blue threshold.
digitalWrite(blueLED,HIGH);
}
break;
default:
break;
}
Serial.println(filter_output);
// TODO - illuminate LEDs based on state.
if(RED_STATE)
{
digitalWrite(redLED,LOW);
digitalWrite(blueLED,HIGH);
digitalWrite(greenLED,LOW);
delay(100);
}

if(BLUE_STATE)
{
digitalWrite(redLED,HIGH);
digitalWrite(blueLED,LOW);
digitalWrite(greenLED,HIGH);
delay(1000);
}

if(GREEN_STATE)
{
digitalWrite(redLED,HIGH);
digitalWrite(blueLED,LOW);
digitalWrite(greenLED,LOW);
delay(100);
}




}

User avatar
adafruit_support_bill
 
Posts: 88086
Joined: Sat Feb 07, 2009 10:11 am

Re: filtering analog data

Post by adafruit_support_bill »

I don't have time for a detailed reply this evening. But the cycling is due to to a problem with the 'if' statements in your handling of the LED states. All three of them will always evaluate to TRUE, so you will cycle through the LEDs.

In the C language, any value other than 0 is TRUE. The value of RED_STATE is defined as '1' so your 'if' will always evaluate to TRUE.

if(RED_STATE)

Instead you need use logical expressions such as a comparison like:

if(state == RED_STATE)

Let me know how it goes and I will check back in the morning.

keithg
 
Posts: 82
Joined: Thu Oct 30, 2008 8:30 pm

Re: filtering analog data

Post by keithg »

Thank you. Tomorrow I am going to build this circuit again on a breadboard to make sure the hardware is functioning properly before soldering another one. We appreciate your expertise.

User avatar
adafruit_support_bill
 
Posts: 88086
Joined: Sat Feb 07, 2009 10:11 am

Re: filtering analog data

Post by adafruit_support_bill »

I promised a more detailed response.

The math in your low-pass filter is suspect. I think you are better off with the one you had posted before:

Code: Select all

input = analogRead(1);
adcResult = adcResult * 0.95 + analogRead(1) * .05;
This will give you a good approximation of a 20-sample running average. If it is still noisy, you can tweak the constants to widen the window. 0.99 and 0.01 will give you a 100 sample window. You shouldn't need to do the shift if you use this filter.

The 'digitalWrite' statements in the switch statement are superfluous. They aren't hurting anything, but you don't need them there.

The 'if' statements I mentioned yesterday are the main problem. Changing them to use logical comparison expressions will stop the cycling.

Good luck with the circuit work. I think you will get better results will less amplifier gain.

User avatar
didier
 
Posts: 115
Joined: Mon Nov 17, 2008 6:14 am

Re: filtering analog data

Post by didier »

Zener wrote:Running average (also known by another name I cannot think of...)
Box car filter, or moving average may be ? :mrgreen:

In fact there are multiple ways for 'filtering':
- Find aberrant value, so called outlier, and remove it. This can be done with the quartile or sigmas method: pretty easy.
- Dilute the effect of an abnormal value (only aberrant values should be removed...) using a smoothing algorithm: box car is the simplest, windowing the data may help under certain conditions
- Model the data using Huber M-Regression that allows a re-weighing of the data depending on the SD of other data points; then you recalculate your 'hat' (^) value versus the model. Uneasy, heavy in bytes, however my favorite method
- Denoise your data: only if you are dealing with periodical signal which does not seem to be the case, but why not mentionning it. Complex algorythm (FFT, thresholding and reverse FFT) which would explode your memory.

As mentionned, a well choosen RLC filter may do the job as weel!

HTH

sabuncu
 
Posts: 1
Joined: Sat Oct 27, 2012 1:27 pm

Re: filtering analog data

Post by sabuncu »

adafruit_support wrote:

Code: Select all

value = value >> 3;
I know this is an old thread, nonetheless it is very useful, and I registered to post my thanks!

Regards.

Locked
Please be positive and constructive with your questions and comments.

Return to “Arduino”