View previous topic :: View next topic |
Author |
Message |
Aayush13
Joined: 12 Aug 2016 Posts: 14
|
Finding frequency |
Posted: Tue Jan 03, 2017 8:50 pm |
|
|
I have hooked up a function generator to pin A1 to get the various values for the sinewave. I have found the amplitude and the RMS value already. I want to write code to find the frequency of the sine wave. How should I go about doing this?
Last edited by Aayush13 on Wed Jan 04, 2017 10:02 am; edited 2 times in total |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19513
|
|
Posted: Wed Jan 04, 2017 3:06 am |
|
|
First:
setup_adc(ADC_CLOCK_INTERNAL);
is _not_ recommended if your system clock is above 1MHz. read the data sheet and correct this.
Now a lot depends on just how fast this signal is?.
If it is above a few tens of Hz, then really you need to read the frequency a different way. Instead of using the ADC, have an external zero crossing detector, and feed the output of this into one of the CCP inputs. Then there is code in the examples for measuring a frequency using the CCP.
If however it is slow enough that you can get several ADC samples each cycle, then you basically can do the same in software. Now you say 'unipolar'. Do you mean you have the signal rectified?. Normally you'd use an op-amp to offset the AC signal, and bias this so that it's being fed into the PIC with it's 'zero' at perhaps half the Vref (so at 2.5v, since you are not using an external Vref). Then you set a flag when the signal is in it's positive half cycle (so >512). When you see the signal go into the -ve half cycle, with this flag 'true', you have seen the +ve to -ve zero-crossing. Record the value of a timer when this happens, and you have the period of one cycle of the waveform. |
|
|
temtronic
Joined: 01 Jul 2010 Posts: 9226 Location: Greensville,Ontario
|
|
Posted: Wed Jan 04, 2017 7:58 am |
|
|
I'll assume he's measuring line frequency as his acquisition loop is about 33ms.
Just thinking about a simple way with current data...
One somewhat inaccurate method to get a rough frequency would be to take the array max index, subtract the array min index, then multiply by the loop 'delay'. Effectively the number of 666us delays between ADC max and ADCmin.
IE: given array[21] = 255, array[41]=0
41-21=20
20 * 666= 13,320 us or .0132ms
1/.0132 = 75.75 Hz
rough , doesn't take into consideration the time to read the ADC and store the data or increment the counter but.....
it'd be interesting to see what real numbers look like.
Jay |
|
|
Aayush13
Joined: 12 Aug 2016 Posts: 14
|
|
Posted: Wed Jan 04, 2017 8:17 am |
|
|
temtronic wrote: | I'll assume he's measuring line frequency as his acquisition loop is about 33ms.
Just thinking about a simple way with current data...
One somewhat inaccurate method to get a rough frequency would be to take the array max index, subtract the array min index, then multiply by the loop 'delay'. Effectively the number of 666us delays between ADC max and ADCmin.
IE: given array[21] = 255, array[41]=0
41-21=20
20 * 666= 13,320 us or .0132ms
1/.0132 = 75.75 Hz
rough , doesn't take into consideration the time to read the ADC and store the data or increment the counter but.....
it'd be interesting to see what real numbers look like.
Jay |
Could you explain why you put 21 and 41 for array[]? |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19513
|
|
Posted: Wed Jan 04, 2017 8:44 am |
|
|
He doesn't.....
Read what he says. He is saying _if_ the high points and the low point in the array were 21, & 41, then the timing would be as shown.
You need to be testing the values in the array to find the low and high points.
However accuracy will be very bad. Given the huge sample interval, you could miss the high point and the low point by nearly a mSec each.
Last edited by Ttelmah on Wed Jan 04, 2017 8:52 am; edited 1 time in total |
|
|
temtronic
Joined: 01 Jul 2010 Posts: 9226 Location: Greensville,Ontario
|
|
Posted: Wed Jan 04, 2017 8:48 am |
|
|
21 is the index(location) of the element in the array that has the minimum value from the ADC and 41 is the index(location) of the element of the array that holds the maximum value from the ADC.
These are just examples for my post. You'll have to do the code to get them from your program. You need the difference between them, in my case 20 'units'. Multiplied by the 'loop delay' ( 666us in your code) to get a rough time between high and low of the sine wave.
Actually while typing this , you need 4X the result , as my idea just gets you 90* worth of time.
I need another coffee.....
Jay |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19513
|
|
Posted: Wed Jan 04, 2017 8:55 am |
|
|
It would (of course) be a lot more accurate to find successive high points (so the full 360 degrees).
However he hasn't answered the question about the nature of the waveform.
Ideally if the data is an offset sine, then my thought would be to find the two values that 'span' where it crosses the zero, and make an assumption that the signal is linear between, and hence calculate the time where it crosses quite accurately by interpolation. |
|
|
Mike Walne
Joined: 19 Feb 2004 Posts: 1785 Location: Boston Spa UK
|
|
Posted: Wed Jan 04, 2017 11:10 am |
|
|
The general principle with sine waves is to measure period/frequency by sampling where the waveform is changing at its fastest.
In other words, at the zero crossing (or its equivalent for an offset waveform).
Or has something changed in the last half century, when I wasn't looking?
Until you tell us what your amplitude and frequency ranges are we can offer little further help.
Mike
You're also not giving any clues about how you're getting amplitude and RMS values.
It's just possible you already have the data to hand and simply need to extract it. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19513
|
|
Posted: Thu Jan 05, 2017 1:40 am |
|
|
Exactly.
And given the low sample rate relative to the actual frequency, linear interpolation between the samples each side will give a better result. |
|
|
|