Where are the variables defined?

After finally figuring out all the hardware for the monitor, I'm not going through the software for the emonlib.  I went through the .h and .cpp files and wasn't able to find a few variables (i.e. where is the constant "timeout" defined and assigned a value or crossings same thing).  Thanks!

On another note, does anyone have a good handle on how often one should record power measurements in order to have a good handle on standard household loads?  I'm testing individual circuit breakers and want to capture power spikes, so I was thinking once per second would be adequate.  Has anyone tested this out?

Robert Wall's picture

Re: Where are the variables defined?

Missing vaiables: Have you looked in the included files - the libraries? That's where you'll find them.

What do you mean by a "power spike"? - what timescale are you looking at. If you are interested in inrush - that's the surge of current that happens when a tungsten lamp is switched on, that lasts for a few cycles,for a fridge motor, it's a lot longer than that, around a second. If you're using emonLib that samples for 0.2 s every say 1s, clearly unless the event you're looking for lasts longer than 1 s, you're not guaranteed to see it, let alone capture it faithfully.

The alternative is to use MartinR's PLL sketch, which monitors continuously. You'll still not see the peak amplitude, only the average power over the averaging period, but at least you'll see something.

squareone's picture

Re: Where are the variables defined?

Hey again Robert.  I found the declarations or that functions were looking for them, but the libraries didn't have something like timeout=500.  That being the case, what is the timeout length?  I read emonLib.h and emonlib.cpp which are the only files I believe are relevant in my energy monitoring compile.  Should I not see the constants defined as a number in those files?  Where are the function calls happening i.e. what calls this function ->  void EnergyMonitor::calcVI(int crossings, int timeout).  Nothing appears to call it in the sketch, the header, or cpp file.

I would like to capture lights coming on and the motor on the refrigerator kicking in, so sounds like .5s intervals would be better.  I'll check out the PLL Sketch.  Thanks for the tip.

Robert Wall's picture

Re: Where are the variables defined?

Ah, I see what you are saying. You need to learn a bit of C++. How much C do you know? While I don't think it is absolutely necessary to be proficient in C, some knowledge will help. My bible for C is of course "Kernigan & Ritchie" http://www.amazon.co.uk/C-Programming-Language-2nd/dp/0131103628/ref=sr_.... This is the standard text book.  The normal place I point people at who want to move up to C++ is http://www.relisoft.com/book/index.htm  and that assumes you know C. Because the Arduino environment normally uses a very small subset of the language, neither are the best place for a beginner to start, nor are many of the other on-line tutorials. I'd still suggest you have both of those, and maybe Bruce Eckel's "Thinking in C++" http://www.planetpdf.com/developer/article.asp?ContentID=6634 available for reference.

However, there is this: http://www.me.umn.edu/courses/me2011/arduino/arduinoGuide.pdf which does look to be a good starting place for a beginner. It does not go as far as classes and methods that are used here, though. So after that, you'll need to progress on to Relisoft.

Briefly, EnergyMonitor is a class, and calcVI is one of its methods. timeout is a parameter that is passed in when the method is called.  A class is a definition a bit like int or long, it becomes an entity when it is instantiated (you make an instance of it) which you do in the sketch (three times) with

EnergyMonitor ct1,ct2,ct3;

So timeout gets its value (2000) in

ct1.calcVI(20,2000);

 

squareone's picture

Re: Where are the variables defined?

OMG, it was right in front of my face the whole time.  I was digging in the header and cpp and not my own code.  Sorry about that!  Thanks Robert.  Working on a solution now that will give me the averaging I want.  I'm not going to change the timeout or crossings, just was curious what I was working with.  You say it should be sampling close to 5hz, so then I should be able to track that in the serial and then later write some code to get the data written to a SD card.  I have the normal emon example sketch running now with a SD card write add on and found that the writing process was taking a long time (700ms or so).  I'm looking for a faster way to write it now and that way I can later see how much electricity I used total.

Robert Wall's picture

Re: Where are the variables defined?

Take a step back. The emonLib calcVI reads the inputs for 20 zero crossings (10 cycles) then returns to your sketch. Per c.t.. Then it sends to RF or serial or whatever, then sleeps for 5 s. I didn't say 5 Hz, I don't know where that came from.

squareone's picture

Re: Where are the variables defined?

You said every .2s which is 5 hz, right?  Glad I know about the sleep cycle now, but that's not a part of the basic emon Library->voltage and current sketch, right?  I actually put a timer on the beginning and end of the calculations so the .2 secs is calculated every step instead of making the .2s assumption.

squareone's picture

Re: Where are the variables defined?

