1

I am taking voltage signal from Analog Input (A0 pin) and current signal (in the form of voltage) from Analog input (A1 pin), converting it to digital and then processing it to get Vrms, Irms and phase data. Then i am storing it in a "dataString" and writing it onto SD card.

The problem i am facing is that somewhere in the floating point computation of the power factor I am doing something wrong due to which the answer is being "displayed as" 1.00 whereas at an angle of 4.97 (degrees) i should get cos(4.97) = 0.9962 (Picture attached) Image1

Although the program is using the correct value i.e., 0.9962 in further computations ( that of real Power) but i want it to display the power factor correctly upto 4 points after decimal. Here is my program code

#include <SPI.h>
#include <SD.h>

#include <Wire.h>
#include "RTClib.h"

RTC_DS1307 RTC;
#include "DHT.h"

#define DHTPIN 8 
#define DHTTYPE DHT21
DHT dht(DHTPIN, DHTTYPE);

#define count 100

const int analogInPin1 = A1;
const int analogInPin0 = A0;

const int chipSelect = 10;

void setup()
{
  Serial.begin(115200);
        Wire.begin();
        RTC.begin();

      if (! RTC.isrunning()) {
        Serial.println("#RTC is NOT running!");
        // following line sets the RTC to the date & time this sketch was compiled
        // uncomment it & upload to set the time, date and start run the RTC!
       // RTC.adjust(DateTime(__DATE__, __TIME__));
      }
  analogReference(DEFAULT);
  Serial.println("#DHTxx test!");

  dht.begin();


  Serial.print("#Initializing SD card...");

  // see if the card is present and can be initialized:
  if (!SD.begin(chipSelect)) {
    Serial.println("#Card failed, or not present");
    // don't do anything more:
    return;
  }
  Serial.println("#card initialized.");
  Serial.println("#Date        Time           Vrms          Irms         Phase        Power_factor       Apparent_Power     Real_Power        Humidity         Temperature");


}

void loop()
{


  float sensorValue0[count];        
  float sumSensorValue0=0;
  float meanSensorValue0=0;
  float Vrms=0;
  sumSensorValue0=0;

  float sensorValue1[count];        
  float sumSensorValue1=0;
  float meanSensorValue1=0;
  float Irms=0;
  int i=0;
  sumSensorValue1=0;

  DateTime now = RTC.now();

  for(i=0;i<count;i++)
  {
    sensorValue1[i] = (analogRead(analogInPin1)*4.8)-3200; //4.8 mV (i.e. 0.0048 Volts)  per unit.. Vref/1024.. here Vref = 5 V ....//3.220 V = Offset
    sensorValue0[i] = (analogRead(analogInPin0)*4.8)-3200;

    sensorValue1[i] = sensorValue1[i]*sensorValue1[i];
    sensorValue0[i] = sensorValue0[i]*sensorValue0[i];
    sumSensorValue1+= sensorValue1[i];
    sumSensorValue0+= sensorValue0[i];
  }

  meanSensorValue1 = sumSensorValue1/count;
  meanSensorValue0 = sumSensorValue0/count;
  Irms = (sqrt(meanSensorValue1)*0.06); //60/1000 = 0.06 Calibrating 60 Ampere/1 Volt to give us the value for X amperes
  Vrms = (sqrt(meanSensorValue0)*0.3565); // Multiplying with 356.5(the product of ratios of 9V and 12 V transformer) gives the measured voltage in mV.. dividing by 1000 to bring it to Volts from mV
  float appPower;
  appPower = Vrms*Irms;

float Vsense=0;
float LastVsense=0;
float Isense=0;
float LastIsense=0;
float phase;
float mean_phase=0;
float counter=0;
unsigned long timer;

 for(int i=0;i<200;i++)
  {
  // put your main code here, to run repeatedly:
 Isense=analogRead(A1)*4.8-3200;
 Vsense=analogRead(A0)*4.8-3220;
 if(Vsense>= 0 && LastVsense<0  && Isense<0 )
   { 
  timer = micros();
  do{
    Isense=analogRead(A1)*4.8-3200;
  }while(!(Isense>=0));
    timer = micros()-timer;
    phase = (timer*360.0)/20000.0;
    mean_phase+=phase;
    counter+=1.0;
    }else;

    if(Isense >= 0 && LastIsense < 0  && Vsense < 0 )
   { 
  timer = micros();
  do{
    Vsense=analogRead(A0)*4.8-3200;
  }while(!(Vsense>=0));
    timer = micros()-timer;
    phase = (timer*360.0)/20000.0;
    mean_phase+=phase;
    counter+=1.0;
    }else;

LastIsense = Isense;
LastVsense = Vsense;

}
  mean_phase= mean_phase/counter;


  float realPower;
  float powerFactor;
  float phase_rad= mean_phase*PI/180.0;
  powerFactor =cos(phase_rad); //phase converted to radian for cosine function
  realPower = Vrms*Irms*powerFactor;

   String dataString = "";

  float h = dht.readHumidity();
  float t = dht.readTemperature();

   if (isnan(t) || isnan(h)) {
    Serial.println("#Failed to read from DHT");
  } else {
    dataString+=now.year(), DEC;
    dataString+="/";
    dataString+=now.month(), DEC;
    dataString+="/";
    dataString+=now.day(), DEC;
    dataString+=" ";
    dataString+=now.hour(), DEC;
    dataString+=":";
    dataString+=now.minute(), DEC;
    dataString+=":";
    dataString+=now.second(), DEC;
    dataString+="         ";
    dataString+=Vrms;
    dataString+="         ";
    dataString+=Irms;
    dataString+="         "; 
    dataString+=mean_phase;
    dataString+="         ";
    dataString+=powerFactor;
    dataString+="                 ";
    dataString+=appPower; 
    dataString+="                 ";
    dataString+=realPower;
    dataString+="         ";
    dataString+=h;
    dataString+="         ";
    dataString+=t;

  }
  // open the file. note that only one file can be open at a time,
  // so you have to close this one before opening another.
  File dataFile = SD.open("datalog.dat", FILE_WRITE);

  // if the file is available, write to it:
  if (dataFile) {
    dataFile.println(dataString);
    dataFile.close();
    // print to the serial port too:
    Serial.println(dataString);
  }
  // if the file isn't open, pop up an error:
  else {
    Serial.println("#error opening datalog.dat");
    }

  delay(10000);
}

1 Answer 1

1

Although the program is using the correct value i.e., 0.9962 in further computations...

That points to the issue being in your printing code.

More specifically, I suspect that this line might be causing trouble:

dataString+=powerFactor;

You are using the String class, so WString.cpp is the relevant file.

If we inspect it, we find that on line 409 (at least, in my version of Arduino, 1.6.7 IIRC), the + operator is declared for floats, and it simply calls concat(float), which can be found on line 323:

unsigned char String::concat(float num)
{
    char buf[20];
    char* string = dtostrf(num, 4, 2, buf);
    return concat(string, strlen(string));
}

If you read the dtostrf docs, you will find that this is converting a double (the float gets promoted) to a string with a width of 4 and 2 digits of precision.

The easiest way to get around this is to use dtostrf to convert the float to a string with the precision you want, and then append that string to your String instance.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.