# Energy calculation using Arduino

How I can calculate accurate energy if I have power, current and voltage values?

This is the code of energy calculation, the result's it's wrong so how I can fix that?

I want to measure apparent energy, I don't have a problem in V, I, P values.

if(millis() >= energyLastSample + 1)
{
energySampleCount = energySampleCount + 1;
energyLastSample = millis();
}
if(energySampleCount >= 1000)
{
apparent_energy_l1 = apparent_power_l1/3600.0;
finalEnergyValue_l1 = finalEnergyValue_l1 + apparent_energy_l1;
energySampleCount = 0 ;
}
}


Energy is the integral of power, and you can compute an integral by the discrete approximation ΣPδt. In code:

float get_power_reading();  // assumed to be defined elsewhere
float energy = 0;  // calculated energy

void update_energy()
{
static uint32_t last_sample_time;
uint32_t now = millis();
uint32_t delta_t = now - last_sample_time;
if (delta_t >= minimal_sample_period) {
energy += power * delta_t;
last_sample_time = now;
}
}


A few remarks:

• The shorter the minimal sample period, the more accurate the resulting integral, but that could slow your program if get_power_reading() is a slow process. If that function is fast, you can forget about minimal_sample_period and update the energy at every loop iteration.

• If the update period is very short, use micros() instead of millis().

• Both millis() and micros() roll over periodically, but the computation of delta_t is rollover-safe.

• If energy gets very large, it may suffer an overflow (if defined as integer/fixed point) or loss of precision (if it is floating point).

• The computed energy is in milliseconds times whatever unit is used by get_power_reading(). For example, if the power reading is in watts, then the energy is in millijoules (1 W × 1 ms = 1 mJ). That would be microjoules if you are using micros() instead of millis(). You may want to convert that to the unit of your choice.

• millis() is called only once per call of update_energy(). This is important to keep the calculations correct.

• Very well written, salute. yesterday

For the sampling of data, I would use a "timer interrupt" for "exact" regularity.

• Choose timing as "problem" needs.

• Sample V and I in the interrupt task.

Then calculate outside interrupt ... P, E, and others variables if needed ... as fast as possible within "time" ...

Here a sample of parts program/libraries used with Arduino UNO...

• digitalWrite(13, HIGH) ; digitalWrite(13, LOW) ;
are for tracing on "logic analyser" the timings of sample ...

Program was use for tracing power & energy on just one 20ms cycle period (21 samples), repeated as soon as possible after all calculations (FFT included).

#include <TimerOne.h>
#include <LowPower.h>

void setup()
{
Serial.begin(115200); // Open serial connection to report values to host
pinMode(13, OUTPUT);

Timer1.initialize(1000); // set a timer of length 1000 microseconds
Timer1.attachInterrupt( timerIsr ); // attach the service routine here

}

/// --------------------------
/// Custom ISR Timer Routine
/// --------------------------
void timerIsr()
{
if (count < nbp)
{
//  Start ADC on negative edge of D13   8 channels ??? in 1 ms ???     OK !!!
// Serial.print(micros() / 10000); Serial.print("/");
// Serial.print(micros() % 10000); Serial.print("/"); // 4 us d'erreur max
// delays are used for some corrections when calculating all powers S, P, Q

digitalWrite(13, HIGH) ; delayMicroseconds(1); digitalWrite(13, LOW) ;  // 0 us
digitalWrite(13, HIGH) ; delayMicroseconds(1); digitalWrite(13, LOW) ;  // 124 us
digitalWrite(13, HIGH) ; delayMicroseconds(1); digitalWrite(13, LOW) ;  // 243.5 us
digitalWrite(13, HIGH) ; delayMicroseconds(1); digitalWrite(13, LOW) ;  // 358.5 us
digitalWrite(13, HIGH) ; delayMicroseconds(1); digitalWrite(13, LOW) ;  // 479 us
digitalWrite(13, HIGH) ; delayMicroseconds(1); digitalWrite(13, LOW) ;  // 599 us
digitalWrite(13, HIGH) ; delayMicroseconds(1); digitalWrite(13, LOW) ;  // 715 us
sensorValue6[count] = analogRead(A6) ; // mid point
digitalWrite(13, HIGH) ; delayMicroseconds(1); digitalWrite(13, LOW) ;  // 838.5 us
sensorValue7[count] = analogRead(A7) ; // mid point
digitalWrite(13, HIGH) ; delayMicroseconds(1); digitalWrite(13, LOW) ;  // 963.5us end

//  ADC channels A4, A5, A6, A7 are also ok ... on pro/mini boards ...

// channel  ... for tension measured at the "same time" ... 20.005 ms ok
// then ... calculus of active/reactive/apparent power possible
// by formula active power = v(0)*c(0)+v(90)/c(90) ???

//    Serial.print(micros()); Serial.print(" / ");
// for control exact timing
}
else {
Timer1.stop();
digitalWrite(13, LOW) ;
num_per++ ;
}
count++ ;
}

$$$$
`