Questions about programming

 

I have some questions regarding the old version of programming please, which I can't understand:

 

1)The"  Ac_Wall_Voltage 122 " is it the voltage from the mains??

    The " AC_Adapter_Voltage 15.2" is it the voltage on the voltage adapter, for example the 9 Volts that you standardized??

 

2)// Initial gueses for ratios, modified by VCAL/ICAL tweaks
   #define AC_ADAPTER_RATIO       (AC_WALL_VOLTAGE / AC_ADAPTER_VOLTAGE)
   double V_RATIO = AC_ADAPTER_RATIO * AC_VOLTAGE_DIV_RATIO * 5 / 1024 * VCAL;
   double I_RATIO = (long double)CT_TURNS / CT_BURDEN_RESISTOR * 5 / 1024 * ICAL;
 
  I cant understand the reasoning of the calculations of the ratio
 
3)When you are doing the high pass filter :
   filteredV = 0.996*(lastFilteredV+sampleV-lastSampleV);
   filteredI = 0.996*(lastFilteredI+sampleI-lastSampleI);
 
I cant understand  why you are doing filtering.
 
If someone can help me please.
 
Thank you
   
TrystanLea's picture

Re: Questions about programming

Ac_Wall_Voltage is the mains voltage yes.

AC_Adapter_Voltage: yes the output voltage of the ac-ac adapter (9v)

Maybe the word ratio is unclear, V_RATIO and I_RATIO are the final voltage and current calibration including the fine tuning calibration given by ICAL and VCAL. 

Have a look at this page, it might help to shed some light on the calibration equation calculation: http://openenergymonitor.org/emon/buildingblocks/ct-and-ac-power-adaptor-installation-and-calibration-theory

The high pass filter is required to subtract the 2.5V bias provided by the biasing voltage divider in the CT and Voltage circuit: http://openenergymonitor.org/emon/buildingblocks/ct-sensors-interface

Polidano's picture

Re: Questions about programming

Im sorry if Im asking too much...

1)I read the links you gave me but if im not using the emontx.. therefore the AC_VOLTAGE_DIV_RATIO is not 11 for me? since im not using R13 and R14. My resistors are 10K ohm and not 3.3V but 5V... so how am I going to find my ratio.

When I read about the filtering, I only found this sentence:

'but this is immediately removed by a software filter, '

and you just chose 10K ohm for R 3 and R4 to be equal. that is I can choose any other number for resistor as long as they are equal and not high enough to increase noise

​so actually I still cant understand the reason behind all, for example why it is multiplied by 0.996 and why the equation is like that:

  filteredV = 0.996*(lastFilteredV+sampleV-lastSampleV);
   filteredI = 0.996*(lastFilteredI+sampleI-lastSampleI);

2)​So the ICAL and VCAL and also the PHASECAL I need to find them by trial and error right? That is I clip on a normal reader, see what I get, then try with my arduino and try to arrange them to get close to the other. In order to be used in the ratio...

​The part of the ratio I understood from the links above...

 

​I am really sorry if I am asking too much.. however I would like to build my own software on something similar , and here is the only help I can find. But first I have to understand your software in order to build mine.

Thanks again

 

 

Robert Wall's picture

Re: Questions about programming

A little more explanation:

"1) .... so how am I going to find my ratio."

See here: http://openenergymonitor.org/emon/buildingblocks/ct-and-ac-power-adaptor-installation-and-calibration-theory   You do not say exactly what you have, So I cannot tell you what to do.  You will need to compare what you have with the standard emonTx circuit and follow through the reasoning in the link above.

"and you just chose 10K ohm for R 3 and R4 to be equal. that is I can choose any other number for resistor as long as they are equal and not high enough to increase noise"

Yes - and provided that they are not very low either. Noise will not be a problem with 10 K Ohm resistors.

"filteredV = 0.996*(lastFilteredV+sampleV-lastSampleV);"

