Rough 'n Ready Audio Frequency extraction with a PIC


Closed Thread
Results 1 to 34 of 34

Hybrid View

  1. #1
    Join Date
    Mar 2009
    Posts
    653


    Did you find this post helpful? Yes | No

    Default

    Quote Originally Posted by Dave View Post
    HankMcSpank ,I would personally count the time between interrupts instead of the number of interrupts in 1/2 second. That way you can increase the low end resolution you are looking for. Even a 1000 hz clock will give you .1% resolution at 100 hz....

    Dave Purola,
    N8NTA

    Dave you're right on the money there - I'm now getting much better stability with your suggested method, here's what I'm seeing onscreen for Timer1 counts between comparator interrupts (this was for approx 100Hz)...

    Timer1 Count= 5007
    Timer1 Count= 5005
    Timer1 Count= 5007
    Timer1 Count= 5004
    Timer1 Count= 5007
    Timer1 Count= 5004
    Timer1 Count= 5007
    Timer1 Count= 5005
    Timer1 Count= 5007
    Timer1 Count= 5004
    Timer1 Count= 5007
    Timer1 Count= 5005
    Timer1 Count= 5007
    Timer1 Count= 5004
    Timer1 Count= 5007
    Timer1 Count= 5004
    Timer1 Count= 5007
    Timer1 Count= 5004



    ...so my jitter is now something like 0.001% - that couls be down to my sigen not being stable even - it has been known to drift about a bit)

    I've got a bit of a mental block with the last remaining bit though (converting to frequency in hertz! - which for all I don't actually need the result in Hz - as I'll just be comparing on the timer count alone to establish whether of not the frequency is stable - it'd be a nice to have!!)

    So, what I'm seeing with my timer counts...

    A 'Timer1 count' of 5000 equals 100Hz
    A 'Timer1 count' of 500 = 1000Hz
    Therefore the timer clock cycle = 2us (0.000002s)

    What formula do I use to convert my Timer1 count into Hertz? (it's the floating point aspect that messing me up - else I'd just use this simple formula....

    1 / ('timer1 count' * 0.000002)

    If I add to the left side of the equation (to take the right hand side out of 'decimals' territory)...it cranks up into the millions - tilt!!!!

    So how should I approach this Hertz conversion?
    Last edited by HankMcSpank; - 27th August 2010 at 20:17.

  2. #2
    Join Date
    Feb 2006
    Location
    Gilroy, CA
    Posts
    1,530


    Did you find this post helpful? Yes | No

    Default

    Quote Originally Posted by HankMcSpank View Post


    A 'Timer1 count' of 5000 equals 100Hz
    A 'Timer1 count' of 500 = 1000Hz
    Therefore the timer clock cycle = 2us (0.000002s)

    What formula do I use to convert my Timer1 count into Hertz? (it's the floating point aspect that messing me up - else I'd just use this simple formula....

    1 / ('timer1 count' * 0.000002)

    If I add to the left side of the equation (to take the right hand side out of 'decimals' territory)...it cranks up into the millions - tilt!!!!

    So how should I approach this Hertz conversion?
    Hank, it looks like you are getting great results. Despite what it may look like, you really are not talking to yourself! A lot of people are interested in what you are doing, myself very much included.

    I often have to take a step back to figure out math .. or try to. For your equation,

    1/(counts * .000002) = hertz
    you can change it by multiplying both top and bottom by 500000.

    That gives you

    500,000/counts = hertz
    Then using one of your data points for counts:

    500,000/5007 = 99.86 hertz
    But since that doesn't fit in a pic well, and since I am sure you want the tenth and hundreds, we multiply the top by 100. Giving us:

    50,000,000/5007 = 9986 hundredths hertz. (really 99.86 hertz)
    To make it work inside a pic, check out the DIV32 function. It allows a number as big as 2,147,483,647 to be divided by a number as large as 32,767. Looks like you are good on both "counts"
    Last edited by ScaleRobotics; - 28th August 2010 at 03:18. Reason: Took out "code" tags, which seem to make people sick to their stomachs.
    http://www.scalerobotics.com

  3. #3
    Join Date
    Mar 2009
    Posts
    653


    Did you find this post helpful? Yes | No

    Default

    Thanks for the moral (& maths!) support.....at last things are starting to take shape (a *big* thanks - as ever - to all on here!)

    Re getting my 'time between comparator interrupts' converted into Hertz, sure enough when I tried to compile the following...

    Code:
    Frequency = 50000000/MyTime  'MyTime is a variable to store the number of timer1 clock counts
    ....some vomit actually jumped out of my screen (I can report that my wife is not happy with the mess on the carpet)

    So I then took one look at some DIV32 examples & augmented the screen's 'dirty protest' on the carpet with my own personal contribution ...I think I need to lie down (perhaps take up another hobby...or maybe dust that 'bus tickets of the world' collection of mine down & actually sort them into chronological order)
    Last edited by HankMcSpank; - 27th August 2010 at 23:22.

  4. #4
    Join Date
    Mar 2009
    Posts
    653


    Did you find this post helpful? Yes | No

    Default

    Ok, a wet VAc has sorted most of my carpet problems, but going straight to the manual for info about using DIV32 has seemingly brought more jitter to the fore....

    First here's what I'm doing....

    Code:
    @ __CONFIG _FCMEN_OFF & _INTRC_OSC_NOCLKOUT & _WDT_OFF & _MCLRE_OFF & _CP_OFF & _IESO_OFF & _BOR_OFF & _PWRTE_OFF
    
    '***********************************************************************************************
    
    '16F690 Pin Connections....
    ' PIN# NAME     USE & CONNECTION
    '  1   Vdd      +5VDC power supply   
    '  7   RC3      C12IN3- (external comparator input)     
    '  20  Vss      Ground
    '*************************************************************************************
    DEFINE  OSC 4          ' set Oscillator at 4Mhz.
    DEFINE  NO_CLRWDT 1   ' PBP doesn't clear WDT automatically
    DEFINE HSER_SPBRG 25   'HSEROUT Stuff.
    DEFINE HSER_TXSTA 24h  'HSEROUT Stuff.
    DEFINE HSER_CLROERR 1  'HSEROUT Stuff.
    
    txsta = %10100100       'setup the tx register
    RCSTA.7 = 1             ' Enable RB7 for TX USART
    INTCON.0 = 0            ' clears the RABIF Flag (to 0), COULD be 1 on reset (unique to F690)
    ANSEL      = 0    'disable AtoD.
    ANSELH     = 0    'disable AtoD.
    CM2CON0 = 0   'turn off comparator 2.
    
    'Turn on & Set up Comparator 1
    CM1CON0 = %11100011    'Comparator ext op pin disabled (op of comparator avaible internally only), compare against external VREF
    VRCON = %0100001       'turn on internal reference
    TRISA.2 = 0            'allow the comparator 1 output pin as an output
    
    MyTime       var  word    ' used to amalgamate TMR1 High & Low Bytes.
    Frequency    var  word    'used to convert the count to frequency.
    
    ' the following is pretty much a straight lift from the compiler manual (DIV32 section)
    a Var Word
    b Var Word
    c Var Word
    dummy Var Word
    b = 500
    c = 1000
              
    INCLUDE "DT_INTS-14.bas"     ' Base Interrupt System
    INCLUDE "ReEnterPBP.bas"     ' Include if using PBP interrupts
    
    ASM
    INT_LIST  macro    ; IntSource,        Label,  Type, ResetFlag?
            INT_Handler   CMP1_INT,  _Comp1_Int,   PBP,  yes
        endm
        INT_CREATE               ; Creates the interrupt processor
    ENDASM
    T1CON = $11               ; Prescaler setting 2us between clocks
    
    @ INT_ENABLE  CMP1_INT     ; enable Comparator 1 interrupts
    
    T1CON.0=0 'stop the timer
    TMR1H = 0 'Set the high part of the timer value to 0
    TMR1L = 0 'Set the low part of the timer value to 0
    
    MyTime = 0 'clear down Mttime, prior to starting.
    
    
    'Main body of Code*********************************************************************************************
    Main:
            pause 10
            goto Main
            end
       
    'Comparator1 Interrupt Handler+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++        
    Comp1_Int:
            if T1CON.0= 0 then 'if timer1 is not running...
            TMR1H = 0 'Set the high part of the timer value to 0
            TMR1L = 0 'Set the low part of the timer value to 0 
            T1CON.0= 1  'start timer
            else        'therefore if it is running, stop the timer & calculate the number of 'clock' counts between comparator interrupts....
            T1CON.0= 0  'stop the timer
            MyTime.Lowbyte = TMR1L 'puts the timer's low byte in MyTime's lower 8 bits 
            MyTime.Highbyte = TMR1H 'puts the timer's high byte in MyTime's upper 8 bits
    
            dummy = b * c '  'a straight lift from the compiler manual (DIV32 section)
            a = DIV32 MYTIME  'use the DIV32 to divide 50,000,000 by the comparator 'time between counts' 
            hserout ["Comparator1_Count = ", dec MyTime, 9, "Frequency = ", dec a,13, 10]       
            endif
            
    @ INT_RETURN

    ....& here's the onscreen hserout data....

    (just to remind you 'Comparator1_Count' is the 'number of clocks' counted between successive comparator interrupts - and the frequency is the DIV32 result of 500000 divided by comparator1_count number )

    Comparator1_Count = 1960 Frequency = 255
    Comparator1_Count = 1961 Frequency = 254
    Comparator1_Count = 1960 Frequency = 255
    Comparator1_Count = 1960 Frequency = 255
    Comparator1_Count = 1961 Frequency = 254
    Comparator1_Count = 1960 Frequency = 255
    Comparator1_Count = 1960 Frequency = 255
    Comparator1_Count = 1961 Frequency = 254
    Comparator1_Count = 1959 Frequency = 255
    Comparator1_Count = 1960 Frequency = 255
    Comparator1_Count = 1961 Frequency = 254
    Comparator1_Count = 1959 Frequency = 255
    Comparator1_Count = 1961 Frequency = 254
    Comparator1_Count = 1960 Frequency = 255
    Comparator1_Count = 1960 Frequency = 255
    Comparator1_Count = 1961 Frequency = 254
    Comparator1_Count = 1960 Frequency = 255
    Comparator1_Count = 1960 Frequency = 255



    (FWIW My sig gen was showing 255.2Hz on its LED display & using a calculator to divide 500000 by the 'average' comparator1_count of say 1960, works out at 255.1Hz)

    so as a percentage the 'variance/jitter' on the lefthand figure (Comparator1_Count) is miniscule....but using the DIV32 seems crank up the 'error' when converted to Hertz? (eg 254, 255, 255, 254)

    What am I doing wrong?!
    Last edited by HankMcSpank; - 28th August 2010 at 00:52.

  5. #5
    Join Date
    Feb 2010
    Location
    USA, New England
    Posts
    164


    Did you find this post helpful? Yes | No

    Default

    HankMcSpank,

    I suspect you are expecting to see a rounded final value when in fact your final value is truncated.

    1960/500,000 = 255.102, PBP truncates to 255 (same as rounding)
    1961/500,000 = 254.972, PBP truncates to 254 (would round to 255!)


    If you add "half of a whole value" before truncating it is the same as rounding. You can't add 0.5 to the DIV32 result because we aren't using floating point. So we add it before the division:

    1960/500,500 = 255.488, PBP truncates to 255
    1961/500,500 = 255.227, PBP truncates to 255 (all is good)


    You've may still have some granularity issues but this should get you closer.

    I remember hearing a long while back that "floating point math is for weenies who can't think big." 8^)

    Best Regards,
    Paul

  6. #6
    Join Date
    Mar 2009
    Posts
    653


    Did you find this post helpful? Yes | No

    Default

    Hi Paul,

    I was aware that the PIC simply threw the decimal portion away, but I'm no mathmetician & just wanted to clarify that I wasn't approaching this incorrectly!

    Thank you for your suggestion...but my goal here is simply to detect the frequency remaining the same for a set length of time (ie the guitar player is 'holding' a note for more than x seconds)....so I don't actually even need to convert to hertz - for simplicity, I can just work in counts.

    It might be handy one day to detect the actual 'Note Played'. when I think my approach would be along the lines of a monster lookup table (with a 'window' either side of the centre frequency for each note)...

    Code:
                      Hertz     Clock Count
    
    	 (from ) 	78	6410  
    Open	E	82.41	6067
    	 (to) 	84.85	5893  
    			
    	 	84.86	5892
    Fret 1	F	87.31	5727
    	 	89.90	5562
    			
    	 	89.91	5561
    Fret 2	F#	92.50	5405
    		95.24	5250
    			
    	 	95.25	5249
    Fret 3	G	98.00	5102
    		100.91	4955
    			
    	 	100.92	4954
    Fret 4	G#	103.83	4816
    		106.91	4677
    			
    	 	106.92	4676
    Fret 5	A	110.00	4545
    	 	113.26	4415
    			
    	 	113.27	4414
    Fret 6	A#	116.54	4290
    	 	120.00	4167
    & so on (I guess Hertz could be derived to decimal points using an even bigger lookup table?!)


    PS Once you get to the highest note on the fretboard (E on the 24th fret - 1318.5Hz) , the compartor clock count between interrupts comes down to something around 379....so it might be worth messing with the prescaler to give a bit more granularity)
    Last edited by HankMcSpank; - 28th August 2010 at 11:26.

Similar Threads

  1. Measuring change of frequency with PIC
    By Aussie in forum mel PIC BASIC Pro
    Replies: 5
    Last Post: - 19th July 2007, 01:47
  2. PIC Audio
    By toofastdave in forum mel PIC BASIC Pro
    Replies: 28
    Last Post: - 27th June 2007, 13:49
  3. Pic driven digital audio delay
    By skimask in forum Off Topic
    Replies: 12
    Last Post: - 19th April 2007, 20:42
  4. Audio Encoding and playback in a PIC
    By Rob in forum mel PIC BASIC Pro
    Replies: 8
    Last Post: - 24th March 2005, 08:56
  5. Frequency Counter using PIC and PicBasic
    By PICtron in forum mel PIC BASIC Pro
    Replies: 31
    Last Post: - 28th January 2005, 06:20

Members who have read this thread : 0

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