CCS C Software and Maintenance Offers
FAQFAQ   FAQForum Help   FAQOfficial CCS Support   SearchSearch  RegisterRegister 

ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

CCS does not monitor this forum on a regular basis.

Please do not post bug reports on this forum. Send them to CCS Technical Support

Power factor calculation using microcontroller

 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
heavenlyrider



Joined: 04 Mar 2016
Posts: 7
Location: India

View user's profile Send private message

Power factor calculation using microcontroller
PostPosted: Fri Apr 07, 2017 6:56 am     Reply with quote

hi,

I am using voltage divider network to measure voltage, and ACS712 (hall effect sensor) to measure current. I am using MCP3204 for ADC conversion.

Here is my code.

Code:

#include <18f46k22.h>

#FUSES NOWDT                    //No Watch Dog Timer
#FUSES NOBROWNOUT               //No brownout reset
#FUSES NOLVP                    //No low voltage prgming, B3(PIC16) or B5(PIC18) used for I/O
#fuses hsh

#use delay(crystal=20M)
#use rs232(baud=9600,parity=N,xmit=PIN_D6,rcv=PIN_D7,bits=8,stream=PORT1)


#define LCD_ENABLE_PIN  PIN_B3                                   
#define LCD_RS_PIN      PIN_B1                               
#define LCD_RW_PIN      PIN_B2                                 
#define LCD_DATA4       PIN_B4                                   
#define LCD_DATA5       PIN_B5                                   
#define LCD_DATA6       PIN_B6                                   
#define LCD_DATA7       PIN_B7

#define Sample 40
#define k_value 10

#INCLUDE <LCD.C>
#include "personal_mcp3204pic45k22.c"
#INCLUDE <math.h>

char read_count=0;
char tick=0;
unsigned int32 adc_accum_v=0;
unsigned int32 adc_accum_i=0;

unsigned int16 adc0_ref=0;
unsigned int16 adc1_ref=0;

float voltsperunit = 0.001220703125; //(volts per Unit  =5/4096)

float rms_v=0;
float rms_i=0;

float rms_v_cor=1.04245;

float rms_v_accum=0;
float rms_i_accum=0;

float adc0_step=0;

unsigned int32 adc_value_v[sample];
unsigned int32 adc_value_i[sample];

unsigned int32 sampling_period=60536; // 65536-60536=5000 >> 5000x200ns=1ms

float apparent_power=0;
float average_power_accum=0;
float vi_accum=0;

char i,k;

#INT_RTCC         
void  RTCC_isr(void)
{
set_rtcc(sampling_period);
tick=1;
read_count++;
return;
}

void initialize() {   
   
   adc_init();
   lcd_init();
   delay_ms(200);   
   setup_timer_0(RTCC_DIV_8);      //13.1 ms overflow       
}

void main()
{
   set_tris_b(0x01);
   set_tris_d(0x80);   
   
   initialize();         
   
   adc1_ref = 2048;
   adc0_ref = 2048;
   adc0_step = 2.5/adc0_ref;   
   k=0;         
   while (true) {

      set_rtcc(sampling_period);
      enable_interrupts(INT_RTCC);
      enable_interrupts(GLOBAL);
     
      while (read_count<Sample) {
     
         while(tick==0) {}
         tick=0;       
       
         adc_value_v[read_count-1] =read_analog(0,2);   // channel, slave                 
         //adc_value_i[read_count-1] = read_analog(5,1);   // code for acs712  // try this pin too                 
         adc_value_i[read_count-1] = read_analog(0,1);
      }     
     
      disable_interrupts(INT_RTCC);
      disable_interrupts(GLOBAL);
      read_count=0;                 
     
      for (i=0;i<Sample;i++) {
         
         if (adc_value_v[i]>=adc0_ref) {adc_value_v[i] = adc_value_v[i] - adc0_ref;}
         else {adc_value_v[i] = adc0_ref - adc_value_v[i];}
         
         if (adc_value_i[i]>=adc1_ref) {adc_value_i[i] -= adc1_ref;}
         else {adc_value_i[i] = adc1_ref - adc_value_i[i];}
   
         
         adc_accum_v +=  (adc_value_v[i] * adc_value_v[i]);
         adc_accum_i +=  (adc_value_i[i] * adc_value_i[i]);   
                 
         vi_accum += ((adc_value_v[i]*adc0_step*201) * rms_v_cor) * (adc_value_i[i] * (voltsperunit/0.066));   
         
         printf("\n%fV %fI",((adc_value_v[i]*adc0_step*201) * rms_v_cor),((adc_value_i[i] * (voltsperunit/0.066))));
       }     
       printf("\n\r\n\r\n\r");
      average_power_accum += vi_accum /Sample;       
      vi_accum=0;
     
      rms_v = ((sqrt(adc_accum_v /Sample))*adc0_step*201) * rms_v_cor ;     
      rms_i = sqrt(adc_accum_i /Sample) * (voltsperunit/0.066);
     
      rms_v_accum += rms_v;
      rms_i_accum += rms_i;
     
      k++;
     
      if (k == k_value) {   
         k=0;
         
         lcd_gotoxy(1,1);
         printf(lcd_putc,"\f%fV %fA                       ",((rms_v_accum/k_value)-5),abs(((rms_i_accum/k_value)-0.03)));         
         delay_ms(2000);
         
         apparent_power=((rms_v_accum/k_value)-5)*abs(((rms_i_accum/k_value)-0.03));         
         
         lcd_gotoxy(1,1);
         printf(lcd_putc,"\f%0.1fW %0.1fKVA                       ",(average_power_accum/k_value),apparent_power);         
         lcd_gotoxy(1,2);
         printf(lcd_putc,"PF: %f                       ",((average_power_accum/k_value)/apparent_power));
         
          printf("\f%fV %fA                       ",((rms_v_accum/k_value)-5),abs(((rms_i_accum/k_value)-0.03)));
          printf("\n%0.1fW %0.1fKVA                       ",(average_power_accum/k_value),apparent_power);
          printf("\nPF: %f                       ",((average_power_accum/k_value)/apparent_power));
          printf("\n\r\n\r\n\r");
         
         rms_v_accum=0;
         rms_i_accum=0;
         
         average_power_accum=0;
     }
      adc_accum_v=0;
      adc_accum_i=0;           
   }
}