This is a standard software high pass filter. See here: https://en.wikipedia.org/wiki/High-pass_filter for the full theory (scroll down to "Algorithmic implementation"). The best way to understand it is to simulate it with a spreadsheet and study how it works (Hint: filteredV and sampleV are the current line on the spreadsheet, lastFilteredV and lastSampleV are the line above. Start with a simple step of 'sampleV' and watch how 'filteredV slowly settles back towards zero). "0.996" controls the time constant.

"2)​So the ICAL and VCAL and also the PHASECAL I need to find them by trial and error right?"

For your starting point for these, see here: http://openenergymonitor.org/emon/buildingblocks/ct-and-ac-power-adaptor-installation-and-calibration-theory   Again, you will have to follow the reasoning and calculate your own equations using the numbers from the components you are using. If you can measure voltage and current with another accurate meter, then you can adjust the calibration constants to make the Arduino show the same values. Otherwise, use the theoretical calibration constants.

[edited: wrong page referenced]

 

Polidano's picture

Re: Questions about programming

thanks a lot

 

1)if I add this program to the xbee send part. therefore i should add it under:

xbeeSerial.begin(9600);

2)and another thing, under each : Serial.print('  '); should i write : sendDataToXbee(); or should I just write it after I reset the accumulators.. because if I put it after the program ends, absviously the accumulators will be reset to zero and therefore the xbee will send just zeros

 
4) I dont have an emonTx all im using is the AC mains non-invasive V3  version, so thats why Im finding it difficult to find my ratio. I am using and arduino of 5 V,  9V voltage sensor the ct senor Yhdc SCT-013-00. and for voltage the circuit is the same as yours 100 Kohm and 3 * 10Kohm, while the current part has a burden of 33 ohm and 2 * 10Kohm

 

Robert Wall's picture

Re: Questions about programming

"1)if I add this program to the xbee send part. therefore i should add it under:

xbeeSerial.begin(9600);"

What program?  The operating system of the Arduino calls two functions. When it starts it calls setup( ). When that returns, it enters a loop, calling loop( ) repeatedly. (The clue is in the names!). So anything you want done repeatedly goes in loop( ). The EnergyMonitor::calibration( ) method - look at Emon.h to see how it's defined and in Emon.cpp to see what it does - just sets the calibration constants. Hopefully, these never need to change, so it naturally goes into setup( ).

"2)and another thing,"

Haven't you answered your own question here? Is your real problem that you don't understand the language the program is written in? If so, try working through this http://www.relisoft.com/book/index.htm

"4) I dont have an emonTx all im using is the AC mains non-invasive V3  version, so thats why Im finding it difficult to find my ratio. "

Yes, but you need to follow exactly the same reasoning. Look at the circuit diagram for the emonTx and look at the calibration theory, and relate one to the other. Then draw out your circuit diagram (with pencil and paper ! ) for the voltage input from mains to input pin; then write out the program calculations from reading the input to transmitting the final value and write on the paper all the calculations using the real numbers along the way. Of course you must substitute the values of your components. As you do this, you will see how to generate your own calibration constant.

Then do the same for current.

You might have a problem working out the voltage from the voltage sensor if it is not one that we have accurate data for, in that case you will need to monitor the mains voltage and adjust the calibration constant by trial and error to get the correct value.

Here's the exam question: Why do the values of the biasing resistors not enter into the calibration?

 

Polidano's picture

Re: Questions about programming

those are used to provide a 2.5V, that is it would not oscillate from negative to positive as the arduino only needs a positive voltage, if im not mistaken

Robert Wall's picture

Re: Questions about programming

So you are saying the bias resistors do not affect the signal amplitude? Correct !  All they do is set the 'no load current' (or 'no mains voltage' in the case of the voltage input) to the midpoint of the analogue to digital converter's range. 

Also, you need not worry about peak-peak values and rms values, as long as you consistently work in one or the other. As we want to display and use the rms current, it makes sense to work in rms values for all of the calibration calculations. You only need to worry about peak-peak values when you are designing to ensure that the signals remain within the range of the analogue to digital converter.