Robert, you seem very detailed oriented.  Could you check my code to make sure I did the maths right for the 1 CT sensor and voltage measurement I have?  I'm using the standard emon Library and just trying to make a kW-h accumulator at this point.  My LCD is showing me a number I would consider too high for my dishwasher.  I think maybe (3600s * 1000W) does not fully convert realPower to kWh.  Any help is appreciated.  

[CODE]

#include <Wire.h>
#include <LCD.h>
#include <LiquidCrystal_I2C.h>
#include "EmonLib.h"                   // Include Emon Library
#include <SD.h>
#include <Time.h>

#define I2C_ADDR 0x3F
#define BACKLIGHT_PIN 3
#define En_pin 2
#define Rw_pin 1
#define Rs_pin 0
#define D4_pin 4
#define D5_pin 5
#define D6_pin 6
#define D7_pin 7

File myFile;
LiquidCrystal_I2C lcd(I2C_ADDR,En_pin,Rw_pin,Rs_pin,D4_pin,D5_pin,D6_pin,D7_pin); //Create an instance of LCD
EnergyMonitor emon1;                   // Create an instance of EnergyMonitor
boolean run = false;
int ledR = 11;
int ledG = 12;
int ledB = 13;
unsigned long old_time=0;
unsigned long new_time=0;
double usekwh=0;

void setup()

  Serial.begin(9600);
  delay(1000);
  emon1.current(1, 60.60606);             // Current: input pin, calibration.
  emon1.voltage(5,118.70,1.7);
  lcd.begin (20,4,LCD_5x8DOTS);
  lcd.setBacklightPin(BACKLIGHT_PIN,POSITIVE);
  pinMode(ledR, OUTPUT);  
  pinMode(ledG, OUTPUT);
  pinMode(ledB, OUTPUT); 
 

  //Initialize the SD Card
  //Serial.print("Initializing SD card...");
  lcd.setBacklight(HIGH);
  lcd.home();
  lcd.print("Init. SD card...");
  // On the Ethernet Shield, CS is pin 4. It's set as an output by default.
  // Note that even if it's not used as the CS pin, the hardware SS pin
  // (10 on most Arduino boards, 53 on the Mega) must be left as an output
  // or the SD library functions will not work.
  pinMode(10, OUTPUT);
  lcd.setCursor(0,2);

  if (!SD.begin(4)) {
    //Serial.println("initialization failed!");
    lcd.print("Init. Failed");
    delay(5000);
    return;
  }
  //Serial.println("initialization done.");
  lcd.println("Init. done.");
  delay(1000);
  run=true;
  lcd.clear();
  usekwh=0;
}

void loop()
{
  if(millis()<15000){
    usekwh=0;
    lcd.clear();
    lcd.home();
    lcd.print("Stabalizing current");
  }
  if (run=true) {
  old_time=millis(); 
  emon1.calcVI(20,2000);         // Calculate all. No.of half wavelengths (crossings), time-out
  //emon1.serialprint();           // Print out all variables (realpower, apparent power, Vrms, Irms, power factor)
  double realPower       = emon1.realPower;        //extract Real Power into variable
  double apparentPower   = emon1.apparentPower;    //extract Apparent Power into variable
  double powerFActor     = emon1.powerFactor;      //extract Power Factor into Variable
  double supplyVoltage   = emon1.Vrms;             //extract Vrms into Variable
  double Irms            = emon1.Irms;             //extract Irms into Variable
  String toFile="";
  new_time=millis();
  if (emon1.Vrms<2) {
     realPower=0;
     supplyVoltage =0;
     Irms=0;
  }
  usekwh+=(realPower * ((new_time-old_time))/3600000);
  //Serial.print(ApparentWatts);        // Apparent power
  //Serial.print(" ");
  //Serial.println(Irms);         // Irms
  //Serial.println(supplyVoltage,2);
  //Display the information on the LCD
  //Serial.println(new_time-old_time);
  lcd.clear();
  lcd.setBacklight(HIGH);
  lcd.setCursor(0,0);
  lcd.print("Real Pwr: ");
  lcd.print(realPower, 4);
  lcd.print("W");
 
  lcd.setCursor(0,1);
  lcd.print("Irms: ");
  lcd.print(Irms,4);
  lcd.print("A");
  
  lcd.setCursor(0,2);
  lcd.print("TkWh: ");
  lcd.print(usekwh,3);
  lcd.print("  ");
  lcd.print(new_time-old_time);
  lcd.print("ms");
 
  lcd.setCursor(0,3);
  lcd.print("V: ");
  lcd.print(supplyVoltage,2);
  lcd.print("V");
  lcd.print("  ");
  lcd.print(new_time/(3600*1000),2);
  lcd.print("hrs");
  if (Irms<=.25){
     setColor(0,0,0);
  }
  else if ((Irms>0.25) && (Irms<3)) {
     setColor(0,255,0);
  }
  else if ((Irms>=3) && (Irms<6)) {
     setColor(100, 240, 0);
  }
  else if ((Irms>=6) && (Irms<=10)) {
     setColor(125, 125, 50);
  }
  else {
     setColor(255,0,50);
  }
  //Info for FileWrite
  char tmp[10];
  //timestamp info

  toFile+=millis();
  //Serial.println(toFile);
 
  toFile+="  ";
  toFile+=dtostrf(realPower, 6,4,tmp);
  toFile+="  ";
  toFile+=dtostrf(Irms, 6, 4, tmp);
  //Serial.println(toFile); //Show me what's written
  /*
  myFile = SD.open("test3.txt", FILE_WRITE);

  // if the file opened okay, write to it:
  if (myFile) {
    myFile.println(toFile);
    // close the file:
    myFile.close();
  }
  else {
    // if the file didn't open, print an error:
    //Serial.println("error opening file");
  }
  }
  */
  //delay(500);
}
old_time=millis();
}

