Low frequency audio level detector using PIC ADC?


Closed Thread
Results 1 to 40 of 69

Hybrid View

  1. #1
    Join Date
    Mar 2009
    Posts
    653

    Default Low frequency audio level detector using PIC ADC?

    I'm very tight on board space, so I'm looking at how I can win back some board real estate..

    My circuit needs to detect the signal level of an incoming audio stream - at the moment, I use the well trodden path....full wave rectifiying then smooting into a PIC ADC.

    But since I have a lot of unused pins on my PIC...and it's not being pushed hard, then why not use some of its latent power to detect signal level? If nothing else, this will help me educate myself about sampling.

    The maximuum audio frequency is about 1.5khz...the lowest is about 50Hz, the signal is quite sinusoidal, so to my questions.....

    1. To try and catch peak (or close to it), what would be a good sampling frequency? (if it helps, I'm using a PIC16f1828 ...max internal oscillator of 40Mhz) - I'm thinking 10khz?

    2. Is this methodology correct....

    setup a time to interrupt at a rate of 10khz
    in the interrupt routine take an ADC sample into a variable, compare it to the last if it's bigger keep it, if it's smaller ignore it.
    run a bit of maths to convert peak voltage to RMS (ie multipy by .0707 using some FP workaround)
    Have another timer setup to reset the ADC sample variable every 20ms (ie 50hz the lowest frequency)

    Anything I'm missing - or any comments?
    Last edited by HankMcSpank; - 16th February 2011 at 09:33.

  2. #2
    Join Date
    Mar 2009
    Posts
    653


    Did you find this post helpful? Yes | No

    Default Re: Low frequency audio RMS signal level detector using PIC ADC?

    Quote Originally Posted by HankMcSpank View Post
    2. Is this methodology correct....

    setup a time to interrupt at a rate of 10khz
    in the interrupt routine take an ADC sample into a variable, compare it to the last if it's bigger keep it, if it's smaller ignore it.
    run a bit of maths to convert peak voltage to RMS (ie multipy by .0707 using some FP workaround)
    Have another timer setup to reset the ADC sample variable every 20ms (ie 50hz the lowest frequency)
    Actually I think my revised method below will be better....

    (VCC is 5V, AC signal will sit on 2.5V, therefore positive half of cycle samples @10 bits will be between 512 & 1024, negative parts of the cycle will be between 0 & 512)

    1. Setup a timer to interrupt at a rate of 20khz

    2. In the timer interrupt routine take an ADC sample into a variable

    3. Compare the ADC sample to the last sample - if it's higher keep it, if it's smaller ignore it.

    4. If the sample reads below 512 (half VCC - the signal's zero cross), then the highest sample from step 3 is signal 'peak', now zero the variable ready for the next positive cycle (ie samples above 512)

    5. Run a bit of maths to convert peak voltage sample to RMS (ie multipy peak sample by .707 using some FP workaround)


    Anything else?
    Last edited by HankMcSpank; - 16th February 2011 at 12:20.

  3. #3
    Join Date
    Aug 2010
    Location
    Maryland, USA
    Posts
    869


    Did you find this post helpful? Yes | No

    Default Re: Low frequency audio RMS signal level detector using PIC ADC?

    Hank, assuming you have time to spare, why not just sample on each iteration of main? I assume it is running much faster then 20K, And if you can stand the short time it takes to aquire the sample, you will have the best sample rate without going to interupts.
    -Bert

    The glass is not half full or half empty, Its twice as big as needed for the job!

    http://foamcasualty.com/ - Warbird R/C scratch building with foam!

  4. #4
    Join Date
    Mar 2009
    Posts
    653


    Did you find this post helpful? Yes | No

    Default Re: Low frequency audio RMS signal level detector using PIC ADC?

    Quote Originally Posted by cncmachineguy View Post
    Hank, assuming you have time to spare, why not just sample on each iteration of main? I assume it is running much faster then 20K, And if you can stand the short time it takes to aquire the sample, you will have the best sample rate without going to interupts.
    Hiya Bert ...thanks for the input.

    The reason for wanting to use interrupts, is that I can sub-contract out the ADC sampling (precisely) & let it maintain itself without having to integrate the sampling into my main loop, where there's other stuff happening (and a whole heap of pauses within!).
    Last edited by HankMcSpank; - 16th February 2011 at 14:56.

  5. #5
    Join Date
    Aug 2010
    Location
    Maryland, USA
    Posts
    869


    Did you find this post helpful? Yes | No

    Default Re: Low frequency audio RMS signal level detector using PIC ADC?

    Well in that case, I would make the rate some easy timer rate. like a 8 bit timer with some prescale, running as fast as you can stand to be interupted.
    -Bert

    The glass is not half full or half empty, Its twice as big as needed for the job!

    http://foamcasualty.com/ - Warbird R/C scratch building with foam!

  6. #6
    Join Date
    Mar 2009
    Posts
    653


    Did you find this post helpful? Yes | No

    Default Re: Low frequency audio RMS signal level detector using PIC ADC?

    Well the concept seems to work, but would you believe the thing that's hampering me is getting the timer1 interrupt frequency set right....I'm chasing an interrupt (ADC Sample) frequency of about 30khz.

    I seem to be getting an interrupt frequency of just 1Khz, which means only low frequency sine waves that I'm sampling are stable from an ADC perspective, what am I doing wrong....

    here's the top bit of my code (setting up the timer1)
    Code:
    ' Timer1 Registers: 
    ' Prescaler=1:1; TMR1 Preset=65503; Freq=30,303.0303Hz; Period=33,000 ns
    T1CON.5 = 0 ' bits 5-4  Prescaler Rate Select bits
    T1CON.4 = 0
    T1CON.3 = 1 ' bit 3 Timer1 Oscillator Enable Control: bit 1=on
    T1CON.2 = 1 ' bit 2 Timer1 External Clock Input Synchronization Control bit: 1=Do not synchronize external clock input
    T1CON.1  = 0 ' bit 1 Timer1 Clock Source Select bit: 0=Internal clock (FOSC/4) / 1 = External clock from pin T1CKI (on the rising edge)
    T1CON.0 = 1 ' bit 0 enables timer
    TMR1H = $FF      ' preset for timer1 MSB register
    TMR1L = $DF      ' preset for timer1 LSB register
    & below is my (DT) interrupt handler (feel free to suggest better way of writing this ...I'm a kludger at heart & I've not really a clue how to code well!)

    zero_cross is just a variable to track whether the signal wave/cycle is above zero (the signal zero point = 128....ie 1/2 my supply of 5V)
    signal_in is a variable to store the sample (previous_sample + peak_sample are too!).

    Code:
    '---[TMR1 - interrupt handler]--------------------------------------------------
    @ INT_DISABLE  TMR1_INT     ; diable Timer 1 interrupts
    T1CON.0 = 0 ' disables timer1
    ADC_Sample:
        ADCIN 8, Signal_In                'sample the incoming signal
        IF SIGNAL_IN > 130 THEN           'a level of 128 is the zero crossing point (130 adds a bit of margin for error)
        zero_cross = 1                            'a simple toggle/flag to track whether signal is above or below the 'zero point (ADC val of 128)
        IF SIGNAL_IN > PREVIOUS_SAMPLE THEN previous_sample = signal_in     ; if this latest incoming sample is bigger than the last sample, then it supercedes the previous value
        GOTO INTERRUPT_END
        ENDIF
    
        if signal_in < 126 and zero_cross = 1 then  'if sample is 128 or less, then we're at the zero cross point, (126 adds some margin for error) therefore we've finished trying to sample peak
        peak_sample = previous_sample               ' our peak sample is therefore whatever value is in the variable 'previous_sample' from above
        previous_sample = 0                         'zero it, ready for when the waveform goes into positive territory again.
        zero_cross = 0                             ' toggle the above zero/below zero flag
        endif
        
        INTERRUPT_END:
        LOOP_COUNT1 =LOOP_COUNT1+1    'this section just allow me to divide the interrupt rate down for onscreen display (else the serial port would bottleneck & PIC would likely restart)
        if loop_count1 = 1000 then                'I'm seeing about 1 update onscreen per second, which suggest the interrupt frequency is 1kHz & not the required 30khz!
        hserout [dec peak_sample,13, 10]
        loop_count1 = 0
        endif
        
    TMR1H = $FF      ' preset for timer1 MSB register
    TMR1L = $f0      ' preset for timer1 LSB register
    T1CON.0 = 1 ' bit 0 enables timer
    
    @ INT_ENABLE  TMR1_INT     ; enable Timer1 interrupts
    @ INT_RETURN
    
    end
    100hz, 2.5Vp signal - extracted 'peak' sample is circa 255....


    100Hz, 1.25Vp signal - extracted 'peak' sample should be circa 192 (remember here that the signal's zero crossing point is ADC=128)


    Ok, now you start seeing the problem...up to 300Hz, the ADC readings are fairly stable at +/- 1 sample, but if I now take the audio frequency up to 400Hz, the ADC 'samples' start getting choppy, which suggests the interrupt rate isn't high enough...




    So what am doing wrong wrt getting the timer1 interrupts to interrupt at a 30Khz?!!!
    Last edited by HankMcSpank; - 16th February 2011 at 23:22.

  7. #7
    Join Date
    Jan 2011
    Posts
    3


    Did you find this post helpful? Yes | No

    Default Re: Low frequency audio RMS signal level detector using PIC ADC?

    [QUOTE=HankMcSpank;99190]Actually I think my revised method below will be better....

    (VCC is 5V, AC signal will sit on 2.5V, therefore positive half of cycle samples @10 bits will be between 512 & 1024, negative parts of the cycle will be between 0 & 512)

    1. Setup a timer to interrupt at a rate of 20khz

    2. In the timer interrupt routine take an ADC sample into a variable

    3. Compare the ADC sample to the last sample - if it's higher keep it, if it's smaller ignore it.

    4. If the sample reads below 512 (half VCC - the signal's zero cross), then the highest sample from step 3 is signal 'peak', now zero the variable ready for the next positive cycle (ie samples above 512)

    5. Run a bit of maths to convert peak voltage sample to RMS (ie multipy peak sample by .707 using some FP workaround)


    i agree

  8. #8
    Join Date
    Aug 2010
    Location
    Maryland, USA
    Posts
    869


    Did you find this post helpful? Yes | No

    Default Re: Low frequency audio RMS signal level detector using PIC ADC?

    Hank, I think something is wrong with the settings. The toggle rate seems to represent a word timing out. For instance timer1 is 16 bit, full count is 65535. 65535*.0000005 = 32.7675mSec. that sure looks like your toggle rate!

    So I would guess TMR0 is not clearing on a match!
    -Bert

    The glass is not half full or half empty, Its twice as big as needed for the job!

    http://foamcasualty.com/ - Warbird R/C scratch building with foam!

  9. #9
    Join Date
    Mar 2009
    Posts
    653


    Did you find this post helpful? Yes | No

    Default Re: Low frequency audio RMS signal level detector using PIC ADC?

    [QUOTE=tony45;99536]
    Quote Originally Posted by HankMcSpank View Post
    Actually I think my revised method below will be better....

    (VCC is 5V, AC signal will sit on 2.5V, therefore positive half of cycle samples @10 bits will be between 512 & 1024, negative parts of the cycle will be between 0 & 512)

    1. Setup a timer to interrupt at a rate of 20khz

    2. In the timer interrupt routine take an ADC sample into a variable

    3. Compare the ADC sample to the last sample - if it's higher keep it, if it's smaller ignore it.

    4. If the sample reads below 512 (half VCC - the signal's zero cross), then the highest sample from step 3 is signal 'peak', now zero the variable ready for the next positive cycle (ie samples above 512)

    5. Run a bit of maths to convert peak voltage sample to RMS (ie multipy peak sample by .707 using some FP workaround)


    i agree

    Tony, Bert - The problem with step 4, is that in the absence of an equal or higher sample arriving (or, as you're proposing, while below zero point) my running peak variable is decremented (remember this code is emulating an analogue peak detect circuit - in such a circuit, the diode only lets through voltage that is higher.....and in the absence of a higher voltage the didoe is reverse biased & the cap starts discharging via a resistor - my running peak variable content decrements in this case).

    This will utlimately mean that during the negative portions of the cycle, the running peak I've stored will decrement a fair bit, before the next positive part of the cycle returns & sets the peak high again - this is essentially like half wave rectification vs full wave - the former gives much more ripple, ie half wave ripple....

    http://www.m.case.btinternet.co.uk/a...e_Smoothed.gif

    ...so what I end up with is pseudo ripple (a variable decrementing then being topped up) This is why when the ADC reading goes below zero (ie below 128 on an 8 bit sample), I want to flip the negative cycle up - to be a positive cycle. This greatly reduces any decrementing (pseudo cap disharging)

    This diagrams illustrate the end goal in analogue waveform terms...

    http://www.eleinmec.com/figures/018_04.gif

    The 0V (zero crossing point) in my case is 2.5V (an ADC reading of 128)...I want to flip the negative part of the wave up. It not only reduces ripple...but halfs the amount of time to detect peak etc, leading to less ripple (peak detect fluctuations)

    http://images-mediawiki-sites.theful...3847055696.png

    I realise 10 bits would be better, but just wanted to keep it all simple while I'm ironing out all the issues.

    N8NTA - tks for the tip about measuring the main loop time, I'll do that.

    Quote Originally Posted by cncmachineguy View Post
    Hank, I think something is wrong with the settings. The toggle rate seems to represent a word timing out. For instance timer1 is 16 bit, full count is 65535. 65535*.0000005 = 32.7675mSec. that sure looks like your toggle rate!

    So I would guess TMR0 is not clearing on a match!
    Wow Bert - that's a great spot! This from the datasheet...

    "The Special Event Trigger output of the CCP occurs immediately upon a match between the TMR1H, TMR1L register pair and the CCPRxH, CCPRxL registerpair. The TMR1H, TMR1L register pair is not reset
    until the next rising edge of the Timer1 clock."


    As far as I can gather. other than to set the CCP register (to select pin toggle vs special event ADC triggering) ...there's nothing else to be done - not sure how this one can be tackled?!!
    Last edited by HankMcSpank; - 24th February 2011 at 14:10.

  10. #10
    Join Date
    Aug 2010
    Location
    Maryland, USA
    Posts
    869


    Did you find this post helpful? Yes | No

    Default Re: Low frequency audio RMS signal level detector using PIC ADC?

    Ok, after some careful reading of the datasheet, I find I am no longer any smarter then I was before I started. I can't find anywhere in the datasheet to say in compare mode timer is reset on a match. It DOES say for the Special event trigger the timer is reset. So I suggest this:

    Go back to SET mode (Special Event Trigger).
    Enable interrupt on A/D conversion done.
    Have the ISR do this:
    toggle a pin (for debuging speed)
    move A/D results to a variable for later use
    Return from INT

    With that done, several things are solved for you.
    -Bert

    The glass is not half full or half empty, Its twice as big as needed for the job!

    http://foamcasualty.com/ - Warbird R/C scratch building with foam!

  11. #11
    Join Date
    Nov 2003
    Location
    Greece
    Posts
    3,807


    Did you find this post helpful? Yes | No

    Default Re: Low frequency audio RMS signal level detector using PIC ADC?

    Hank,

    1. why don't you make a full rectifier of your analog signal?

    2. is the signal always of the same amplitude?

    3. are you after a peak detector or an rms calculator? I am little confused by this thread...

    Ioannis

Members who have read this thread : 1

You do not have permission to view the list of names.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts