# How to correct these notches in sine wave

Status
Not open for further replies.

#### praveen_palaparthi

##### Full Member level 1
duty cycle sine wave

Hi i am working on SINE WAVE UPS.I have written code to generate sine wave but got some notches how to remove these and get pure sine wave. Suggest me if have to change my logic.

closed loop sine wave

Green colur waveform is the output voltage and yellow colour is the sensing voltage to the controller for controlling output voltage.............

sine wave output after pi controller

Suggest me if have to change my logic.
How can we know without any information about your "logic" or hardware? It even can't be seen, if we have an oscillation of the output filter or the control loop. You have to provide basic information to get a meaningful answer.

i am a sinewave

I am sorry here the logic.

I have divided half cycle of sine wave into 36 intervals and stored the values in an array.I intialised the timer-0 so that at every 278 micro second i will update the duty cycle by taking the value from sine table.How i got 278 micro second...ok i have taken only half cycle so time period is 10 mill second divided by 36 i got 278 us. this is open loop here i am getting pure sine wave without notches.

But when sensing the out put voltage point by point means at every 278 micro sec i am correcting the duty cycle using PI equation.I am getting these noise as shown in figure.First i am measuring the output voltage using ADC as i am having DC off set in sensing voltage the sensing voltage is shifted to 2.5 volts from origin as shown in yellow colour waveform so i am substrating this DC offset from measured output voltage that is output voltage=measured-500 and then i am calculating the error=ref-output.THen this error is passed through PI euqation then i am sending the corrected duty cycle to registers.

here a pseudo code for correcting the duty cycle this code is executed for every 278 micro second.

sine_value= sine_table[sine_table_count];
ref_voltage= sine_value;
out_voltage_1=out_voltage-500;
if (Half_cycle_count)
{
out_voltage_1=~out_voltage_1;
out_voltage_1=out_voltage_1+1;
}
x =ref_voltage-out_voltage_1;
z1=ki*x;
z=z1>>10;
y=yold+(kp*(x-xold))+z;
Duty_cycle=y>>6;
if(Duty_cycle<0)
{
Duty_cycle=~Duty_cycle;
Duty_cycle=Duty_cycle+1;
}
if(Duty_cycle>0x1F4)
Duty_cycle=0x1F0;
xold=x;
yold=y;

this is what i am doing and getting the noise please suggest me is there any logic to correct duty cycle to maintain constant volatge +/-10 volts of 230 volts.

duty cycle on a sine wave

O.K., seems to be mainly a problem of controller design.

There's a basic issue with the zero crossing discontinuity in your controller. Assume the PI output produces a correct duty cycle before the zero crossing but has a non-zero I signal. Because you are inverting the output voltage rather than the sine table at zero crossing, the I signal has a starting value of wrong polarity after the zero crossing. This causes a duty cycle step which is eleminated in an oscillating controller response over several controller sampling intervalls. As an additional issue, if the PI output should saturate at zero (related to the actual polarity), it's producing a positive output instead. You should use the half_cycle information instead of inverting negative duty_cycle values.

It may be the case, that a small offset in output voltage measurement is causing the problem, so it could be minimized by adjusting the arbitrary offset of 500. But basically, it's wrong to invert the PI controller polarity at each half cycle. At least, you should reset the integral signal at the zero crossing, if you do it that way.

You reported, that the open loop waveform is quite good. So I wonder, if it's necessary to correct the momentary output voltage. You may want to use a slow controller for the RMS output instead.

duty cycle of sine wave

Sir i have given you only the output correction part ok i will put complete code tell me where my logic is going wrong.I putting only sinusoidal PWM generation with closed loop please help me to develop the logic.
THis is timer-0 routine which generates sinuoidal PWM i have not mentioned intialisation part.