I can measure the rms voltage, rms current and averaged power. But i have problem in measuring Power factor. While connecting a ceiling fan, my meter's power factor is always near to 0.9 but a reference meter which am i using shows 0.5 to 0.9 for various speeds. Please give me some idea to rectify this problem.

This is my hardware:
[img]https://ibb.co/ncgv6F[/img]
_________________
Thanks & Regards,
Heavenlyrider.
Mike Walne



Joined: 19 Feb 2004
Posts: 1785
Location: Boston Spa UK

View user's profile Send private message

PostPosted: Fri Apr 07, 2017 11:23 am     Reply with quote

We don't have your ADC code, which does not help.

Several approaches can be tried.

1)
You could record a series of current and voltage readings.
Then work out RMS values, real & apparent power and PF by hand.
Could be revealing.

2)
Seriously simplify, get rid of all the correction factors and fudges.
RMS values, real & apparent power will all be wrong but PF should be OK.

3)
Use a simpler load.
Say an X rated capacitor.
You SHOULD then get a PF of zero.

On UK mains 1uf gives RMS current of ~70mA.

Just a few things to try.

Mike
Ttelmah



Joined: 11 Mar 2010
Posts: 19561

View user's profile Send private message

PostPosted: Fri Apr 07, 2017 11:53 am     Reply with quote

Look through your samples to find the zero crossing point of the current. (interpolate between the samples each side of this point). Do the same for the voltage. Given you know your sampling rate, you can then calculate the time between these, and calculate the phase angle. Cosine of this is the PF.
Any other approach goes wrong if the waveshape goes non sinusoidal.....
Mike Walne



Joined: 19 Feb 2004
Posts: 1785
Location: Boston Spa UK

View user's profile Send private message

PostPosted: Sun Apr 09, 2017 2:11 am     Reply with quote

I gave up trying to decipher your schematic.
(You appear to be using drawing methods I abandoned half a century ago.)

You seem to be assuming that voltage & current readings of 2048 coincide with zero crossings.
That's possibly not the case and unneccessary.
You are creating an array for all your current and voltages but don't use them in any real way.
I'm guessing you are working with 50Hz mains.

There is a neater way to do all your calculations which:-

1) Uses less maths, and only unsigned integers except for the final stage.
2) Does not require the use of an array.
3) Does not require you to guess at (or make assumptions about) the zero crossing point.
4) Works for both sinusoidal and non-sinusoidal waveforms.

You simply process the raw current and voltage readings as follows.

Start by resetting all the running totals to zero then do the following:-

1) Calculate Square of Voltage (V2).
2) Calculate Square of Current (I2).
3) Calculate product of Current&Voltage (IV).

Keep running totals of:-
4) Sum_of_Voltages. Sum_V
5) Sum_of_Voltages_Squared. Sum_V2.
6) Sum_of_Currents. Sum_I
7) Sum_of_Currents_Squared. Sum_I2.
8) Sum_of_Current*Voltage, Sum_IV

Assuming you have n samples you then calculate:-