Polidano's picture

Re: Questions about programming

exactly they give 2,5V in order to be safe in my case since Im using a 5 V arduino.. for emonTx wich is 3.3V one has to arrange the resistors in order to get 1,5V. 

Thanks a lot and sorry for being a pest :D

Robert Wall's picture

Re: Questions about programming

I was a student once - over 40 years ago !  Microprocessors didn't exist then, even the 709 op-amp was cutting edge.

Polidano's picture

Re: Questions about programming

:O i think it was really tough engineering back then... and im freaking myself out hahahha trying to figure out this :/..

Polidano's picture

Re: Questions about programming

why to find the real power, you still multiply by I_Ratio and V_Ratio, if it is already taken care the ratio to find the RMS of V and I. 

I mean the ratio to find the RMS is multiplied by the ratio, in order to take care of the scale down due to the sensors and the circuit. But why is there the need to multiply by I_Ratio and V_ratio to find the real power as well??

 

Robert Wall's picture

Re: Questions about programming

You are referring to  (3) Post loop calculations in EmonLib.cpp

Because you are not using the rms values of current and voltage to obtain power! The sum I think you have in mind [P = V.I.cos(Ø)] only works for pure sine waves. You are not guaranteed pure sine waves in the real world. The voltage wave might be relatively close to a sine wave, but the current wave most certainly will be distorted especially if you have lamp dimmers, switched mode computer power supplies and such.

The correct way to calculate power is exactly as the calculations are done in the software: multiply the instantaneous values of current and voltage [(F) Instantaneous power calc], and then take the mean.

(I think you have mixed up some of the variables when you read through the program).

It's cheaper (in terms of program execution time) to multiply at the end outside the loop rather than multiply each reading inside the loop, and you get the same answer.

 

Polidano's picture

Re: Questions about programming

thanks :))))))))) ... I wrote all the program now in my own words :D.. now Im waiting for the PCB so I can calibrate all the stuff .. I will soon start the Ethernet part

calypso_rae's picture

Re: Questions about programming

Robert Wall, on 2/4/2012:

"filteredV = 0.996*(lastFilteredV+sampleV-lastSampleV);"

This is a standard software high pass filter. See here: https://en.wikipedia.org/wiki/High-pass_filter for the full theory (scroll down to "Algorithmic implementation"). The best way to understand it is to simulate it with a spreadsheet and study how it works (Hint: filteredV and sampleV are the current line on the spreadsheet, lastFilteredV and lastSampleV are the line above. Start with a simple step of 'sampleV' and watch how 'filteredV slowly settles back towards zero). "0.996" controls the time constant.

Thanks for that really helpful explanation.  I've just tried out your idea of the spreadsheet demo, and it does indeed behave as you say.  Using the time-constant value of 0.996, it takes forever (well, nearly) to settle.  To get anywhere near to zero from 10 would take more screen-worths than I'm prepared to scroll down!  By changing the time-constant to 0.8, the dc-blocking behaviour can be seen on a more compressed timescale, with 20% of the ac-transmission being sacrificed.

When I switch my Emon system on from cold, crazy readings often appear, but the system thankfully settles down after a few seconds.  Maybe this is the dc-blocking filters getting to grips with the 2.5V offsets in our voltage and current readings?

 

Robert Wall's picture

Re: Questions about programming

Yes, it's the filter.

"The best way to understand it is to simulate it with a spreadsheet..."  -- Make one cycle of a sine wave in column 1 of the correct amplitude (it need not be very accurate, say every pi/10) , square it in column 2 and then sum column 2 and take the root. Do the same with a big offset on the sine wave and see just how crazy the numbers are. It's obvious really when you think what rms means - it's the equivalent direct current that gives the same heating effect, so if you add a load of dc to it (in the short term) it will heat a resistor more.