void setColor(int red, int green, int blue)
{
  analogWrite(ledR, red);
  analogWrite(ledG, green);
  analogWrite(ledB, blue); 
}

[/CODE]

Robert Wall's picture

Re: Where are the variables defined?

The 0.2 s comes from the number of zero crossings (20) counted by calcVI, and it could be half a cycle longer while it waits for the first one to start counting. The delay is (or should be) in your main sketch.

I can't check all that now! Watch this space.

squareone's picture

Re: Where are the variables defined?

Hey Robert!  Just so you know, a normal runtime from my "old time" and "new time" is about 70-100ms, which seems lower than I would have thought based on the .2s zero crossings.  If the signal is 60 hertz, I would expect 20 zero crossings every 166ms as you suggested.  Am I measuring the wrong block of time?

Sorry, alot of the code is LCDs and LEDs that I'm using before I implement the SD card that is commented out here.  The LCD and LEDs work fine.  It's the (3600*1000) that I'm weary of.  I ran the dishwasher last night and it said 400kwh.  Either my machine needs to never be used again or I made an error in the conversion, which is the more likely scenario!  I saw on my output about 5.5A for a while, so if I was to do some math for a 1 hour run cycle at that draw, it should have been (5.5A * 120V)*1hr = .66kWh total.  

Edited in Bold

I think the error is that you cannot measure Watts and just multiply it by milliseconds.  You must convert it to seconds and the multiple as you are looking to integrate the area of the power consumption curve and all units must match.  This would mean the conversion should be:

