How I Monitor Power

I'm using current transformers (200A) that clip around the main power lines coming into the house.  These feed one of the analog inputs to an Arduino Duemilanove.  I also sample the wall power level to give me a voltage reference and use a basic wall wart for power.  I added a Wishield for wifi since there is no network connection near the power panel.

Like a whole lot of people, my wireless gateway to the DSL line is way across the house in the opposite corner and wifi won't go that far.  So I recycled an old wireless router by turning it into an access point and mounted it as close to the power panel as I could; I already had a wired network connection in the garage just not close to where the power panel was.

Every couple of seconds the Arduino samples the power levels, calculates power and holds the values in variables.  I have a minimal web server running on the Arduino interfaced to the Wishield so I can get the power levels with an HTTP request.  However, the network connection turned out to be unreliable so I had to sample it locally and use an HTTP put to send the data to Pachube.com.  I have a laptop that runs the grab and forward software as a simple batch script running in a command window.

So, it's power panel to Arduino to wireless to laptop to gateway to Pachube.  Confused yet?  

I'm only serving comma separated values so they're easy to parse.  In order they are, real power, apparent power, power factor, rms current, rms voltage and frequency.  This makes it really easy to grab the data and forward it using a batch file.

Details on the Implementation

Somehow, I needed to measure the current flowing through the wires into the house.  There are a number of devices out there that can do this, but they're expensive, won't work on my house, inadequate or the company wouldn't respond to questions.  And yes, I did try to call them and even left messages.  But prowling the web looking at these devices I discovered a little component called the current transformer.

These things are a coil of wire that wraps around the wire and inductively measures the power flowing through a wire.  There are a ton of web descriptions of these devices so learning about them was relatively easy; finding one at a reasonable price was a different matter.  Finally, I found a nice device that would work at my house.  I have a 400 Amp service that splits into two 200 Amp distributions.  I'm currently only using half of it for 200 Amps but the wires leading to it are a little over a half inch in diameter.  I actually broke the first device I tried by forcing it over the wire.


Here are the two devices, one on each leg of the 240 split phase mains we have here in the US.  They were not hard to install; just clip them around the mains and run the wire out of the box.  There's very little risk of shock since the wires are insulated and you don't have to touch them to clip the CT (current transformer) around the wire.  They tended to slip down the wire so a couple of plastic ties hold them in place.

You can actually tie these in series, attach a multimeter and get a reasonable indication of the power usage by watching the voltage rise and fall as you turn on appliances.  The voltage output has to be compared against some standard before you actually know how much power you're using, but you can certainly tell they are working.

The CTs are available from ITeadStudio and usually have about a two week lead time.  Besides the 200 Amp version I used, there are other styles and ratings available.  Just be sure to get one big enough to go around the wire.




Most of my implementation was blatantly stolen from Trystan Lea.  Please visit his site at http://openenergymonitor.org/emon/ for an in-depth discussion of his ongoing implementation.  I took his Arduino code for power monitoring, modified it to work with two current transformers, and added network code to serve data based on a simple html request.  Trystan has single phase 240 power and didn’t need to consider using double CTs, but don’t worry, you simply tie the two of them in series if you have split phase 220.  My device hasn’t made it past the breadboard stage.  Why bother right now?  It works fine and I can get back to it anytime.



The transformer on the left is a 10V center taped step down to provide a reference for the AC mains.  The wires coming in the center are the outputs from the CTs and are tied in series.  I use the center connection of the CTs to calibrate a single CT; one has to do this only once in the beginning.  Yes, I know that the transformer could be used to power the Arduino, that will come in time, but for now…it works, don’t fix it.  The wire leaving the Arduino and looping up to the right is the Wifi antenna; I got the Wishield with the separate antenna to extend the range and prevent worrying about where I put the device.

My future plans for this device are to add screw terminals for the incoming wires, get power from the step down transformer removing the wall wart and solder the various parts down on a proto board to pretty it up.  Heck, someday I might actually mount it on a pretty plastic base instead of the piece of plywood I found.  I’ll never cover it up though since it’s too much fun to show off the circuitry.

