Prototyping – Part I

Well I finally got around to get some code and test things out. Without known test loads and an oscilloscope, testing shall require some creativity.  Armed with a multimeter I began testing things out.

Software

The longer term plans include creating spot measurement devices  using the arduino and rather than slapping the code and copying and pasting stuff around, I opted to create a couple of classes to facilitate reuse. It took some trial and error to understand how to add classes to the arduino dev environment and could never get multiple inheritence to compile in the environment. I assumed the problem was between the keyboard and the chair.

I ended creating two classes: ACSignal to help capture and compute some basic stuff like average, RMS values. The PowerSignal class takes two ACSginal references and computes apparent power, real power, etc.

The code to use the classes is rather simple. Converting the float to alpha–since the LCD4Bit library does not handle spitting out floats–took more time that I wanted.

As explained earlier, the math looks more complicated than it is. The two main formulas are shown below along with the corresponding code to implement it. Anti-climatic if you ask me, but nice to see the stuff working.  As long as the sampling rate is much greater than the highest frequency component, things should be good to go. I take 2000 samples display stuff and resample.  Since this is all this arduino does I don’t need interrupt driven sampling periods. The maximum sampling rate for the ATMEGA chip on the arduino is around 9600 hz.  More than enough for this power line sampling.

P_{avg} = \frac{1}{N}\sum_{n=1}^{N}v_ni_n \approx \frac {1}{T}\int^{to+T}_{to}p(t)dt \qquad(1) X_{rms}= \sqrt{\frac{1}{N}\sum_{n=1}^{N}x^2_n} \approx \sqrt{\frac {1}{T}\int^{to+T}_{to}x^2(t)dt} \qquad(2)

@@

void PowerSignal::updateAccumulator()
{
  mSumVoltageTimesCurrent += mVoltageSignal.getInstantaneousValue() * mCurrentSignal.getInstantaneousValue();
}

float PowerSignal::computeAveragePower()
{
 return( mSumVoltageTimesCurrent / mVoltageSignal.getSampleCount() );
}

float ACSignal::acquireSignalSample()
{
 float lVal;

 mCurSample = analogRead( mPin )  ;
 mCurVoltage = mCurSample * PS_VOLTS_PER_STEP;
 mSampleCount++;
 mSumVoltageRaw += mCurVoltage;
 mRealVoltage = mCurVoltage - mDCOffset;  // remove DC offset from circuit voltage divider
 lVal = getInstantaneousValue();
 mSumVoltageSquared +=  lVal * lVal;

 if( lVal > mMax )
 mMax = lVal;

 if( lVal < mMin )
 mMin = lVal;

 return( lVal );

}
float ACSignal::getRMSValue()
{
 float lRMSValue = PS_PWR_CALC_ERR;
 if( mSampleCount > 0 )
   lRMSValue = sqrt( mSumVoltageSquared / mSampleCount );
 return( lRMSValue );

}