2

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 ;                                                           
         }
}
Transistor
  • 168,990
  • 12
  • 186
  • 385

2 Answers2

6

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) {
        float power = get_power_reading();
        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.

Edgar Bonet
  • 503
  • 3
  • 4
1

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           
        sensorValue0[count] = analogRead(A0) ;
digitalWrite(13, HIGH) ; delayMicroseconds(1); digitalWrite(13, LOW) ;  // 124 us         
        sensorValue1[count] = analogRead(A1) ;
digitalWrite(13, HIGH) ; delayMicroseconds(1); digitalWrite(13, LOW) ;  // 243.5 us          
        sensorValue2[count] = analogRead(A2) ;
digitalWrite(13, HIGH) ; delayMicroseconds(1); digitalWrite(13, LOW) ;  // 358.5 us          
        sensorValue3[count] = analogRead(A3) ;
digitalWrite(13, HIGH) ; delayMicroseconds(1); digitalWrite(13, LOW) ;  // 479 us         
        sensorValue4[count] = analogRead(A4) ;
digitalWrite(13, HIGH) ; delayMicroseconds(1); digitalWrite(13, LOW) ;  // 599 us          
        sensorValue5[count] = analogRead(A5) ;
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++ ;
}


```
Antonio51
  • 11,004
  • 1
  • 7
  • 20