Skocz do zawartości

Zasada obliczania cos fi EmonLib


Marcin1922

Pomocna odpowiedź

Witam, 

Czy mógłby ktoś przybliżyć mi na jakiej zasadzie w bibliotece EmonLib jest określany Cos fi ? Odbywa to się na podstawie obliczania przesunięcie pomiędzy prądem i napięciem ? I czy jesteśmy w stanie z niej wycisnąć Hz sieci ? Dodam, że posiadam już zbudowany układ pomiarowy który funkcjonuję poprawnie.

Edytowano przez Marcin1922
Link do komentarza
Share on other sites

/*
  Emon.cpp - Library for openenergymonitor
  Created by Trystan Lea, April 27 2010
  GNU GPL
  modified to use up to 12 bits ADC resolution (ex. Arduino Due)
  by boredman@boredomprojects.net 26.12.2013
  Low Pass filter for offset removal replaces HP filter 1/1/2015 - RW
*/

// Proboscide99 10/08/2016 - Added ADMUX settings for ATmega1284 e 1284P (644 / 644P also, but not tested) in readVcc function

//#include "WProgram.h" un-comment for use on older versions of Arduino IDE
#include "EmonLib.h"

#if defined(ARDUINO) && ARDUINO >= 100
#include "Arduino.h"
#else
#include "WProgram.h"
#endif


//--------------------------------------------------------------------------------------
// calc F
//--------------------------------------------------------------------------------------
void EnergyMonitor::calcF(int crossings)
{
  boolean stf = false;
  unsigned long first, second;
  unsigned long delta = 0;
  int startF = 0;
  


  while(stf == false)                                   //wait for first crossing
  {
    startF = analogRead(inPinV);                    //using the voltage waveform
    if ((startF > 512) && (startF < 520)) {
      stf = true;  //check its within range
      first = millis();
      delay(4); //Make sure no second read is in this range

    }
  }

  stf = false;

  for (int i = 0 ; i < crossings ; i++) {
    while (stf == false) {                                   //wait for next crossing
  
      startF = analogRead(inPinV);                    //using the voltage waveform
      if ((startF > 512) && (startF < 528)) {
        stf = true;
        second = millis();
        delta += (second - first); //Add time between crossings
        first = second;
        delay(4); //Make sure no second read is in this range
      }
    }
    stf = false;
  }

  frequency = (crossings / 2) / ((double)delta / 1000);
}



//--------------------------------------------------------------------------------------
// Sets the pins to be used for voltage and current sensors
//--------------------------------------------------------------------------------------
void EnergyMonitor::voltage(unsigned int _inPinV, double _VCAL, double _PHASECAL)
{
  inPinV = _inPinV;
  VCAL = _VCAL;
  PHASECAL = _PHASECAL;
  offsetV = ADC_COUNTS>>1;
}

void EnergyMonitor::current(unsigned int _inPinI, double _ICAL)
{
  inPinI = _inPinI;
  ICAL = _ICAL;
  offsetI = ADC_COUNTS>>1;
}

//--------------------------------------------------------------------------------------
// Sets the pins to be used for voltage and current sensors based on emontx pin map
//--------------------------------------------------------------------------------------
void EnergyMonitor::voltageTX(double _VCAL, double _PHASECAL)
{
  inPinV = 2;
  VCAL = _VCAL;
  PHASECAL = _PHASECAL;
  offsetV = ADC_COUNTS>>1;
}

void EnergyMonitor::currentTX(unsigned int _channel, double _ICAL)
{
  if (_channel == 1) inPinI = 3;
  if (_channel == 2) inPinI = 0;
  if (_channel == 3) inPinI = 1;
  ICAL = _ICAL;
  offsetI = ADC_COUNTS>>1;
}

