//Measuring AC mains energy use the non-invasive current transformer method //Experimental Voltage synthesis method. //OpenEnergyMonitor.org project licenced under GNU General Public Licence //Author: Trystan Lea //For analog read double value; //Constants to convert ADC divisions into mains current values. double ADCvoltsperdiv = 0.0048; double VDoffset = 2.4476; //Initial value (corrected as program runs) //Calibration values //Calculated from comparison of Irms calculated here with Irms from commercial meter. double Ioffset = -0.08; //factorA = CT sens reduction factor / Rsens double factorA = 15.2; //Constants set voltage waveform amplitude. double SetV = 228.0; double peakV = SetV * sqrt(2.0); //Used for generating voltage waveform double time=0.0; double dtime=0.0; double upeak=0.0; //Counter int i=0; int samplenumber = 2000; //Used for calculating real, apparent power, Irms and Vrms. double sumI=0.0,sumV=0.0,sumP=0.0; int sum1i=0; double sumVadc=0.0; double Vadc,Vsens,Isens,Imains,Vsynth,sqI,sqV,Irms,Vrms; double realPower,apparentPower,powerFactor; long t,lt,dt; //Increasing this value from 0 will decrease the power factor. //opossite to what i thought it did originally? double vstart = 0.0; //plotted against pf - if as v3 increases pf becomes more stable //especially good near whole numbers. 8 up is probably good double v3 = 8.0; //frequecy 50Hz double freq=5.0; //What changes power factor? //Powerfactor is max when freq is closest to grid freq //does not change with value of rsens or ctsens //max when v3 is larger than 3 and a whole number //max when vstart=0 //but max is still lower than measured on comercial meter? double twopi = 2.0 * 3.1415; double Vmax=0.0,Vmin=5.0; void setup() { Serial.begin(115200); } void loop() { value = analogRead(0); //Summing counter i++; //Voltage at ADC Vadc = value * ADCvoltsperdiv; if (Vadc>Vmax) Vmax = Vadc; if (Vadc=1000) {VDoffset = sumVadc/sum1i; sum1i = 0; sumVadc=0.0;} lt=t; t = micros(); dt=t-lt; //Infer voltage waveform from current waveform dtime=(twopi*freq*(dt/100000.0)); time=time+dtime; if (Imains>=upeak) {upeak = Imains; time=vstart*dtime;} if (time>=(v3*twopi)) {upeak=upeak/2.0; time=0.0;} Vsynth = peakV * cos(time); //Root-mean-square method current //1) square current values sqI = Imains*Imains; //2) sum sumI=sumI+sqI; //Root-mean-square method voltage //1) square voltage values sqV = Vsynth*Vsynth; //2) sum sumV=sumV+sqV; //Real power calculation //1) sum sumP=sumP+(Vsynth*Imains); if (i>=samplenumber) { i=0; //Calculation of the root of the mean of the current squared (rms) Irms = factorA*sqrt(sumI/samplenumber)+Ioffset; //Calculation of the root of the mean of the voltage squared (rms) Vrms = sqrt(sumV/samplenumber); realPower = factorA*(sumP/samplenumber); apparentPower = Irms * Vrms; powerFactor = realPower / apparentPower; //Output values to serial Serial.print(realPower); Serial.print("A"); Serial.print(apparentPower); Serial.print("B"); Serial.print(powerFactor); Serial.print("C"); Serial.print(Vrms); Serial.print("D"); Serial.print(Irms); Serial.print("E"); //Serial.print(Vmax); //Serial.print(" "); //Serial.println(Vmin); //Serial.print(" "); Vmax =0.0; Vmin=5.0; //Reset values ready for next sample. sumI=0.0; sumV=0.0; sumP=0.0; upeak=0.0; time=0.0; } }