NerdKits - electronics education for a digital generation

You are not logged in. [log in]

NEW: Learning electronics? Ask your questions on the new Electronics Questions & Answers site hosted by CircuitLab.

Microcontroller Programming » Help understanding math portion of code (Sound Meter)

December 30, 2010
by caliliving714
caliliving714's Avatar

I am attempting to make a pizzo VU meter. My goal is just to use 8 outputs to control 8 LED's.

My problem is I don't understand the math/output of the function.

Can anyone give me some insight as to how this works?

I understand that "blocks" and then to "j" is what is driving the LED's.

Guess my main question is how does it use this variable to determine which LED's.

I figured if I knew the range in value I could just use if and while statements.

Any help would be appreciated. Oh if anyone has the code for the 4 LED sound meter that was mentioned in the 2nd or 3rd newsletter, I sure code use it.

Thanks, Mike

    //diff between min and max represents sound level
    int16_t diff = max - min;

    uint8_t j;
    if(diff == 0) diff=1;
    double diff_d = 1.0* diff; //turn diff into a double
    double blocks_raw = 11.0*log10(diff_d) - 10.0; //take log of of the sound level and scale to fit onto the sound meter

    int8_t blocks;    
    if(blocks_raw >= 0.0)
      blocks = blocks_raw;
    else
      blocks = 0;

    //sticky max represents the extra bar at the top that slowly appears to get "pushed" up by the sound bar
    // set new sticky max
    if(blocks > sticky_max){
      sticky_max = blocks;
      decay_rate = 1;
    }

    //decay sticky max
    if(iterations % 4 == 0){
      sticky_max = sticky_max - decay_rate;
      decay_rate++; //increase the reate of falling so the bar appears to be accelarating down
    }

    //redner blocks to display
    for(j = COLS; j > (COLS-blocks); j--){
       ledarray_set_column(j-1,1);
    }
    for(; j > 0; j--){
       ledarray_set_column(j-1,0);
    }
    //render sticky max
    ledarray_set_column(COLS - sticky_max,1);

  } 
  return;
}

void do_bar_test(){
  uint8_t i = 0;
  while(1){
    for(i = 0; i < COLS; i++){
      ledarray_set_column(i,1);
      delay_ms(1000);
    }
    ledarray_blank();
    delay_ms(1000);
  }
}

int main() {
  ledarray_init();

  sei();

  // start up the Analog to Digital Converter
  adc_init();

  while(1) {
      do_sound_meter();
      do_scrolling_display();
  }

}
December 30, 2010
by hevans
(NerdKits Staff)

hevans's Avatar

Hi caliliving714,

The "range" in the math is really defined by the possible values of min and max. Since our ADC is 10 bits the maximum difference between them is 1024, which is the maximum amplitude the buzzer can read. From there we wanted to use a logarithmic scale to display sound since sound is best visualized on a logarithmic scale. Since we know we want to run the diff through a log, we just need to scale it to fit in the 24 bars we have. log10(1025) is about 3.3 so at first we scaled by 7. This was giving us a big baseline value just from ambient noise, so we added an offset of about 10 because it seems about right based on the numbers we were getting. After we subtracted 11, we upped the scale factor to fill out the 24 bars. So at its max 11*log10(1025)-10 is about 23.1, which should completely fill out the array. The process was not extremely scientific, but it works!

Once we have a scaled value between 0 and 24 in the blocks variable, we just have to fill out the colums on the LED Array we want. We have two for loops on lines 29-34 of the code above that are responsible for turning on the correct columns. The first for loop starts from the top and turn on "blocks" number of columns on, then the second for loop turns the rest of the columns off.

Hope that helps! Let me know if you have specific questions.

Humberto

December 30, 2010
by caliliving714
caliliving714's Avatar

Thanks for the reply. I some what understand.

A couple more questions for you. If you may.

So lets say I want to use 7 LED's. Since 7 goes into 24 evenly. So each LED would represent a 4V difference. Roughly.

So I will take that value and say "while block <=5 turn led on."?

Thanks for the help.

December 30, 2010
by hevans
(NerdKits Staff)

hevans's Avatar

Hi caliliving,

I think your best bet is just to rescale blocks_raw into 7. You know for a fact that your maximum diff_d value is 1024. This will happen when the amplitude the sound is saturating the amplifier and your input is swinging from +5V to 0V. So I would try

double blocks_raw = 3.0*log10(diff_d) - 2;

This would make your max value 7.03 for blocks raw, and anything less than 10 on diff_d give you a value less than 1.

After than you can just use if statements to turn on individual pins. Something like

if(blocks_raw > 1){
  //turn on led 1;
}
if(blocks_raw > 2){
  //turn on led 2;
}
....

Hope that makes sense.

Humberto

May 21, 2011
by Rachid
Rachid's Avatar

The soundmeter.c for LCD seems to be incomplete. was it done on purpose? I dont see the function do_sound_meter()....just wondering

May 22, 2011
by hevans
(NerdKits Staff)

hevans's Avatar

Hi Rachid,

I just went and looked at the file we serving up for sound_meter_lcd.c, and it defines the do_sound_meter() function starting on line 58. Perhaps the file you downloaded got corrupted somehow.

Humberto

Post a Reply

Please log in to post a reply.

Did you know that you can see each keypress on a computer keyboard on an oscilloscope? Learn more...