//--------------------------------------------------------------------------------------
// emon_calc procedure
// Calculates realPower,apparentPower,powerFactor,Vrms,Irms,kWh increment
// From a sample window of the mains AC voltage and current.
// The Sample window length is defined by the number of half wavelengths or crossings we choose to measure.
//--------------------------------------------------------------------------------------
void EnergyMonitor::calcVI(unsigned int crossings, unsigned int timeout)
{
  #if defined emonTxV3
  int SupplyVoltage=3300;
  #else
  int SupplyVoltage = readVcc();
  #endif

  unsigned int crossCount = 0;                             //Used to measure number of times threshold is crossed.
  unsigned int numberOfSamples = 0;                        //This is now incremented

  //-------------------------------------------------------------------------------------------------------------------------
  // 1) Waits for the waveform to be close to 'zero' (mid-scale adc) part in sin curve.
  //-------------------------------------------------------------------------------------------------------------------------
  boolean st=false;                                  //an indicator to exit the while loop

  unsigned long start = millis();    //millis()-start makes sure it doesnt get stuck in the loop if there is an error.

  while(st==false)                                   //the while loop...
  {
    startV = analogRead(inPinV);                    //using the voltage waveform
    if ((startV < (ADC_COUNTS*0.55)) && (startV > (ADC_COUNTS*0.45))) st=true;  //check its within range
    if ((millis()-start)>timeout) st = true;
  }

  //-------------------------------------------------------------------------------------------------------------------------
  // 2) Main measurement loop
  //-------------------------------------------------------------------------------------------------------------------------
  start = millis();

  while ((crossCount < crossings) && ((millis()-start)<timeout))
  {
    numberOfSamples++;                       //Count number of times looped.
    lastFilteredV = filteredV;               //Used for delay/phase compensation

    //-----------------------------------------------------------------------------
    // A) Read in raw voltage and current samples
    //-----------------------------------------------------------------------------
    sampleV = analogRead(inPinV);                 //Read in raw voltage signal
    sampleI = analogRead(inPinI);                 //Read in raw current signal

    //-----------------------------------------------------------------------------
    // B) Apply digital low pass filters to extract the 2.5 V or 1.65 V dc offset,
    //     then subtract this - signal is now centred on 0 counts.
    //-----------------------------------------------------------------------------
    offsetV = offsetV + ((sampleV-offsetV)/1024);
    filteredV = sampleV - offsetV;
    offsetI = offsetI + ((sampleI-offsetI)/1024);
    filteredI = sampleI - offsetI;

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

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

    //-----------------------------------------------------------------------------
    // E) Phase calibration
    //-----------------------------------------------------------------------------
    phaseShiftedV = lastFilteredV + PHASECAL * (filteredV - lastFilteredV);

    //-----------------------------------------------------------------------------
    // F) Instantaneous power calc
    //-----------------------------------------------------------------------------
    instP = phaseShiftedV * filteredI;          //Instantaneous Power
    sumP +=instP;                               //Sum

    //-----------------------------------------------------------------------------
    // G) Find the number of times the voltage has crossed the initial voltage
    //    - every 2 crosses we will have sampled 1 wavelength
    //    - so this method allows us to sample an integer number of half wavelengths which increases accuracy
    //-----------------------------------------------------------------------------
    lastVCross = checkVCross;
    if (sampleV > startV) checkVCross = true;
                     else checkVCross = false;
    if (numberOfSamples==1) lastVCross = checkVCross;

    if (lastVCross != checkVCross) crossCount++;
  }

  //-------------------------------------------------------------------------------------------------------------------------
  // 3) Post loop calculations
  //-------------------------------------------------------------------------------------------------------------------------
  //Calculation of the root of the mean of the voltage and current squared (rms)
  //Calibration coefficients applied.

  double V_RATIO = VCAL *((SupplyVoltage/1000.0) / (ADC_COUNTS));
  Vrms = V_RATIO * sqrt(sumV / numberOfSamples);

  double I_RATIO = ICAL *((SupplyVoltage/1000.0) / (ADC_COUNTS));
  Irms = I_RATIO * sqrt(sumI / numberOfSamples);

  //Calculation power values
  realPower = V_RATIO * I_RATIO * sumP / numberOfSamples;
  apparentPower = Vrms * Irms;
  powerFactor=realPower / apparentPower;

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

//--------------------------------------------------------------------------------------
double EnergyMonitor::calcIrms(unsigned int Number_of_Samples)
{

  #if defined emonTxV3
    int SupplyVoltage=3300;
  #else
    int SupplyVoltage = readVcc();
  #endif


  for (unsigned int n = 0; n < Number_of_Samples; n++)
  {
    sampleI = analogRead(inPinI);

    // Digital low pass filter extracts the 2.5 V or 1.65 V dc offset,
    //  then subtract this - signal is now centered on 0 counts.
    offsetI = (offsetI + (sampleI-offsetI)/1024);
    filteredI = sampleI - offsetI;

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

  double I_RATIO = ICAL *((SupplyVoltage/1000.0) / (ADC_COUNTS));
  Irms = I_RATIO * sqrt(sumI / Number_of_Samples);

  //Reset accumulators
  sumI = 0;
  //--------------------------------------------------------------------------------------

  return Irms;
}

void EnergyMonitor::serialprint()
{
  Serial.print(realPower);
  Serial.print(' ');
  Serial.print(apparentPower);
  Serial.print(' ');
  Serial.print(Vrms);
  Serial.print(' ');
  Serial.print(Irms);
  Serial.print(' ');
  Serial.print(powerFactor);
  Serial.println(' ');
  delay(100);
}

//thanks to http://hacking.majenko.co.uk/making-accurate-adc-readings-on-arduino
//and Jérôme who alerted us to http://provideyourown.com/2012/secret-arduino-voltmeter-measure-battery-voltage/

long EnergyMonitor::readVcc() {
  long result;

  //not used on emonTx V3 - as Vcc is always 3.3V - eliminates bandgap error and need for calibration http://harizanov.com/2013/09/thoughts-on-avr-adc-accuracy/

  #if defined(__AVR_ATmega168__) || defined(__AVR_ATmega328__) || defined (__AVR_ATmega328P__)
  ADMUX = _BV(REFS0) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1);
  #elif defined(__AVR_ATmega644__) || defined(__AVR_ATmega644P__) || defined(__AVR_ATmega1284__) || defined(__AVR_ATmega1284P__)
  ADMUX = _BV(REFS0) | _BV(MUX4) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1);
  #elif defined(__AVR_ATmega32U4__) || defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) || defined(__AVR_AT90USB1286__)
  ADMUX = _BV(REFS0) | _BV(MUX4) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1);
  ADCSRB &= ~_BV(MUX5);   // Without this the function always returns -1 on the ATmega2560 http://openenergymonitor.org/emon/node/2253#comment-11432
  #elif defined (__AVR_ATtiny24__) || defined(__AVR_ATtiny44__) || defined(__AVR_ATtiny84__)
  ADMUX = _BV(MUX5) | _BV(MUX0);
  #elif defined (__AVR_ATtiny25__) || defined(__AVR_ATtiny45__) || defined(__AVR_ATtiny85__)
  ADMUX = _BV(MUX3) | _BV(MUX2);

  #endif


  #if defined(__AVR__)
  delay(2);                                        // Wait for Vref to settle
  ADCSRA |= _BV(ADSC);                             // Convert
  while (bit_is_set(ADCSRA,ADSC));
  result = ADCL;
  result |= ADCH<<8;
  result = READVCC_CALIBRATION_CONST / result;  //1100mV*1024 ADC steps http://openenergymonitor.org/emon/node/1186
  return result;
  #elif defined(__arm__)
  return (3300);                                  //Arduino Due
  #else
  return (3300);                                  //Guess that other un-supported architectures will be running a 3.3V!
  #endif
}

