Measuring sine wave altitude by adc

Thread Starter

soderdaen

Joined Nov 21, 2015
16
Hey everyone,

I am currently struggeling in measuring a one way rectified sine wave with my arduino board. I have a function generator which gives me a sine wave. I rectify it by a diode and measure the signal with my adc. No problem so far.
Now I just like to have the maximum point of the sine wave, but my code gives me the right values sometimes, sometimes the wrong values. I know why, but I am not that experienced to solve the programming task here by myself. I am continuosly asking the adc if it has a higher value for me than in the variable "highvalue". If it is, we have a new highvalue, if not than a counter counts up. If that counter reaches 10 I return my highvalue.
The reason why I get wrong values is because of noise or a lack of adc accuracy. Then the counter counts up, but it shouldnt. Or in the half wave that has been cut off there is a little noise that when the upper_halfwave function starts there I will get a 5 in my highvalue and then just zeros out of the adc and in the end my high value is 5.
Can anyone help me out with that ? Here is my code:

Code:
int upper_halfwave()
{
    while(1)
    {
        ADCSRA |= (1<<ADSC);
        while(ADCSRA & (1<<ADSC))
        {
        }
        adc_value = ADCW;
        usart(adc_value);
        if (adc_value>=highvalue)
        {
            highvalue=adc_value;
            counter=0;
        }
        else
        {
            counter++;
        }
        if (counter==10)
        {
            highvalue=0;
            return highvalue;
        }
    }

}
 

DickCappels

Joined Aug 21, 2008
6,531
What may be the simplest and most sure solution is placing a capacitor on the diode's output to form a peak detector. Then a large resistor across the capacitor to act as a bleeder will allow tracking as the amplitude of the sine wave is reduced.

About a year ago I implemented code to simulate a diode peak detector and a bleeder resistor in an AVR and after tweaking time constants it worked very nicely.

Yes, the ADC was kept very busy, being run in an interrupt routine that was triggered by a timer. If I recall correctly, I also did some averaging to reduce noise -for example adding together sixteen measurements then shifting the sum shirt right four times to divide by 16, yielding the average.
 

DickCappels

Joined Aug 21, 2008
6,531
I wrote code similar to yours that constantly monitored the input signal, increased the value in a register (like your "highvalue" variable if the ACD gave a reading that was higher than the last recorded "highvalue". A separately timed task would subtract a little; bit from "highvalue" so that the content of "highvalue" dropped, lagging a little, as the peak input value dropped. It simulated the action of a diode-capacitor peak detector and bleeder resistor. It was all in firmware.

Is this a school assignment?
 

Thread Starter

soderdaen

Joined Nov 21, 2015
16
Ah ok, reducing highvalue is a nice idea, I will try that.

It's for my bachelor thesis at the university. The main part is the hardware side, I did not know the programming part would be that hard. And programming is definately not my favourite subject..

Edit: Oh that helped me a lot, thanks for the advice. Now it's just in the falling part of the sine that makes bad values. But doing the routine for the bottom halfwave and waiting for the zero cross and then going to my upper_halfwave routine should do it i guess.
 
Last edited:

NorthGuy

Joined Jun 28, 2014
611
If you used a diode to rectify it, you have added a biss caused by the voltage drop across diode.

As for the math, I would suggest to do as follows, which is probably the easiest:

1. Read N values (e.g. 10) and calculate the highest of them as you read them. Set the highest value to the calculated number.

2. Read next N values and calculate the highest of them. While doing so, keep outputting the highest value calculated on step 1.

And so on.

If you have computing power, you can calculate RMS - square root of the sum of squared samples. That's the way AC is usually measured.

C:
  // code to calculate the highest value

  int ret_val = 0;
  int count = 0;
  int cur_val = 0;


int highest(int adc_val) {

   if (adc_val > cur_val) {
     cur_val = adc_val;
   }

   if (++count == 10) {
     count = 0;
     ret_val = cur_val;
     cur_val = 0;
   }

   return ret_val;

}
 
Last edited by a moderator:

ErnieM

Joined Apr 24, 2011
8,053
Where does the "10" come from?

You have a pulsing wave with some period. How fast is your A2D sampling this wave? How long until 10 samples happen?

For your scheme to work you want to collect a lot of data across at least one period of time to insure you caught the peak value.
 

Thread Starter

soderdaen

Joined Nov 21, 2015
16
The 10 is random.

Sampling rate is is Clock /1024. The ten samples are just for false values.
I managed to solve my problem by DickCappels advice. The part which made problem is then being solved in the main function waiting for the zero crossing.

The bias by the diode will later be considered.

If you have computing power, you can calculate RMS - square root of the sum of squared samples. That's the way AC is usually measured.
I think thats interesting, I am going to look up how it works.

Thank you all for now :)
 