usekwh+=(realPower * ((new_time-old_time))/(3600*1000*1000); 

I took the 3600000 from the Solar PV GLCD library since the emonGLCD displays the same kind of information I'm looking to make as scrolling text on my LCD.  It seemed to make sense because you have to convert the watts unit of time to hours which is the 3600 and then form kilo watts which is 1000 watts of course.

Robert Wall's picture

Re: Where are the variables defined?

OK, I've looked at your code.

1. Old-time = millis( ) is done at the end of loop( ) then again at the beginning - that's not right.

2. Tied in with that, usekwh is the energy measured over 10 cycles. It's not even a 'best guess' at the energy for 1 complete loop.

3. I don't see why you're making a second copy of realPower etc.

4. I don't know what if (run=true) is doing. run has already been set to true, run=true is an assignment, not a logical comparison and in any case I think what you intended is redundant because loop( ) doesn't execute until setup( ) has completed. I think what you're trying to do is allow the software filters time to settle, and for that to happen you must run calcVI a number of times but ignore the values it returns. What I would do is:

emon1.calcVI(20,2000);         // Calculate all. No.of half wavelengths (crossings), time-out

if(millis()<15000){
    usekwh=0;
    lcd.clear();
    lcd.home();
    lcd.print("Stabilizing current");
  }
  else {

..... do everything else to the end

So long as your units are consistent, it doesn't matter what you actually use. But you need to pick sensible units for the accumulator to keep the numbers manageable. Watt-hours are probably a good choice (and sufficient precision as the billing unit is usually 1 kWh).

I assumed you were on a 50 Hz system hence 20 mS per cycle, so as you say 20 crossings should take 166 ms to 175 ms on a 60 Hz system, depending on how long it has to wait for the first crossing. But as I wrote above, you need to rethink what you are doing with time. I can't see why you need to measure the measurement period, don't you want to treat that power as representative of the power over the whole time of one loop - including writing to the display and the SD card - and use the loop time to estimate the energy. So immediately before you fetch new_time, you do old_time = new_time; then carry on as before, you never need to do old_time = millis( )

I ran the dishwasher last night and it said 400kwh. That was quite a party then?

There's no such thing as ApparentWatts - they are called VA (volt-amperes).

And there are concerns with the life of an SD card when written frequently - I suggest you look at an alternative mechanism for storage - those who use it with  RPi and emoncms see a life of a few months when written to every 5 s. Most seem to use a USB memory stick or a spinning hard disk.

 

squareone's picture

Re: Where are the variables defined?

Hey Robert,

I was seeing a weird .6khw show up at the beginning of the loops.  I think it was from the system booting up and false signals creating some voltage and current in the system.  If I reset it to zero for 15sec, it seemed to stabalize.  I'm quite certain I was off by a factor of 1000 now that I've looked at it.  I wonder how the GLCD loop calculates time or power because it is only dividing by (3600*1000).  So either the conversion from ms is made OR the conversion to kwh and not both at the usekwh line of the cpp file.  

ApparentWatts is just a name I made up so I knew that it was something other than the measured voltage and measured current.  It is an artifact of older code since you got me all lined up on my hardware!

The run=true line allows the sd card time to boot up before the loops begin.  I notice the loops started earlier than the SD card could catch up.  It was very strange as I thought the Arduino would complete all of setup BEFORE the loops.  It would activate the SD card, but the SD card wouldn't be up before the loops began.  I haven't figured out the boot sequence yet on the Arduino.

I never thought to apply the power to the whole run-time, but you're right, I'm missing power by only calculating it for the loops. I'll fix that tonight and try again.

Like you mentioned, I saw some strange calculations for the run-time at the beginning of the loops (i.e. up to 3 seconds to complete instead of 175ms).  This generally lasts about 1 min and then evens out.  I couldn't figure out why it was so slow.  Is there a good reason for this?

I stole the following from the example code which is why i have most of these variables:

void loop()
{
  emon1.calcVI(20,2000);         // Calculate all. No.of half wavelengths (crossings), time-out
  emon1.serialprint();           // Print out all variables (realpower, apparent power, Vrms, Irms, power factor)
 
  float realPower       = emon1.realPower;        //extract Real Power into variable
  float apparentPower   = emon1.apparentPower;    //extract Apparent Power into variable
  float powerFactor     = emon1.powerFactor;      //extract Power Factor into Variable
  float supplyVoltage   = emon1.Vrms;             //extract Vrms into Variable
  float Irms            = emon1.Irms;             //extract Irms into Variable
}

Is that what you mean by the double declaration of realPower?  Otherwise I don't see it initialized anywhere else.

Great to have you look it over.  Thanks as always.  TR

Robert Wall's picture

Re: Where are the variables defined?

There are software filters in emonLib that remove the offset that is inserted by the half-supply bias voltage in hardware. The wrong and high values on startup are while those settle. So as you found out, it is best to ignore the results totally while that is going on. But you must run the filters for them to settle.

The run=true line isn't doing what you intend. Read it again carefully. "if (run=true) {" is assigning the value true to run, that then always evaluates as true, so the statement is actually: if (true) {...   so it is doing nothing useful.

(Hint: this is a very common C bug.)

But looking harder, I think the return in here is wrong.

if (!SD.begin(4)) {
    //Serial.println("initialization failed!");
    lcd.print("Init. Failed");
    delay(5000);
    return;
  }

I think it will prematurely end setup( ), and crash into loop( ) with a failed SD card. Not what you wanted?

If there is a way to test the SD card, it needs to enter a loop within setup( ) and exit it when the SD card is proven OK, otherwise all you can do is put in a long delay before you end setup( ). If the card is proven not OK, it should enter a permanent loop, just displaying the warning and never exit, unless you want to show the data in any case, when you should make the SD card writes conditional on the SD card being healthy.

double realPower   = emon1.realPower; etc

You're not changing some of them except to make them zero on startup, and not using the rest at all, so it would be safer (less chance of you making a mistake) to remove them all and use emon1.realPower etc instead.

calypso_rae's picture

Re: Where are the variables defined?

squareone: My LCD is showing me a number I would consider too high for my dishwasher.  I think maybe (3600s * 1000W) does not fully convert realPower to kWh.  Any help is appreciated.  

You may find it helpful to run one or more of the basic tools that appear at the start of my Summary Page.  These will allow you to check how much of your ADC's input range is being used by your Current and Voltage sensors.  The more range that you use, the better - providing that you never exceed the end-points.  RawSamplesTool will give a graphical representation for each of your waveforms.

Using a simple resistive load, such as a 3kW kettle or a 60W light bulb, you can calibrate your measurement system to give the expected value.  You should then have more confidence in the measured values for other household appliances such as your dishwasher.

squareone's picture

Re: Where are the variables defined?

Thanks Calypso.  Looks like I was about to start working things you've already thought of!  Glad I have the library versus me creating it from scratch!

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.