calc F to dodany kod. Jak nie znajduje przejść prze ,,zero'' zatrzymuje program i czeka na nie. Jak tego uniknąć ? by gdy tych przejść nie będzie program biegł dalej ?

 

Link do komentarza
Share on other sites

Zarejestruj się lub zaloguj, aby ukryć tę reklamę.
Zarejestruj się lub zaloguj, aby ukryć tę reklamę.

jlcpcb.jpg

jlcpcb.jpg

Produkcja i montaż PCB - wybierz sprawdzone PCBWay!
   • Darmowe płytki dla studentów i projektów non-profit
   • Tylko 5$ za 10 prototypów PCB w 24 godziny
   • Usługa projektowania PCB na zlecenie
   • Montaż PCB od 30$ + bezpłatna dostawa i szablony
   • Darmowe narzędzie do podglądu plików Gerber
Zobacz również » Film z fabryki PCBWay

void EnergyMonitor::calcF(int crossings)
{
  boolean stf = false;
  unsigned long first, second,firsta ;
  unsigned long delta = 0;
  int startF = 0;
  firsta = millis() + 1000;

  if (firsta <= millis()) {
    return;
  }
else {

  while(stf == false)                                   //wait for first crossing
  {
    startF = analogRead(inPinV);                    //using the voltage waveform
    if ((startF > 512) && (startF < 520)) {
      stf = true;  //check its within range
      first = millis();


      delay(4); //Make sure no second read is in this range

    }
  }

  stf = false;

  for (int i = 0 ; i < crossings ; i++) {
    while (stf == false) {                                   //wait for next crossing
  
      startF = analogRead(inPinV);                    //using the voltage waveform
      if ((startF > 512) && (startF < 528)) {
        stf = true;
        second = millis();
        delta += (second - first); //Add time between crossings
        first = second;
        delay(4); //Make sure no second read is in this range
  
      }
    }
    stf = false;

  }
  

  frequency = (crossings / 2) / ((double)delta / 1000);
}
}