A thought: It ought to be possible to pre-load the filter at startup and reduce (but probably not eliminate) the settling time.

Fuzzylogic's picture

Re: Questions about programming

Thanks for this great project!

I'm using the calcIrms() function on a PIC (12F1822) to measure -only- the current on a three phase mains line.

It's working fine, if only using one CT, if i add a second channel in the code, and vary the input of  this channel manually with a potentiometer, the measured data on the first channel will be not correct anymore.

I think i found the problem that is causing this behavior. When the loop is started sampleI and filteredI are uninitialized (or contain values from the last channel). So DC settling is taking place every time i switch to the next channel.

I'm currently sampling with 2048 samples, and that seems to be to low. But even increasing it to 4096 samples will not completely remove this "interference" from the previous channel.

A solution for me was to add an extra loop, with a lower time constant for the high pass filter, so that it settles quickly, and once it has, the measurement loop is started

for (int n = 0; n < 100; n++)
  {
    lastSampleI = sampleI;
    sampleI = analogRead(inPinI);
    lastFilteredI = filteredI;
    filteredI = 0.9*(lastFilteredI+sampleI-lastSampleI);
  }

I've ordered a emonTx today, so i soon will be able to verify this on the official hardware too.

 

Robert Wall's picture

Re: Questions about programming

You are programming in C++? 

The two channels should each be using their own instance of the EnergyMonitor class, so each uses its own set of properties inside the filter equation (assuming you have copied the standard emonTx sketch and library).

e.g. you declare:  EnergyMonitor ct1,ct2; 

When you do this, you actually have (seen from outside of the calc( ) method and assuming those properties/variables to be visible, which they are not)

when you are looking at ct1:

ct1.lastSampleI = ct1.sampleI;

when you are looking at ct2:

ct2.lastSampleI = ct2.sampleI;

etc. and the two channels will not interact.

If you are not using C++ or other object-oriented language, then you need a second set of variables with different names for the second channel.

Fuzzylogic's picture

Re: Questions about programming

That was the problem. Thanks for the correct solution.

 

 

Polidano's picture

Re: Questions about programming

can anyone give me any light on the programming of the ethernet shield and xbee receive together???

Polidano's picture

Re: Questions about programming

 

 //Calculation of Powers
 Real_Power=V_final*I_final*total_P/3000;  
 Apparent_Power=RMS_V*RMS_I;
 PF=Real_Power/Apparent_Power;
 
//Send data trough Xbee
Serial.print(Real_Power);
xbeeSerial.print(' ');
 
Serial.print(Apparent_Power);
xbeeSerial.print(' ');
 
Serial.print(PF);
xbeeSerial.print(' ');
 
Serial.print(RMS_V);
xbeeSerial.print(' ');
 
Serial.print(RMS_I);
xbeeSerial.print(' ');

I wrote the send part like that.. should I close it in a loop or it is good like that?? and therefore on the receive part i should only add to the ethernet program this:

 
//Ethernet unit arduino sketch - openenergymonitor.org GPL
//Author: Trystan Lea
 
//Libraries
#include <Ethernet.h>
#include <NewSoftSerial.h>
 
//Sets the unique mac address for the ethernet board
byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
//Sets the IP address of the ethernet board
//You need to make sure this is in the right range.
//A good way to check is to find the ip of other things in your house like a laptop
//and set the ethernet to be a similar ip for example if your laptop is 
//192,168,1,45 set your ethernet ip to
//192,168,1,44 (as long as there is nothing else on this address)
byte ip[] = { 192, 168, 1, 44 };
 
//Router IP address
byte gateway[] = { 192, 168, 1, 253 };
//Server IP address
byte server[] = { 85, 92, 86, 84 }; //OpenEnergyMonitor.org shared server
 
//Setup a client
Client client(server, 80);
 
//Xbee serial connection.
NewSoftSerial xbeeSerial(2, 3);
 
//Character array used to convert recieved serial characters to floats.
char cArray[10];
int ic=0;
 