9) Voltage_Mean as (Sum_V)/n. (This is the zero crossing level for the AC Voltage)
10) Voltage_RMS as SQRT(( Sum_V2 )/n - Voltage_Mean^2 )
11) Similar for Current_Mean and Current_RMS.
12) Power_Real as ((Sum_IV)/n - (Voltage_Mean)*(Current_Mean)).
13) Power_Apparent and PF are then straightforward.
14) Convert to engineering units.

At this stage you have an arrays of all your values.
Take a complete set of values and process by hand by both your method and mine.
(Or transfer to Excel and let the PC do the work)
Both methods SHOULD yield the same results.

On the other hand you could try with a small set of simple numbers and use pencil and paper.
You could take samples for multiples of 100ms (5 cycles of 50Hz, 6 cycles of 60Hz).
That way you could work on either 50/60 mains.

Mike
temtronic



Joined: 01 Jul 2010
Posts: 9253
Location: Greensville,Ontario

View user's profile Send private message

PostPosted: Sun Apr 09, 2017 5:28 am     Reply with quote

OK, I had a look at the schematic and it makes NO sense to me and like Mike I have several decades of design under my belt.
The glaring problem I have is in feeding an AC voltage into the ADC chip(MCP3204) that was only designed for +ve inputs.
The second ADC (for current ) isn't needed either.

What is missing is a zero cross detector. If that was wired in, it's dead simple to aquire the voltages and currents and do the 'math'. the 'math' of course would be done in scaled integers,easily in realtime.

Also missing is a TTL<>RS232 convertor for the PC interface. Typically a MAX232 device, the 2nd section of it can be used for the aforementioned 'zero cross detector'. That clever bit of kit was done for a 'Mains frequency meter' 30 years ago, using a PIC16C84.

Jay
Ttelmah



Joined: 11 Mar 2010
Posts: 19561

View user's profile Send private message

PostPosted: Sun Apr 09, 2017 7:46 am     Reply with quote

Aargh.....

I must admit I hadn't seen that there was a circuit link.
Whimper.
dyeatman



Joined: 06 Sep 2003
Posts: 1938
Location: Norman, OK

View user's profile Send private message

PostPosted: Sun Apr 09, 2017 11:12 am     Reply with quote

Here are several more simple zero crossing detectors.

http://www.bristolwatch.com/ele2/zero_crossing.htm
_________________
Google and Forum Search are some of your best tools!!!!
Mike Walne



Joined: 19 Feb 2004
Posts: 1785
Location: Boston Spa UK

View user's profile Send private message

PostPosted: Sun Apr 09, 2017 11:56 am     Reply with quote

The key advantage of my method of calculating is that you do not need a zero crossing detector at all.
If you do use one it can be used to synchronise your sampling to the incoming signal.
That way you make measurements over several complete whole cycles.

Mike

No response from O/P so assume this topic is dead.
heavenlyrider



Joined: 04 Mar 2016
Posts: 7
Location: India

View user's profile Send private message

PostPosted: Mon Apr 24, 2017 6:36 am     Reply with quote

Hi Mike,

Quote:


The key advantage of my method of calculating is that you do not need a zero crossing detector at all.
If you do use one it can be used to synchronise your sampling to the incoming signal.
That way you make measurements over several complete whole cycles.

Mike




I found that the problem was in the MCP3204 library file, where the SPI function itself uses 400us delay. So that the voltage and current samples cannot be taken at the same time. i adjusted those delays, Now my program is working without any problem.

And MIKE, Thanks for your help. I tried your method too, the results seems to be pretty good than my own code.
_________________
Thanks & Regards,
Heavenlyrider.
guy



Joined: 21 Oct 2005
Posts: 297

View user's profile Send private message Visit poster's website

PostPosted: Wed Apr 26, 2017 1:16 am     Reply with quote

If you need to rectify the sinewave signal for the ADC without losing the Vf of the diodes, use a good Precision Detector circuit.
Mike Walne



Joined: 19 Feb 2004
Posts: 1785
Location: Boston Spa UK

View user's profile Send private message

PostPosted: Fri Apr 28, 2017 10:08 am     Reply with quote

heavenlyrider wrote:
Hi Mike,

Quote:


The key advantage of my method of calculating is that you do not need a zero crossing detector at all.
If you do use one it can be used to synchronise your sampling to the incoming signal.
That way you make measurements over several complete whole cycles.

Mike



I found that the problem was in the MCP3204 library file, where the SPI function itself uses 400us delay. So that the voltage and current samples cannot be taken at the same time. i adjusted those delays, Now my program is working without any problem.

And MIKE, Thanks for your help. I tried your method too, the results seems to be pretty good than my own code.


A great many ADC's cannot measure two channels simultaneously.
My usual solution is to take readings either side of each other.
In your case that would be measure Amps, Volts followed by Amps again.
If you get the timing right you can assume the average Amps reading is in effect taken at the same time as the volts reading.
Job done.

Mike
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2005 phpBB Group