void interruupt ACDC(void)
{
if(TOIF)
{

T0IF = 0;
T0CS = 0; // set up timer0
TMR0=0x5B;
PSA=0;
PS2=0;
PS1=0;
PS0=1;
sine_value= sine_table[sine_table_count];
ref_voltage= sine_value;
out_voltage_1=out_voltage-500;
if (Half_cycle_count)
{
out_voltage_1=~out_voltage_1;
out_voltage_1=out_voltage_1+1;
}
x =ref_voltage-out_voltage_1;
z1=ki*x;
z=z1>>10;
y=yold+(kp*(x-xold))+z;
Duty_cycle=y>>6;
if(Duty_cycle<0)
{
Duty_cycle=~Duty_cycle;
Duty_cycle=Duty_cycle+1;
}
if(Duty_cycle>0x1F4)
Duty_cycle=0x1F0;
xold=x;
yold=y;
PR2 = 0x80; //0xA6 0x80 0x80 0x93 0xC0;
T2CON = 0x04; / enablint timer 2 and prescaler value =1:1
if(Half_cycle_count) // positive half cycle
{
CCPR2L = Duty_cycle>>2;
CCP2CON = ((Duty_cycle&&0x03)<<4)+0x0C;
CCP1CON = 0x00;
}
else // Negative half cycle
{
CCPR1L =Duty_cycle>>2;
CCP1CON = ((Duty_cycle&&0x03)<<4)+0x0C;
CCP2CON = 0x00;
}
sine_table_count++;
if(sine_table_count>=0x24)
{
sine_table_count=0x00;

if(Half_cycle_count)
Half_cycle_count=0;
else
Half_cycle_count=1;
}

}

sine wave notching

Help me guys how to correct the output voltage i posted code and feedback circuit...............

sine wave notch

Ok I see you problem.

The main problem is you are feeding absolute values into your PI loop. No signs. This introduces a high frequency component at the zero crossings and the PI loop tries to compensate for this causing it to ring. You need the error to be reference sine - output voltage. Feed this into your PI function then look at the output sign to decide output polarity.

Looking at your code it looks like your PI code is wrong as well. Look at the code below, you may need to adjust kp, ki and the amount of shift to get it right but it should fix your problem.

Code:
void interrupt ACDC(void)
{
if(T0IF)
{
T0IF = 0;
T0CS = 0; // set up timer0
TMR0=0x5B;
PSA=0;
PS2=0;
PS1=0;
PS0=1;
// Get reference voltage
ref_voltage = sine_table[sine_table_count];
// make reference negative on second half cycle
if (half_cycle_count) ref_voltage = -ref_voltage;  // 16 bit signed
// Update counters
sine_table_count ++;
if (sine_table_count >= 0x24)
{
sine_table_count = 0;
if (half_cycle_count) half_cycle_count = 0;
else half_cycle_count = 1;
}
// Do PI calculation
x = ref_voltage - output_voltage;  // 16 bit signed
integral += ki * x;        // 32 bit signed
proportional = kp * x;     // 32 bit signed
// Scale down from 32 bits. This reduces rounding error by doing this last
PI_output = (integral + proportional) >> (10 + 6); // 32 bit signed to 16 bit signed
// Check if positive or negative
if (PI_output >= 0)
{
// Positive values
duty_cycle = PI_output;
if (duty_cycle > 0x1F0) duty_cycle = 0x1F0
PR2 = 0x80;
T2CON = 0x04;
CCPR2L = Duty_cycle >> 2;
CCP2CON = ((Duty_cycle & 0x03) << 4) + 0x0C;
CCP1CON = 0x00;
}
else
{
// Negative values
duty_cycle = -PI_output;
if (duty_cycle > 0x1F0) duty_cycle = 0x1F0
PR2 = 0x80;
T2CON = 0x04;
CCPR1L = Duty_cycle>>2;
CCP1CON = ((Duty_cycle & 0x03) << 4) + 0x0C;
CCP2CON = 0x00;
}
}
}

Sorry I forgot to subtract the bias from output_voltage.
Shouldn't the bias be 512 not 500. I assume a 10bit ADC with a 5V reference.

Looking at the circuit you have, I would use a rail-rail opamp. Gives you a little more common mode range.

Hello itaig,

Thank you for responding to me.Now i can able to remove notches in my waveform but the at present problem is My wave shape is not maintaining sinewave when i am putting load.Our output rating is 200 VA inverter.can you help me how to maintain sine wave shape ..............

Thank you

P.Praveen

Added after 1 hours 13 minutes:

Here i am putting my whole code of sine wave inverter as i mentioned above problem tell me what should i do..

#include <pic.h>
#define kp 57
#define ki 32

int out_voltage=0,out_voltage_1=0,tim_per=0x80;
int ref_voltage=0; // ref volatge based on feedback
signed int x=0;
int xold=0;
long y=0;
long yold=0;
int duty_cycle=0;
long z=0,z1=0,proportional=0,integral=0;
unsigned char sine_table_count=0,count=0,adc_flag=1; // Index into the sinewave reference table
unsigned char Half_cycle_count=0,i=0; // Determines the halfcycle
unsigned int sine_value=0x00; // Sine table value
unsigned int d1;

bank1 unsigned int const sine_table={39,77,114,151,186,219,250,279,305,328,347,364,377,386,392,394,392,386,
377,364,347,328,305,279,250,219,186,151,114,77,39,15};

void main(void)
{
/* setup stuff */
TRISA= 0x2F; // PORTA pins as input pins
TRISC = 0x00; // PORT C pins as output pins
PORTC=0x00;
TRISB=0xF2;
PORTB=0;
RB3=1;
ADIF=0; // clearing A/D interrupt flag
TMR0=62; //0x3D; //0x3D;//0x5B; // TMR0 setup
PSA=0;
PS2=0;
PS1=0; //0;
PS0=1; //1;
T0CS = 0; // Timer increments on instruction clock
T0IE = 1; // Enable interrupt on TMR0 overflow
PEIE=1;
GIE=1; // Global interrupt enable
GODONE = 1;
while(1) // Loop forever
{
}
}

static void interrupt isr(void) // Here be interrupt function - the name is unimportant.
{
{
out_voltage=0;
GODONE =1;
if(out_voltage==0)
out_voltage=500;

}

if(T0IF) // Clear interrupt flag, ready for next
{
T0IF = 0;
T0CS = 0; // set up timer0
TMR0=62; //0x3D; //0x5B;
PSA=0;
PS2=0;
PS1=0;
PS0=1;
ref_voltage= sine_table[sine_table_count];
if (Half_cycle_count)
ref_voltage=-ref_voltage;
sine_table_count++;
if(sine_table_count==32)
{
sine_table_count=0x00;
if(Half_cycle_count)
Half_cycle_count=0;
else
Half_cycle_count=1;
}
x =ref_voltage-out_voltage_1;
proportional=(kp*x)>>10;
integral+=ki*x;
y= (integral + proportional)>>6;
if(y>=0)
{
duty_cycle=y;
if(duty_cycle>1023)
duty_cycle=1023;
}
if(y<0)
{
duty_cycle=-y;
if(duty_cycle>1023)
duty_cycle=1023;
}
if(Half_cycle_count) // positive half cycle
{
CCPR2L = duty_cycle>>2;
CCP2CON = ((duty_cycle&&0x03)<<4)+0x0C;
CCP1CON = 0x00;
}
else // Negative half cycle
{
CCPR1L =duty_cycle>>2;
CCP1CON = ((duty_cycle&&0x03)<<4)+0x0C;
CCP2CON = 0x00;
}

}
}

Ok I can help.

First can you post a capture of the output voltage and current waveforms that you get when you have the load on?

What type of load are you using? Is it resistive, reactive or non-linear?

One thing I did notice is that you are using a "logical and" instead of a "bitwise and"
when you are writing to the CCP registers. Look in my code, I use & not &&. This will only effect the 2 LSBs so will not effect the output much.

Anyway post the waveforms and I will see what I can do.

Thank you itaig,Here i am putting my waveform please tell me wat to do.....

Ok I see a mistake in the code.

out_voltage=0;
...
...
...
x =ref_voltage-out_voltage_1;
proportional=(kp*x)>>10;
integral+=ki*x;
y= (integral + proportional)>>6;

The line:
x =ref_voltage-out_voltage_1;

needs to be changed to:
x = ref_voltage-out_voltage-512;

you were using the wrong variable and also the dc bias has not been subtracted so your PI loop was not actually looking at the output.

Of course now your kp and ki may be wrong as well as the scaling.

If you still have problems, post the new waveforms and turn the pk-pk measurement on as well.

Another question, which PIC are you using?

@ praveen_palaparthi. What type of Oscilloscope are you using? The images are clear. I'm very interested in getting one. Help me with the details to ease my purchase. Thanks and sorry for the diversion.

Sorry my mistake it should be:

x = ref_voltage - (out_voltage - 512);

or

x = ref_voltage - out_voltage + 512;

Hope you read this before you try it.

Hello itaig,
I tried but its the same not maintaining the sinewave

Added after 4 hours 44 minutes:

HI again i am posting the code which is corrected but even the waveshape is changing please correct it

#include <pic.h>
#define ki 54
#define kp 32

int out_voltage=500,out_voltage_1=00; // A/D converter value

int ref_voltage=0; // ref volatge based on feedback

int x=0;
int xold=0;
// PI Compensator values
long y=0;
long yold=0;

int Duty_cycle=0;
long z=0,z1=0;

unsigned char sine_table_count=0; // Index into the sinewave reference table

unsigned char Half_cycle_count=0; // Determines the halfcycle

unsigned int sine_value=0x00; // Sine table value

unsigned int d1;

// This table yields VRMS input

bank1 unsigned int const sine_table={39,77,114,151,186,219,250,279,305,328,347,364,377,386,392,394,392,386,
377,364,347,328,305,279,250,219,186,151,114,77,39,0};

void main(void)
{
/* setup stuff */

TRISA= 0x2F; // PORTA pins as input pins
TRISC = 0x00; // PORT C pins as output pins
PORTC=0x00;
TRISB=0;
RB3=1;
ADIF=0; // clearing A/D interrupt flag
TMR0=62; //0x3D; //0x3D;//0x5B; // TMR0 setup
PSA=0;
PS2=0;
PS1=0; //0;
PS0=1; //1;
T0CS = 0; // Timer increments on instruction clock
T0IE = 1; // Enable interrupt on TMR0 overflow
PEIE=1;
GIE = 1; // Global interrupt enable
GODONE = 1;
while(1) // Loop forever
{}
}

static void interrupt isr(void) // Here be interrupt function - the name is unimportant.
{
{
out_voltage=0;
GODONE = 1;
}

if(T0IF) // Clear interrupt flag, ready for next
{
T0IF = 0;
T0CS = 0; // set up timer0
TMR0=62; //0x3D; //0x5B;
PSA=0;
PS2=0;
PS1=0;
PS0=1;
sine_value= sine_table[sine_table_count];
ref_voltage= sine_value;
out_voltage_1=out_voltage-500;
if (Half_cycle_count)
{
out_voltage_1=~out_voltage_1;
out_voltage_1=out_voltage_1+1;
}
x =ref_voltage-out_voltage_1;
z1=ki*x;
z=z1>>10;
y=yold-(kp*(x-xold))-z;
Duty_cycle=y>>6;
if(Duty_cycle<0)
{
Duty_cycle=~Duty_cycle;
Duty_cycle=Duty_cycle+1;
}
if(Duty_cycle>0x1F4)
Duty_cycle=0x1F0;
xold=x;
yold=y;
PR2 = 0x80; //0xA6 0x80 0x80 0x93 0xC0; // period=d2
T2CON = 0x04; // enablint timer 2 and prescaler value =1:1
if(Half_cycle_count) // positive half cycle
{
CCPR2L = Duty_cycle>>2;
CCP2CON = ((Duty_cycle&0x03)<<4)+0x0C;
CCP1CON = 0x00;
}
else // Negative half cycle
{
CCPR1L =Duty_cycle>>2;
CCP1CON = ((Duty_cycle&0x03)<<4)+0x0C;
CCP2CON = 0x00;
}

sine_table_count++;
if(sine_table_count>=32)
{
sine_table_count=0x00;
if(Half_cycle_count)
Half_cycle_count=0;
else
Half_cycle_count=1;
}

}

}

Ok. I posted a message before but it seemed to have gotten lost.

Time to do some debugging. You will need a spare output on the micro for this.

In the two places you see this code:

Code:
if(duty_cycle>1023)
duty_cycle=1023;

replace with this:

Code:
if(duty_cycle>1023)
{
duty_cycle=1023;
DiagOutputHigh();  // Set you test output high
}
else
{
DiagOutputLow(); // Set your test output low
}

When you have done this post the waveform coming out of the pin as well as the output waveform. Do this with you 160W load.

Does your scope have the FFT module fitted? If it does then post a FFT of the output waveform as well. This will allow me to see how strong the harmonics are.

hi ,

has there been any improvement to the wave shape since the last assistance from itaig?. i,am having similar problem and hope to apply suggestions by itaig.but i believe you need to trow more light on the design of the PI to see if the coeficient kp and ki ere adequate

regards,
babalola.

I havent used PI equation.With PI equation i m getting those notches.so i removed PI and kept only P controller for this what i have done is i have sensed output voltage for every 1 milli second for complete half cycle and took the average and calculated error.IF that error is more than 5 volts use to increment the sine table value by one or decrement the sine table value by one.Like this i have done and its working.

If u got any idea of using PI equation let me know i too want to learn the thing.

praveen,

please can you make available the working code for us to see?. i will appriciate it.as for the PI equation you need to supply the
1: the output filter of you schematic to formulate the plant model
2: the switching frequency
3: the load ,dc input voltage
with these parameter i think one can design the pi for the kp and ki, other performance specification like settling time and percentage overshoot with steady state error are equally important .

regards
babalola.

hi praveen,

why dont you try a more direct equation as follows:

Y=Yold +K0(error) +K1(olderror)

where K0=KP+KI*T/2
and K1=-KP+KI*T/2

T=sampling time, inyour case i think its 278us

or if you want to use your old equation ,i expext the equation to be thus:

proportional= KP*ERROR, while integral=KI* ACCUMULATED ERROR
where accumulated error is error+old error

PI=proportional +integral.

please make your working code available for us to see the implementation because my real problem is the software implementation of these control law.

regards,
babalola.

Status
Not open for further replies.