Trystan’s site (http://openenergymonitor.org/emon/) has tons of details on how the measurements are made and links to the source he used.  Each implementation will have some nuance that will need adaptation though so use his work as a starting example; consider my work as a recreation and proof of concept.  But basically rapid measurements of the instantaneous voltage and current are squared, summed and averaged to get the Vrms and Irms.  These are used along with the power factor to get a fairly accurate measure of real power usage.  I simply combined this with a very simple web server to pass the data along.


Update March19, 2011:  I had a failure of a WiShield in the power display that I will detail on that page later, but this pointed out that I need to have a wireless communication path that has massive availability.  I chose XBee as the tool to use.  Since this entire set of projects is for saving power, I started with the power monitor.  After doing a bunch of work to enable the device to send over XBee radio I realized I had forgotten how I had built the darn thing.  So I reverse engineered my own device to get the schematic and am posting it here to help other folks and provide a reference for myself next time.


Simple isn't it?  Nothing but a couple of voltage sources and dividers to scale the values for the Arduino to read.

The Arduino Sketch #1

//Basic energy monitoring sketch plus kwh and frequency calc - by Trystan Lea
//Licenced under GNU General Public Licence more details here
// openenergymonitor.org
/*
 * Credits:
 * Most of the power measurement and calculations were invented by Trystan Lea and documented at
 * http://openenergymonitor.org/.  I modified it for the split phase 240 in residential use in the U.S.
 * I'm using a ladyada boot rom (purchased directly from her site) to overcome weak network problems
 * and multiple vulnerable arduinos.  A lot of the remaining code was taken from example sketches
 * supplied by the Arduino site www.arduino.cc
 *
 * Open source rules!
 * Dave Thompson
 */


//Sketch measures voltage and current.
//and then calculates useful values like real power,
//apparent power, powerfactor, Vrms, Irms, frequency and kwh.

#include <WiServer.h>
#include <avr/wdt.h>

#define WIRELESS_MODE_INFRA 1
#define WIRELESS_MODE_ADHOC 2

// Wireless configuration parameters ----------------------------------------
unsigned char local_ip[] = {192,168,0,200}; // IP address of WiShield
unsigned char gateway_ip[] = {192,168,0,1}; // router or gateway IP address
unsigned char subnet_mask[] = {255,255,255,0}; // subnet mask for the local network
PROGMEM const prog_char ssid[] = {"whatever"}; // max 32 bytes

unsigned char security_type = 1; // 0 - open; 1 - WEP; 2 - WPA; 3 - WPA2

// WPA/WPA2 passphrase
const prog_char security_passphrase[] PROGMEM = {"whatever"}; // max 64 characters

// WEP 128-bit keys
// sample HEX keys
prog_uchar wep_keys[] PROGMEM = { 0x11, 0x11, 0x11, 0x11, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Key 0
 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Key 1
 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Key 2
 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 // Key 3
};

// setup the wireless mode
// infrastructure - connect to AP
// adhoc - connect to another WiFi device
unsigned char wireless_mode = WIRELESS_MODE_INFRA;

unsigned char ssid_len;
unsigned char security_passphrase_len;
// End of wireless configuration parameters ----------------------------------------


//Setup variables
int numberOfSamples = 3000;

//Set Voltage and current input pins
int inPinV = 4;
int inPinI = 5;

//Calibration coeficients
double VCAL = 0.592;
double ICAL = 03.2;
double PHASECAL = 0.1;

//Sample variables
int lastSampleV,lastSampleI,sampleV,sampleI;

//Filter variables
double lastFilteredV, lastFilteredI, filteredV, filteredI = 0;
double filterTemp;

//Stores the phase calibrated instantaneous voltage.
double calibratedV;

//Power calculation variables
double sqI,sqV,instP,sumI,sumV,sumP;

//Useful value variables
double realPower,
       apparentPower,
       powerFactor,
       Vrms,
       Irms;

#define NETTIMECHECK 120
long netTimeout = 0;  // counter to check for net activity    
    
  //--ENERGY MEASURMENT VARIABLES------------------------------
    //Calculation of kwh

    //time taken since last measurment timems = tmillis - ltmillis;
    unsigned long ltmillis, tmillis, timems;
    //time when arduino is switched on... is it 0?
    unsigned long startmillis;
  
    //kwhTotal is cumulative kwh today, the other 3 are historical over the last 3 days for comparison.
    double kwhTotal =0.0;
  //-----------------------------------------------------------

  //--FREQUENCY MEASURMENT VARIABLES---------------------------
    //time in microseconds when the voltage waveform
    //last crossed zero.
    unsigned long vLastZeroMsec;
    //Micro seconds since last zero-crossing
    unsigned long vPeriod;
    //Sum of vPeriod's to obtain an average.
    unsigned long vPeriodSum;
    //Number of periods summed
    unsigned long vPeriodCount;
  
    //Frequency
    float freq;
  
    //Used to filter out fringe vPeriod readings.
    //Configured for 50Hz
    //- If your 60Hz set expPeriod = 16666
    unsigned long expPeriod = 16666;
    unsigned long filterWidth = 2000;
  //-----------------------------------------------------------

// This is my page serving function that generates web pages
boolean sendMyPage(char* URL) {
    /* The assumption is that if the code got here, the network is alive.  However
        if too much time passes without someone requesting data, the network may
        have died.  Therefore, measure the time and after it passes set a watchdog
        to expire.  In this routine the timer will be reset and the main loop will
        set the watchdog.
    */
    netTimeout = millis();        // made it, reset the timer
    wdt_reset();                  // turn off the watchdog
    wdt_disable();                // and disable it just in case
    Serial.println("net request");

    // Check if the requested URL matches "/"
    if (strcmp(URL, "/") == 0) {
        WiServer.print(realPower);
        WiServer.print(", ");
        WiServer.print(apparentPower);
        WiServer.print(", ");
        WiServer.print(powerFactor);
        WiServer.print(", ");
        WiServer.print(Irms);
        WiServer.print(", ");
        WiServer.print(Vrms);
        WiServer.print(", ");
        WiServer.print(freq);
        // URL was recognized
        return true;
    }
    // URL not found
    return false;
}

/* Measurement calculations */

int PwrCalcs()
{
  for (int n=0; n<numberOfSamples; n++) // gather samples
  {

     //Used for offset removal
     lastSampleV=sampleV;
     lastSampleI=sampleI;
     // wireless server has to have some time to work
     WiServer.server_task();
     //Read in voltage and current samples.
     sampleV = analogRead(inPinV);
     sampleI = analogRead(inPinI);

     //Used for offset removal
     lastFilteredV = filteredV;
     lastFilteredI = filteredI;

     //Digital high pass filters to remove 2.5V DC offset.
     filteredV = 0.996 * (lastFilteredV+sampleV-lastSampleV);
     filteredI = 0.996 * (lastFilteredI+sampleI-lastSampleI);

     //Phase calibration goes here.
     calibratedV = lastFilteredV + PHASECAL * (filteredV - lastFilteredV);

     //Root-mean-square method voltage
     //1) square voltage values
     sqV= calibratedV * calibratedV;
     //2) sum
     sumV += sqV;

     //Root-mean-square method current
     //1) square current values
     sqI = filteredI * filteredI;
     //2) sum
     sumI += sqI;

     //Instantaneous Power
     instP = abs(calibratedV * filteredI);
     //Sum
     sumP += instP;

     //--FREQUENCY MEASURMENT---------------------------        
     if (n==0) vLastZeroMsec = micros();

     //Check for zero crossing from less than zero to more than zero
     if (lastFilteredV < 0 && filteredV >= 0 && n>1)
     {
       //period of voltage waveform
       vPeriod = micros() - vLastZeroMsec;

       //Filteres out any erronous period measurments
       //Increases accuracy considerably
       if (vPeriod > (expPeriod-filterWidth) && vPeriod<(expPeriod+filterWidth))
       {
          vPeriodSum += vPeriod;
          vPeriodCount++;
       }
       vLastZeroMsec = micros();
     }
  } //end of sample gathering

  //Calculation of the root of the mean of the voltage and current squared (rms)
  //Calibration coeficients applied.
  Vrms = VCAL*sqrt(sumV / numberOfSamples);
  Irms = ICAL*sqrt(sumI / numberOfSamples);

  //Calculation power values
  realPower = VCAL*ICAL*sumP / numberOfSamples;
  apparentPower = Vrms * Irms;
  powerFactor = realPower / apparentPower;

  //FREQUENCY CALCULATION--------------------------
  freq = (1000000.0 * vPeriodCount) / vPeriodSum;
    
  vPeriodSum=0;
  vPeriodCount=0;
  //------------------------------------------------

  //--ENERGY MEASURMENT CALCULATION----------------  
      
  //Calculate amount of time since last realpower measurment.
  ltmillis = tmillis;
  tmillis = millis();
  timems = tmillis - ltmillis;
    
  //Calculate number of kwh consumed.
  //kwhTotal = kwhTotal + ((realPower/1000.0) * 1.0/3600.0 * (timems/1000.0));

  //Output to serial
  Serial.print("RP=");
  Serial.print(realPower);
  Serial.print(" AP=");
  Serial.print(apparentPower);
  Serial.print(" PF=");
  Serial.print(powerFactor);
  Serial.print(" V=");
  Serial.print(Vrms);
  Serial.print(" I=");
  Serial.print(Irms);
  Serial.print(" KW=");
  Serial.print(kwhTotal);
  Serial.print(" F=");
  Serial.println(freq);

    //Reset accumulators
  sumV = 0;
  sumI = 0;
  sumP = 0;
}

void setup()
{
  
  Serial.begin(57600);
  Serial.println("Initialize web server");

  wdt_enable(WDTO_8S);          // I'm giving the network 8 seconds to set itself up
  // Initialize WiServer and have it use the sendMyPage function to serve pages
  WiServer.init(sendMyPage);
  // Enable Serial output and ask WiServer to generate log messages (optional)
  wdt_reset();                  // made it, turn off the watchdog until things start working
  wdt_disable();
  Serial.println("Enable webserver");
  WiServer.setIndicatorPins(5, 6);              //This could make it fun to monitor.
                                                //However, the Wishield uses 2,8,9,10,11,12,13
                                              
                                              

  //debug mode for webserver
  //WiServer.enableVerboseMode(true);

  netTimeout = millis();               // timer to make sure the net is active

  //--ENERGY MEASURMENT SETUP--------------------------------
  //Calculation of kwh
  tmillis = millis();
  startmillis=tmillis;
  //---------------------------------------------------------
}

void loop()
{
    // get power calcs into variables
  PwrCalcs();
  // Run WiServer
  WiServer.server_task();
  delay(100);
  if ((millis() - netTimeout) >= (NETTIMECHECK * 1000))  //has too much time passed?
  {
    wdt_enable(WDTO_8S);    // eight seconds from now the device will reboot
    Serial.println("net timeout, rebooting");
    while(1) {}
  }
}

35 comments:

  1. Cool how you glued together various components to build a smart solution that really seems to pay off

    I saw your post on jeelabs and thought I'd just check your project out.

    ReplyDelete
  2. Thanks for visiting. This is, and has been, an interesting project that actually pays off.

    ReplyDelete
  3. Hello Dave, Nice work! do you mind if I link through to your write-up I'm sure it would be of great use to people. I have put a link at the bottom of the page here:
    http://openenergymonitor.org/emon/node/58

    Thanks, Trystan

    ReplyDelete
  4. Of course I don't mind. Especially since I stole so many ideas from you and your site.

    ReplyDelete
  5. As I understand it, you have put the two CT's on the 220V mains input wires in series so you are only using a single ADC channel on the Arduino. Is this accurate?

    Otherwise, nice work. I am building a similar system based on Trystan's info as well. Thanks for sharing.

    -Jon

    ReplyDelete
  6. Yes, the two CTs are in series on one input to the Arduino. I calibrated them one at a time using a current meter around the wire then hooked them up. If you get too low a level when you hook them in series reverse the phase on one of them. I did the final test with a 2KW load (large light) plugged into one side then the other.

    ReplyDelete
  7. Nice work and great website.

    Thanks for sharing.

    Dawn.

    ReplyDelete
  8. Hi, I noticed that you and Trystan Lea seem to disagree in the RMS calculation section 1).

    You square the CalibratedV (what Lea calls shiftedV), but Lea squares filteredV...

    It seems to me that you are probably correct, can you confirm that? Thanks!

    ReplyDelete
  9. Y'know, I'm not sure there's a significant difference. I chose to square the calibrated value because it matched the metering equipment I was using that way. I'm not sure why Trystan did it his way. However, I was able to read a commercial meter and compare it to mine and that gave me a bunch more confidence in the voltage reading.

    Basically, I wanted my values to be as close to a calibrated commercial source as I could get to keep the debugging and tweaking down.

    ReplyDelete
  10. I'm from Brazil and we have 2 x 110v phases and 1 neutral.

    How did you measure voltage on 2 phases? You wire your transformer only on one phase or each leg of transformer input on each phase and you don't use the neutral? Is it better to use two transformers to get two different reading from each phase?

    ReplyDelete
  11. Take a look at the pictures above, I used two CTs, one on the hot leg of each phase. You can then wire them in series to get the total power used or read each one in the code and add them together. To calibrate them, only hook one up and put a controlled load on that leg of the power.

    ReplyDelete
  12. Dave,

    I am trying to get my graphs to work in Pachube. Right now, I only have one graph and cannot figure out how to get multiple datastreams. How did you get yours to works.

    Thanks,

    Paul.

    ReplyDelete
  13. Notice in the sketch I sent a comma separated string of values, something like:

    100,200,300,400,500

    Pachube itself separated these out into separate data streams. At first I had forgotten a couple of things and sent about 10 items separated by strings and it took some time to figure out why I had too many datastreams showing up. I simply deleted the extras on pachube and corrected my code.

    So, each value in the csv (comma separated values) string is assigned to a data stream.

    I was too lazy to learn JSON or EML or the other methods when something this simple was available.

    ReplyDelete
  14. Dave,

    Thanks for your reply.

    I finally figured it out. If the content_length is larger than the length of the data being received it won't work.

    I just put in a number for my content_length. Do you have a formula to find the data length or did you just do it by putting in a numerical value too.

    Thanks,

    Paul.

    ReplyDelete
  15. I have two different devices that update to pachube right now. I'll be using only one in a couple of weeks. I'm moving my update operation to a more dedicated device. However, with the WiShield, it takes care of the length for me and I don't have to do anything. With an 'official' arduino ethernet board, I get the data string all formated then then do a strlen(dataString), send the standard header, with the length in it and lastly, the data string.

    Here's the code fragment that I use:

    strcpy_P(Dbuf2, PSTR("%d,%d,0.%d,%d.%02d,%d.%02d,%d.%02d"));
    sprintf(dataBuf,Dbuf2,
    (int)round(realPower),
    (int)round(apparentPower),
    (int)(powerFactor*100),
    (int)rmsCurrent,
    (int)(((rmsCurrent+0.005) - (int)rmsCurrent) * 100),
    (int)rmsVoltage,
    (int)(((rmsVoltage+0.005) - (int)rmsVoltage) * 100),
    (int)(frequency),
    (int)(((frequency+0.005) - (int)frequency) * 100));
    strcpy_P(Dbuf,PSTR("Pachube Connecting..."));
    Serial.print(Dbuf);
    if(pachube.connect()){
    strcpy_P(Dbuf,PSTR("OK"));
    lastConnectionTime = millis();
    Serial.println(Dbuf);
    tNow = now();
    strcpy_P(Dbuf,PSTR("PUT /api/feedNumber.csv HTTP/1.1\n"));
    pachube.print(Dbuf);
    strcpy_P(Dbuf,PSTR("Host: www.pachube.com\n"));
    pachube.print(Dbuf);
    strcpy_P(Dbuf,PSTR("X-PachubeApiKey:bunch of numbers\n"));
    pachube.print(Dbuf);
    strcpy_P(Dbuf,PSTR("Content-Length: "));
    pachube.print(Dbuf);
    pachube.println(strlen(dataBuf), DEC); // this has to be a println
    strcpy_P(Dbuf,PSTR("Content-Type: text/csv\n"));
    pachube.print(Dbuf);
    strcpy_P(Dbuf,PSTR("Connection: close\n"));
    pachube.println(Dbuf);
    pachube.println(dataBuf);
    pachube.stop();
    }

    Notice that I had some trouble with the darn floating point numbers getting them into a sprintf that doesn't support floats. But that was easier than writing special code for it.

    Hope this helps

    ReplyDelete
  16. Dave,

    Cool. Thanks for the code. I had problem with floats too. So I just stuck with client.print instead of sprintf but it is kind of a hack job and I would like to pretty it up.

    cheers,

    Paul.

    ReplyDelete
  17. The information you have on this page is great, and it's prompted me to start getting into Arduino projects. I've been able to pretty much piece together the general way I could go about duplicating your work, but I cannot seem to source the ac/ac step-down transformer.

    Any suggestions would be greatly appreciated.

    ReplyDelete
  18. Something like this will work fine. http://search.digikey.com/scripts/DkSearch/dksus.dll?Cat=590573&k=T1004-ND It's a wall wart for supplying power for a clock or something. I picked mine up at Fry's Electronics when I was there drooling over other stuff. Just look for something that will take line voltage to 6-12VAC. The only hard requirement is that it be AC to AC, which leave out cell phone chargers and such. You can tailor the voltage divider to provide reference voltage to the Arduino which only needs a volt or two.

    ReplyDelete
  19. Hi Dave!

    Great work! Can u explain where this come from (mathematically)?

    "kwhTotal = kwhTotal + ((realPower/1000.0) * 1.0/3600.0 * (timems/1000.0));"

    Thanks!

    Gabriel

    ReplyDelete
  20. add real power / 1000 (power in watts) / number of seconds in an hour * how long it has really been in seconds

    Notice that I don't actually use this number. There is a small amount of drift from what I read and what they read. It's a tiny amount, but it adds up over time to totally confuse me. I could have tailored this more and added corrections, but what I was really interested in was what I'm using right now. Controlling it on an ongoing basis is better than looking at it at the end of the month.

    ReplyDelete
  21. Hey, this is a really cool setup, I'm building a project where the arduino acts as a webserver and hosts a simple html page to control relays. I cannot perform exactly what I like though because of the below errors. Seems the sample libraries we used are the same so I thought maybe you ran into this problem too. The sample code Webserver works and I can host a html page in one big string, but I want to print different things to the server to change/update the website on current values. This may be a bit different but you seem knowledgeable so I thought I would ask. Also, having trouble with the get request to receive data when a button on the webpage is clicked. Thank you very much.

    C:\Users\COLINV~1\AppData\Local\Temp\build8672606563252562455.tmp/sketch_may11a.cpp:283: undefined reference to `WiServer'
    C:\Users\COLINV~1\AppData\Local\Temp\build8672606563252562455.tmp/sketch_may11a.cpp:173: undefined reference to `Server::server_task()'

    ReplyDelete
  22. This looks like the compiler can't find the library. The source needs to be in the library directory of the Arduing IDE and you have to restart the IDE before it will know it is there. Also, it can happen if you forget the #include for the WiShield software up at the top of the module.

    ReplyDelete
  23. Dear, The port analog arduino number of A4 and A5 I turn on the circuit above? I can connect the output of 5 V arduino too?

    ReplyDelete
  24. Yes, I used the Arduino 5V and ground.

    ReplyDelete
  25. Why are you using 320Ohm burden resistor with this CT?

    I made some calculations and on 3.3v I would use 36Ohm resistors or 56Ohm on 5v.

    ReplyDelete
  26. If I remember right, it was what I had on hand at the time. It's easy to correct for values (within reason) in the code. That's the beauty of using a computer.

    ReplyDelete
  27. I truly like to reading your post. Thank you so much for taking the time to share such a nice information. I'll definitely add this great post in my article section.
    Freight Forwarding Software

    ReplyDelete
  28. I was looking for a way to send you a private email, but it doesn't look like there's a way. I hate to offer any feedback that isn't completely constructive, so I hope this helps you at some point in the project:

    This is a great project and I love what you're doing. Just one issue that might really confuse you or someone else at some point trying to duplicate this(unless I'm really missing something).

    The way you have this configured is not really measuring what you think it's measuring. I'm sure you've calibrated out some error but various reactive appliances will not read correctly (unless, like I said, I'm really missing something). The two 110 lines coming in to your home are two separate feeds. They are 180 degrees out of phase and power various device in your home either completely separately, or in the case of a 220 dryer, as a combined (but out of phase) load. From your photo, you've got the CT's placed out of phase from each other, which will (sort of) provide an additive effect. However, since reactive loads will shift the phase of each one a different amount, what you end up with is two semi-out of phase signals combined. To add insult to injury, you are only using one of the two lines for your voltage reading. As such, any reactive voltage components on the second line are completely ignored. As such, a reactive component on the unmeasured line will read as if it is purely resistive.

    You might think the error is small, but I would estimate that if you calibrate to a load on one line, a load of the same power consumption but a different reactive component on the other line could easily read up to 20-40% off.

    Please let me know if I'm missing something. Again, thanks for all the great work!

    ReplyDelete
  29. You're right. The situation is that I have to make some trade offs or spend a heck of a lot of money setting up highly accurate devices. The goal here is not to get the numbers exact, but close enough.

    The trade off is not between the numbers I get and a very accurate reading, it's between a coarse reading of instantaneous power or nothing at all. See, the only method that's available without instrumentation, is to read the meter and write it down, come back later and read the meter and write it down...etc. Each of these is after the fact and I already owe the money for the period that the measurement took. If the power company provided meters that had a pulse output, the readings would be as accurate as the power meter provides, but that's not the case in my area.

    Regarding power factor. I did a long test of power factor and it never varied more than around 3%, which corresponded to the numbers the power company said their reading were. So, things like dryer motors, A/C motors and such don't really cause much problem. I measured the voltage on the two legs of the split phase 220 and graphed them over a week and they never varied more than a volt from each other. Actually, this made sense because all my heavy loads are 220 and suck from both sides.

    Things changed a bit when I got a permanent magnet motor for the swimming pool. It's highly reactive and causes a drop in the power factor that definitely will cause a misreading. I'll work on that problem someday, but for now, the period is so small I'm just ignoring it.

    Notice that I don't try to accumulate the power usage over time (at least not anymore) I use the device to tell me trends, tracing high usage periods and monitoring the usage of appliances. When I first put it in, I did accumulate values and they corresponded within 2% to the power company values. Then I went through a period of flaky power and recurring outages. That convinced me that I didn't want to try and argue total usage with the power company.

    I'd just lose.

    ReplyDelete
  30. There are several factors that help me in this. My major loads are all 220. I only have one seriously reactive load. I balanced my 110V legs by moving appliances (actually repositioning the breakers) such that the two legs are close to each other. And probably a couple of things I've forgotten. Over the past year and some months my peak demand bills from the power company have matched pretty darn closely the numbers I get going back through the readings.

    Regarding calibration: It was tough at first. I started out using a resistive load (toaster) and comparing it to a Kill-a-watt; when I was comfortable this was working correctly using light bulbs heaters and such, I tried reactive loads and was really surprised that they matched up equally well. Then I used a 220V resistive load (my water heater) and added the phases as you noticed. That compared favorably with a true rms meter I borrowed from an electrician down the street and around the corner. Then I compared this to a 220V motor (A/C compressor and water pump motor) and was again surprised that it matched. So, I hooked it up and took on the power company. I described this interaction somewhere on this site. It resulted in them replacing the meter and suddenly, my readings and the meter's readings matched each other. After that I, unsuccessfully, tried accumulating values.....

    So, while it isn't as accurate as the power company's equipment,it does give me a good indication of my instantaneous power usage. I can turn on a motor and see the increase immediately. I can tell at a glance when the outside security lights have been left on or the dishwasher drying element was not turned off. I have watched the electric oven cycle the element to keep the temperature even and the same with the electric dryer element. I can even see when the vacuum cleaner motor is turned on; amazing how much power a 10 amp vacuum cleaner uses.

    In our efforts to lessen our electricity usage, we are severly hampered by not having anything that will tell us what our usage is 'right now'. This little device with all its shortcomings, does this admirably well in my case.

    And, it was about a quarter of the cost of the cheapest similar device.

    My thoughts for the future of this device follow your suggestions, measuring the voltage for both legs and separating the CTs such that I can actually measure the usage on each leg. The problem with this is the additional isolation transformer and increased load on the tiny processor. This would be added and then my reading would be closer to absolutely correct. If I'm someday lucky enough to get a meter with a pulse output, I may read it and get away from the CTs altogether, but I'm not holding my breath. I do not plan on accumulating values, that will just lead to frustration when my numbers and the power company's don't match. I'm satisfied knowing that I'm using somwhere around 6.8KW when the South A/C kicks on at the same time as the pool motor.

    Thanks for bringing this up. I may add a link to your comment and my response to the page so people can get a clearer understanding of the purpose.

    And, sorry I rambled on so long.....

    ReplyDelete
  31. I second Dave here. I have to deal with 2 X 120 volts and placed a CT on each leg of the 220 volts coming in. I use the reference voltage from only one leg, since I, too, measured really small (negligible?) differences between the two legs over a period of time. Most heavy loads use 220 volts anyway.
    Contrary to Dave, I don't sum the two reading from the CTs at input, but calculate two separate values and sum the resulting current/watt readings. This tales care of any phase discrepancies between various CTs.

    I actually use 5 CTs in my setup, which keeps the Arduino really busy. The Arduino runs at full speed, without delays in the code and outputs one set of values every 3 seconds or so.

    ReplyDelete
  32. OK, you two guys have convinced me...see, I can learn from others as well. I'm going to change the code and hook the other CT to one of the other arduino pins. I have plenty of room for additional resistors and it's not like I have to worry about running out of Arduino pins! It'll be interesting to see how much difference this makes.

    Unfortunately, it'll mean that I have to recalculate the phase angle difference caused by the CT itself, but if I remember correctly, it's not all that hard to do.

    Robert, you convinced me to try this; my hesitation was that I wasn't sure the arduino could keep up with the floating point math.

    I suspect it will wait until after Christmas though. Well, and New Year too. And, the hangover after New Year.

    ReplyDelete
  33. Hello!

    Thank you for sharing your awesome creation! I am trying to build a contraption to monitor my well pump. I'm having a tough time understanding how you have your CT's wired. I would pay pal you 10 dollars if you would throw together a little sketch (even in mspaint) of how you have those wired in series and where they connect to your arduino. If you get a chance would you shoot it to me in an e-mail? Cyrus@jandjpumps.com
    I would really appreciate your help!

    ReplyDelete
  34. Cyrus, I dropped you a note on how I figured out the wiring. If it doesn't help, write me back and I'll explain it better (well, maybe better). Regarding how it's wired into the Arduino, I just hooked it to an analog input and started reading the voltage. The schematic above shows how I used a voltage divider to get the proper range and which pins I used to do it.

    ReplyDelete
  35. Hi Dave I am trying also to build a energy monitor and I have some questions about you design. How did you wire the current transducers in series and what kind of circuitry you build for voltage/current measurement? I mean what kind of sensor electronic did you use to connect the current transducers into the arduino.
    my email is xeneixen@hotmail.com
    Thank you

    ReplyDelete