I have a project where I have to extract 50 Hz from input signal and calculate its magnitude within 1% accuracy. Inputs are from CT 10mV- 100mV. I have tried with numerous option FFT lib, Goertzel, plain DFT but all of them are inaccurate. My amplitude is constantly changing and varying more than 15%. Any ideas to bring it down. Using ATMEGA2560. Plan to switch-over to Arduino due.
This is not my area. If I was faced with something like this I would start by inputting a clean 50Hz signal and checking that I could accurately detect it. Then I would start adding noise and check that the system still worked, before moving to the actual target system.
I would also get a specification of the target signal.
You say you have tried various options but they are all inaccurate. How do you know that, how do you know you did not have programming or sensor errors or that the target signal actually contained a 50Hz signal?
Hi
I fed the signal from a agilent function generator directly to ADC input. FFT mag seems to be fluctuating and not steady. Did you get a steady value? Can you tell me how?
I have not done this, I am just thinking about how I would try to tackle the problem.
I would certainly start by making sure I was accurately reading the input before I did any manipulation of it.
Have you tried getting your function generator to output a 50Hz square wave and then just print the output from the ADC?
It should be pretty clear that you have a square wave and the amplitude should not be jumping all over the place.
If you cannot see a square wave then something is wrong with either the way you have connected the generator to the arduino, the A to D conversion or the actual output from the generator.
If square waves work move to a 50Hz sine wave. Once you know you are inputting a sine wave correctly start doing the signal analysis stuff. If the analysis fails then you probably have a programming error because you know your are correctly inputing a clean sine wave.
You'll probably need to have the ADC sampling rate be a integer multiple of 50 Hz and the FFT length contain an integer number of 50 Hz cycles to eliminate edge effects. It is also important to minimize jitter in the sampling interval which probably means using the ADC in the free running mode rather than looping up AnalogRead().
If the amplitude is varying by a factor of 10, I'm not sure you can get 1% with a 10 bit ADC.
Hi
Thanks for all the answers. Request to describe a workaround. After googling found AD7606 interface to arduino. Would this solution work for me? Besides arduino ADC is noisy when the inputs are close to 10mV (btw inputs change from 10mV to 1V RMS)
You'll probably need to have the ADC sampling rate be a integer multiple of 50 Hz and the FFT length contain an integer number of 50 Hz cycles to eliminate edge effects. ...
Sampling needs to be done at the very least at twice the signal frequency but it does not need to be an integer multiple does it? Using an integer multiple pre-supposes knowledge of the signal and also the frequencies are never going to be exact. I would have thought any sampling frequency over 100Hz would do with faster being better (up to a point).
... It is also important to minimize jitter in the sampling interval which probably means using the ADC in the free running mode rather than looping up AnalogRead()....
A uniform sampling interval makes sense but could the AnalogRead() interval not just be timed using micros() to run at say 250Hz ?
gary36:
Hi
Thanks for all the answers. Request to describe a workaround. After googling found AD7606 interface to arduino. Would this solution work for me? Besides arduino ADC is noisy when the inputs are close to 10mV (btw inputs change from 10mV to 1V RMS)
It will not work for you if the Arduino ADC is not the problem.
You originally said the input range was 10mV- 100mV.
What is the actual minimum and maximum signal amplitude you expect to see?
I would definitely feed in a square wave with a small amplitude and simply print out the readings before jumping to the conclusion that the Arduino ADC is too noisy. If you are going to print the readings sample at a slow rate to avoid too much output. You could also add a bit of logic to measure how much the min and max readings actually vary by.
I ran ADC in free running mode 19.2K, collected 768 samples. Went through moving average before decimating by 12. Applied 64 point FFT. Still my output is not rock steady.
I ran ADC in free running mode 19.2K, collected 768 samples. Went through moving average before decimating by 12. Applied 64 point FFT. Still my output is not rock steady.
Look at the raw data before you do any processing.
So far you have not eliminated any potential problems.
Use a square wave, sample at a slow speed, print out the values - then look at them!
For that matter sample a constant input voltage, how much does it vary by?
At 50Hz each wave takes 1/50=0.02s
You took 768 samples at 19,200Hz so your sample time was 0.04s that is only enough time for two waves.
ardly:
Sampling needs to be done at the very least at twice the signal frequency but it does not need to be an integer multiple does it? Using an integer multiple pre-supposes knowledge of the signal and also the frequencies are never going to be exact. I would have thought any sampling frequency over 100Hz would do with faster being better (up to a point).
The integer multiple requirement comes from the FFT. A pure sinusoidal signal should have all its energy in one FFT bin under the conditions described. If a non-integer number of cycles is taken, there will be energy in harmonic bins. If a large number of samples can be taken windowing can suppress these edge effects, but causes spreading of the spectral peaks. Also 8-bit Arduinos have limited RAM so number of samples is limited.
A uniform sampling interval makes sense but could the AnalogRead() interval not just be timed using micros() to run at say 250Hz ?
At low sampling rates (relative to the Arduino micros() resolution) this might be good enough, but one would have to look at the amount of jitter introduced.
I ran ADC in free running mode 19.2K, collected 768 samples. Went through moving average before decimating by 12. Applied 64 point FFT. Still my output is not rock steady.
I agree with Ardly in that you need to break the problem down and look at intermediate results. Start with collecting your sample buffer and dumping it to serial out for analysis.
I haven't looked at the specifics of configuring the ADC, but getting exact 19.2k samples per second from a 16 MHz clock doesn't seem possible.
It will be easiest to look at a large amplitude pure sine wave at 50 Hz, but for the objective application, it is still important to quantify what else is in the signal. That is, are we expecting just for harmonics or is there relatively fast amplitude modulation which will produce non-harmonic signal content.
I have a project where I have to extract 50 Hz from input signal and calculate its magnitude within 1% accuracy.
How does a FFT help with “magnitude”? Analog peak detection is far easier than sampling at high rates. I’m not convinced the OP has the right approach, given the above rather vague problem statement.
Is it just maximum envelope amplitude that you want? Please explain the details and the requirements a bit further. Given the CT and 50 Hz pieces of the puzzle, is this for some type of power line monitoring?
Hi
I am just out of my experiment and will be unable to provide details at this moment. But to tell you it is about power line monitoring. Need to extract 50 Hz from harmonics and DC component. I have a bleed of 10ohm across CT(1:1000). Full load primary current is 100A(secondary is 100mA). So I was dabbling with FFT and Goertzel to see if could extract 50 Hz signal whose amplitude changes from (10mV to 1V). Amplitude accuracy is important for power system protection. So I am expecting better than 1%. 10mV corresponds to 1A. So I need variation of amplitude in steps of 1A (of course with accuracy of 1%). I hope you guys have gotten my problem. Now looking for help about the most effective way to solve it
gary36:
Hi
I am just out of my experiment and will be unable to provide details at this moment. But to tell you it is about power line monitoring. Need to extract 50 Hz from harmonics and DC component. I have a bleed of 10ohm across CT(1:1000). Full load primary current is 100A(secondary is 100mA). So I was dabbling with FFT and Goertzel to see if could extract 50 Hz signal whose amplitude changes from (10mV to 1V). Amplitude accuracy is important for power system protection. So I am expecting better than 1%. 10mV corresponds to 1A. So I need variation of amplitude in steps of 1A (of course with accuracy of 1%). I hope you guys have gotten my problem. Now looking for help about the most effective way to solve it
What kind of values exactly are you trying to monitor?
You are only mentioning current (Ampere). If this is true, then FFT, Goertzel etc. are not necessary. Simply take the signal from your current transformer, and sample the waveform. From the waveform, you can detect peak current and calculate RMS current.
About the harmonics (waveform distortion) - to get a precise peak measurement and RMS measurement, you actually NEED the harmonics. If you filter them out first, then your measurement will not reflect the real current in your power line.
About the accuracy: The problem lies in the length of your sample. Either the sample has to be exactly the length of one period. Use zero crosssing to detect the start and end of the period. Or you need more than 100 periods, to average out the error introduced by sampling only part of a period.
In any case, if you want stable readings, it is a good idea to use the average of several readings.
This is always a compromize between speed and accuracy: A fast overcurrent detection (within one period) does not need 1% accuracy. This would be complete overkill. Even 10% or 20% would be good enough. The more critical factor is the speed of your emergency shutdown system.
On the other hand, 1% accuracy can easily be achieved, if you collect enough periods and take the average.
If noise is a problem: simply use an old style analog low pass filter with one capacitor and one resistor in front of the ADC input. If you really want to do the noise filtering in software, then use some simple averaging, before you do the peak detection / RMS calculation.
Note: noise and harmonics is not the same thing. Calculate your low pass filter, so it lets the harmonics through - say up to 200 Hz. Higher frequencies are then defined as noise.
About the DC component: I am not sure that the current transformer actually lets the DC component through. By definition, a transformer with coils only works with AC. That‘s why CT‘s don‘t work with DC current.
If all you are trying to do is measure current, then simply peak rectify the output of the current clamp to DC, and use a small capacitor to smooth the DC and then feed it into the Arduinos ADC.
This type of measurement ignores any loads that dont have a unity power factor, but will generally be good enough.
I ran ADC in free running mode 19.2K, collected 768 samples. Went through moving average before decimating by 12. Applied 64 point FFT. Still my output is not rock steady.
As I have said you need to start by looking at and understanding your input signal, before analysis.
If you don't believe me forget about a real physical input, just generate points in software using the sine function. Those points are therefore on a perfect sine wave. Feed them into your analysis and I bet you still don't get a "rock steady" output.