próbowałem dać takiego if , że jak dłużej niż 1 s zamuje to żeby przerwało ale nie zdaje to egzaminu 

 

 

Link do komentarza
Share on other sites

void EnergyMonitor::calcF(int crossings)
{
boolean stf = false;
unsigned long first, second;
unsigned long delta = 0;
int startF = 0;
int g = 0;

 while (stf == false)                                   //wait for next crossing
{
  startF = analogRead(inPinV);                    //using the voltage waveform
  if ((startF > 512) && (startF < 520))
  {
   stf = true;  //check its within range
   first = millis();
   delay(4); //Make sure no second read is in this range
  }
g++;
if (g > 3000)
{
return;
}
}




stf = false;

for(int i = 0 ; i < crossings ; i++)
{
  while (stf == false)                                   //wait for next crossing
  {
   startF = analogRead(inPinV);                    //using the voltage waveform
   if ((startF > 512) && (startF < 528))
   {
    stf = true;
    second = millis();
    delta += (second - first); //Add time between crossings
    first = second;
    delay(4); //Make sure no second read is in this range
   }
   g++;
if (g > 3000)
{
return;
}
  }
 stf = false;
}

frequency = (crossings / 2.0115) / ((double)delta / 1000);
g=0;
}

Oczywiście, że dodam. Sposób toporny prosty ale najważniejsze, że działa. 

  • Lubię! 1
Link do komentarza
Share on other sites

Przed chwilą, ethanak napisał:

Bardzo się z tego powodu cieszymy, chyba nawet zrobimy jakąś imprezę okolicznościową...

A zdradzisz tajemnicę jak to zrobiłeś, czy będziesz się starać o patent?

Raczej będę starał się o patent 

  • Lubię! 1
Link do komentarza
Share on other sites

2 minuty temu, farmaceuta napisał:

Ale bez alkoholowa rozumiem?( 😂hahahah) wybacz mi to! Nie wiem co dzis z tym alko mi sie pokrecilo...zartuje😇

Bez alkoholowa hmmmm ... To warto wyprawiać 😄 ? 

  • Lubię! 1
Link do komentarza
Share on other sites

1 minutę temu, Marcin1922 napisał:

Szczerze mówiąc nie słyszałem o formatowaniu kodu.

W skrocie chodzi o to zeby kod byl schludny i latwo czytelny...zeby przestrzegac nie tyle zasad, ale takich ogolnie przyjetych norm tego jak taki kod powinien wygladac, zeby kazdy w miare szybko mogl przesledzic o co w tym programie chodzi...tak z grubsza (no ale wiadomo..kazdy pisze jak chce, zwlaszcza dla siebie...wazne zeby dzialalo😉)

  • Lubię! 1
Link do komentarza
Share on other sites

Bądź aktywny - zaloguj się lub utwórz konto!

Tylko zarejestrowani użytkownicy mogą komentować zawartość tej strony

Utwórz konto w ~20 sekund!

Zarejestruj nowe konto, to proste!

Zarejestruj się »

Zaloguj się

Posiadasz własne konto? Użyj go!

Zaloguj się »
×
×
  • Utwórz nowe...

Ważne informacje

Ta strona używa ciasteczek (cookies), dzięki którym może działać lepiej. Więcej na ten temat znajdziesz w Polityce Prywatności.