joeyd999

Joined Jun 6, 2011
4,425
I do things like this the hard way...my code would actually simulate an analog peak detector using a digital filter. I'd program the decay time of the filter to whatever desired, perhaps dynamically based upon the computed period of the incoming waveform.
 

dannyf

Joined Sep 13, 2015
2,197
Then the counter counts up, but it shouldnt.
Because your code is designed that way. Maybe you should only increment the counter when the adc value is above a threshold value - when you consider the data to be valid.

Or in the half wave that has been cut off there is a little noise that when the upper_halfwave function starts there I will get a 5 in my highvalue and then just zeros out of the adc and in the end my high value is 5.
Sounds like you are measuring AC, not pulsed DC.

Can anyone help me out with that ?
Without more information, not much help can be given.
 

dannyf

Joined Sep 13, 2015
2,197
Assuming low frequency AC, you should consider some form of "continuous adc":

1) start the adc if zero-crossing is detected;
2) continues to perform adc, and save the highest value until the next zero-crossing is detected.
3) return the highest value.

Your code has a uart procedure in there. Arduino's uart isn't interrupt driven and is very slow so you may have performed adc during different cycles.
 

dannyf

Joined Sep 13, 2015
2,197
I put this together quickly to see how I may do it.

It is a simple routine that detects the peak of an analog signal (0-5v). Once a minimum threadhold, ADC_MIN=200(1v@5v Vref), is reached, the routine starts to save the peak value (=4.5v = 920.7 -> 921 @ 5v Vref).

As you can see, it correctly detected the peak here.

I used adc to detect the beginning and ending threshold. A digital input will work as well, assuming sufficient signal swing.
 

Attachments

Thread Starter

soderdaen

Joined Nov 21, 2015
16
Because your code is designed that way. Maybe you should only increment the counter when the adc value is above a threshold value - when you consider the data to be valid.

Sounds like you are measuring AC, not pulsed DC.

Without more information, not much help can be given.
It is pulsed DC. But I think the adc is not that exactly and measures some times a value which is not zero

Your second post is interesting, maybe I will try that next week when I have time again for that project.
Thank you everyone :)

Edit: I just see your third post. Looks good, but I think your sine wave does not have noise which is the real problem here. By the way: What programm is this? Can you simulate the code on the Pc and connecting your device virtually ?
 

ErnieM

Joined Apr 24, 2011
8,053
You don't state what device you are using but many devices are capable os "in circuit debugging" where you can set break point or even step your code line by line and see how your code works in the actual hardware.

I work with Microchip devices and their PICkit programmer (under $50) can Aldo do debugging like this. It is quite a valuable tool to have.

One point to emphasize in Danny's work is his use of a min test to bypass the near zero values and only start testing values when they are in the area where the peak occurs. That is what the two while loops do at lines 52 and 5C.
 

Thread Starter

soderdaen

Joined Nov 21, 2015
16
You don't state what device you are using but many devices are capable os "in circuit debugging" where you can set break point or even step your code line by line and see how your code works in the actual hardware.

I work with Microchip devices and their PICkit programmer (under $50) can Aldo do debugging like this. It is quite a valuable tool to have.

One point to emphasize in Danny's work is his use of a min test to bypass the near zero values and only start testing values when they are in the area where the peak occurs. That is what the two while loops do at lines 52 and 5C.
I am working on the ATmega 328p on Arduino Uno. I just kind of "debug" by usart giving out adc values and I also have a oscillocope here to measure high frequent pin changes.
 

shteii01

Joined Feb 19, 2010
4,644
PUSH:

Does anyone know what programm dannyf used for the screenshot?
Print Screen key on the keyboard takes the shot. Then paste in whatever program you use for picture editing. I use IrFanView (free). New M$ Paint works since they now allow to save in jpeg format. There is White Rabbit photoshop that you can find, that was pre release of Photoshop 5 or CS5 that was leaked.

Interesting feature of Print Screen is Alt+Print Screen, takes snap shot of the active window, not the whole desktop.
 
Top