double realPower = 0, 
       apparentPower = 0,
       powerFactor = 0,
       Vrms = 0,
       Irms = 0,
       Freq = 0;
 
//Used to determine significant change - detailed below.
int currentValue, lastValue, secondLastValue;
 
int lastValueSent;
//Significant change of more than 20W in this case.
int differenceThreshold = 20;
 
 
void setup()   {                
  
  //Start ethernet, usb serial and xbee serial.
  Ethernet.begin(mac, ip, gateway);
  
  //Serial.begin(9600);  
  
  xbeeSerial.begin(9600);
 
  delay(1000);
  
}
 
//Reads in data from xbee, converting the character stream to floats.
int readXbeeData()
{
   int done = 0;
   
   int inByte;
  
   while (xbeeSerial.available() > 0) 
   {
      //Read in a byte
      inByte = xbeeSerial.read();
 
      //Serial.print((char)inByte);
    
      //Each value send is marked with a character
      //atof converts the character array to a float.
      if (inByte=='A') realPower = atof(cArray);
      if (inByte=='B') apparentPower = atof(cArray);
      if (inByte=='C') powerFactor = atof(cArray);
      if (inByte=='D') Vrms = atof(cArray);
      if (inByte=='E') Irms = atof(cArray);
      if (inByte=='F') {Freq = atof(cArray); done = 1;}
      
      //If the recieved byte is a digit (specified by ASCII values 65 to 90)
      if (inByte>64 && inByte<91) 
      {
         ic=0;
         for(int i=0; i<10; i++) cArray[i] = 0;
      }
 
      //If the recieved byte is a digit (specified by ASCII values 65 to 90)
      //or a decimal point ASCII 46
      if ((inByte>47 && inByte<58) || inByte==46)   
      {
         //add to character array
         cArray[ic] = inByte; ic++;
      }
   }
   
   //Return status
   return done;
}
 
 
void loop()                     
{
 
if (readXbeeData()==1){
  
  
    /*In order to reduce the number of server calls, data is only sent when there is
    a significant change in power consumption. This means that we get rid of the 
    needless detail but keep the very definite change in power consumption when it
    does change significantly (The detailed data can be stored on the USB pen)
    
    //To determine if there has been a significant change we compare the last value
    with the current value if the difference is > differenceThreshold then a significant
    change has happend. But to make sure its significant and lasting, not just a blip we
    also compare the current value to the 2nd last value.*/
    
    //Set the 2nd last value
    secondLastValue = lastValue;
    
    //Set the last value
    lastValue = currentValue;
    
    //Set the current
    currentValue=(int)realPower;
    
    //Do the comparison
    if (abs(currentValue-lastValue)>differenceThreshold && abs(currentValue-secondLastValue)>differenceThreshold){
    
    //Send the data
    if (client.connect()) {   
      //Accessing a shared server requires the server domain name in here as there is no fixed ip address.
      //If your accessing a shared server you need to add your URL "GET http://yourwebsite.org/cgi-bin/post.pl?L="
      //This is because a shared server shares one fixed IP between many users, its the url that points to your website on the shared hosting.
     
      client.print(lastValueSent);
      client.print("&C=");
      client.print(currentValue);
      lastValueSent=currentValue;
      client.println();
      client.stop();
    } else {
      //Serial.println("Failed to connect to client");
    }
 
    delay(1000);
    
    }
 
 
}
 
}
 
 
This will go from one to the next.. as in from the apparent power to the pf or i should write it for each and everyone??

 

TrystanLea's picture

Re: Questions about programming

Hello Polidano

Best way to program xbee and ethernet together, is to start by getting xbee each part to work independently of each other. Maybe for now drop using my code that you have pasted above and try and assemble the code you need from the examples given by the xbee and ethernet libraries. There are a few things going on in my code above that you may not need and its quite old so you may run into problems with the latest libraries etc.

 

Comment viewing options

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