PIC16F Sine Wave Inverter

Feedback in sine wave inverter (PIC16F series based)

I have previously shown how to calculate the values for the sine table: http://tahmidmc.blogspot.com/2011/01/generation-and-implementation-of-sine.html

I have also shown how to implement SPWM in PIC16: http://tahmidmc.blogspot.com/2012/10/generation-of-sine-wave-using-spwm-in_10.html

Now I will show how to implement feedback for SPWM.

Due to various limitations in PIC16, such as ADC speed, instruction time and the ALU, it is extremely difficult, if not impossible, to calculate in real time the values required for feedback in sinusoidal pulse width modulation (SPWM). Thus, to implement feedback, a different approach must be used. That approach would be to retrieve the values from a sine table that contains the duty cycle values for a specific duty cycle. Here is one sine table I used, for example:

const unsigned char sin_table[416]={

0, 16, 32, 47, 62, 77, 91, 103, 115, 126, 136, 144, 151, 156, 160, 162, 163, 162, 160, 156, 151, 144, 136, 126, 115, 103, 91, 77, 62, 47, 32, 16, //65%

0, 17, 33, 49, 65, 80, 94, 107, 120, 131, 141, 149, 156, 162, 166, 168, 169, 168, 166, 162, 156, 149, 141, 131, 120, 107, 94, 80, 65, 49, 33, 17, //67.5%

0, 17, 34, 51, 67, 82, 97, 111, 124, 135, 146, 154, 162, 167, 172, 174, 175, 174, 172, 167, 162, 154, 146, 135, 124, 111, 97, 82, 67, 51, 34, 17, //70%

0, 18, 35, 53, 69, 85, 101, 115, 128, 140, 150, 160, 167, 173, 178, 180, 181, 180, 178, 173, 167, 160, 150, 140, 128, 115, 101, 85, 69, 53, 35, 18, //72.5%

0, 18, 37, 55, 72, 89, 104, 119, 133, 145, 156, 166, 174, 180, 184, 187, 188, 187, 184, 180, 174, 166, 156, 145, 133, 119, 104, 89, 72, 55, 37, 18, //75%

0, 19, 38, 56, 74, 91, 108, 123, 137, 150, 161, 171, 179, 186, 190, 193, 194, 193, 190, 186, 179, 171, 161, 150, 137, 123, 108, 91, 74, 56, 38, 19, //77.5%

0, 20, 39, 58, 77, 94, 111, 127, 141, 155, 166, 176, 185, 191, 196, 199, 200, 199, 196, 191, 185, 176, 166, 155, 141, 127, 111, 94, 77, 58, 39, 20, //80%

0, 20, 40, 60, 79, 97, 114, 131, 146, 159, 171, 182, 190, 197, 202, 205, 206, 205, 202, 197, 190, 182, 171, 159, 146, 131, 114, 97, 79, 60, 40, 20, //82.5%

0, 21, 42, 62, 82, 100, 118, 135, 151, 165, 177, 188, 197, 204, 209, 212, 213, 212, 209, 204, 197, 188, 177, 165, 151, 135, 118, 100, 82, 62, 42, 21, //85

0, 21, 43, 64, 84, 103, 122, 139, 155, 169, 182, 193, 202, 210, 215, 218, 219, 218, 215, 210, 202, 193, 182, 169, 155, 139, 122, 103, 84, 64, 43, 21, //87.5%

0, 22, 44, 65, 86, 106, 125, 143, 159, 174, 187, 198, 208, 215, 221, 224, 225, 224, 221, 215, 208, 198, 187, 174, 159, 143, 125, 106, 86, 65, 44, 22, //90%

0, 23, 45, 67, 88, 109, 128, 147, 163, 179, 192, 204, 213, 221, 227, 230, 231, 230, 227, 221, 213, 204, 192, 179, 163, 147, 128, 109, 88, 67, 45, 23, //92.5%

0, 23, 46, 69, 91, 112, 132, 151, 168, 184, 198, 210, 220, 228, 233, 237, 238, 237, 233, 228, 220, 210, 198, 184, 168, 151, 132, 112, 91, 69, 46, 23 //95%

//0, 25, 49, 73, 96, 118, 139, 159, 177, 193, 208, 220, 231, 239, 245, 249, 250, 249, 245, 239, 231, 220, 208, 193, 177, 159, 139, 118, 96, 73, 49, 25, //100%

Each set of values corresponding to one duty cycle has 32 values.

A table pointer is used to retrieve the values for a given duty cycle. So, when the value of the table pointer is 0, the program reads the first 32 values (65% duty cycle), then the next 32 values when value of table pointer is 1 and so on. 

The microcontroller first starts with the lowest duty cycle and then analyses the output voltage. 

If the output voltage must be increased, the value of the table pointer is incremented and so, the next set of values is retrieved, increasing duty cycle and thus output voltage. If output voltage must be decreased, the value of the table pointer is decremented so that the previous set of values is retrieved, lowering duty cycle and thus output voltage. 

Here is how the table pointer is updated:

                    FBV = ADC_Get_Sample(FBCh);

                    if (FBV < 512){

                       FB_Step++;

                       if (FB_Step > 12) FB_Step = 12;

                    }

                    else{

                         if (FB_Step > 0){

                            FB_Step--;

                         }

                    }

                    adder = FB_Step << 5;

                    TMR1L = 0;

                    TMR1H = 0;

                    T1IF_bit = 0;

The reference value of the ADC is 5V, so 512 represents a voltage of 2.5V, which is the feedback reference voltage in this example. When voltage on ADC pin is >2.5V, table pointer value is decremented and when it is <2.5V, table pointer value is incremented. 

The required set of values is retrieved and applied by something like this:

        TBL_POINTER_NEW = TBL_POINTER_OLD + SET_FREQ;

        if (TBL_POINTER_NEW < TBL_POINTER_OLD){

           P1M1_bit = ~P1M1_bit;

        }

        TBL_POINTER_SHIFT = TBL_POINTER_NEW >> 11;

        DUTY_CYCLE = TBL_POINTER_SHIFT + adder;

        CCPR1L = sin_table[DUTY_CYCLE];

        TBL_POINTER_OLD = TBL_POINTER_NEW;

        TMR2IF_bit = 0;

Now that I've shown how to generate a sine table manually and with "Smart Sine", implement SPWM in PIC16 and now, how to implement feedback, you can easily make a sine wave inverter using the information I've provided. All you need to do is make sure you've understood what I've said and do some research on your own to make the project complete.

To make this clearer and so that you understand better, I am presenting some common questions and their answers. 

Question: I am designing a pure sine wave inverter using an output H bridge at 310vdc. Is there any need for feed back control if I keep the 310 Vdc steady?

Answer: If you can keep the 310VDC steady, then there is no need for feedback of SPWM. Your output will be relatively stable, since the DC bus is regulated.

Question: Why is the feedback not necessary, since there will be a voltage drop when there is increase in load? Remember the code is not incrementing or decrementing at this time. Now take an example of your normal modified sine inverter using SG3524 or any PWM IC. The output voltage drops when 

there is increase in load but the battery voltage doesn't change. Therefore there will be a need to control the code also. Right?

Answer: When there is increase in load, you will notice that the battery voltage always decreases due to the internal resistance. Measure the battery voltage of the inverter under load and you will see that it decreases as load increases. A battery that measures about 12-13V open circuit may drop to 11V or lower under load. Plus, there is a significant drop by the transformer under load.

Also, think about this: in the H-bridge converter, when load increases (and so current increases) but the +ve bus voltage is constant, where will the voltage be dropped? There is no transformer to deal with, as 

the primary side PWM will take care of drops by the transformer (and battery voltage drop) and keep the output fixed. The only place for voltage drop is the MOSFETs and there will be a drop in voltage in the MOSFETs, but not so large that the output voltage will be beyond acceptable bounds.

Question: You have shown 32 values for each duty cycle in the program. Can I use 192 for my 3.5kHz design?

Answer: You can use any number of duty cycle values in an array. 32 is usually sufficient, but with 192, greater precision can be had, especially since the frequency is 3.5kHz and the time period is much longer as compared to 16kHz. So, the SPWM is more accurate. However, just keep in mind that all of the values are stored in program memory. So, it will consume more program memory. You can use the software Smart Sine to generate the sine table: http://tahmidmc.blogspot.com/2012/10/smart-sine-software-to-generate-sine.html 

For manual calculation, go through this tutorial: http://tahmidmc.blogspot.com/2011/01/generation-and-implementation-of-sine.html

Question: What about this unsigned char I can see (416) in the code. What is it used for?

Answer: 32 values correspond to the sine wave at one duty cycle. I have set 13 duty cycle settings. 13 * 32 = 416

There are total 416 values in the array, 13 sets, and each set (containing 32 values) corresponds to one duty cycle setting.

Each set of values corresponding to one duty cycle has 32 values.

A table pointer is used to retrieve the values for a given duty cycle. So, when the value of the table pointer is 0, the program reads the first 32 values (65% duty cycle), then the next 32 values when value of table pointer is 1 and so on.

Practical Example:

The microcontroller first starts with the lowest duty cycle and then analyses the output voltage.

If the output voltage must be increased, the value of the table pointer is incremented and so, the next set of values is retrieved, increasing duty cycle and thus output voltage. If output voltage must be decreased, the value of the table pointer is decremented so that the previous set of values is retrieved, lowering duty cycle and thus output voltage. The table pointer keeps increasing by 1 to increase the duty cycle and so, the output voltage of the inverter.

Practical example: At the beginning of program execution, the table pointer is zero and the microcontroller starts with 65% duty cycle. Let's assume we have a 8V (primary) to 256V (secondary) transformer and a full bridge converter is being used to drive the transformer. The bridge is being driven by signals from the microcontroller - these SPWM signals.

The RMS voltage to the transformer primary will be (0.65 * 12/1.4142135)V = 5.5V.

Turns ratio of the transformer (primary:secondary) is 1:32.

So, secondary voltage (assuming 100% transformer efficiency) will be 32*5.5V = 176V.

As we require an output of 220V, this is lower than required. So, output voltage must be increased. So, table pointer is incremented to 1.

Then, duty cycle is 67.5% and output voltage is 183V.

Table pointer is incremented to 2.

Duty cycle is 70% and output voltage is 190V.

Table pointer is incremented to 3.

Duty cycle is 72.5% and output voltage is 197V.

Table pointer is incremented to 4.

Duty cycle is 75% and output voltage is 204V.

Table pointer is incremented to 5.

Duty cycle is 77.5% and output voltage is 210V.

Table pointer is incremented to 6.

Duty cycle is 80% and output voltage is 217V.

Table pointer is incremented to 7.

Duty cycle is 82.5% and output voltage is 224V.

Table pointer is decremented to 6.

Duty cycle is 80% and output voltage is 217V.

Table pointer is incremented to 7.

Duty cycle is 82.5% and output voltage is 224V.

Table pointer is decremented to 6.

Duty cycle is 80% and output voltage is 217V.

.

.

.

.

And so on.

This is how regulation is achieved.

This is all at 12V. But, you can see how the table pointer will be changed to maintain a constant output.