Using EmonLib library and analogReadFast library for better AC sampling is ok?

Hi there

I´m building a Arduino energy monitor using the emonlib library

All is good for now but I´m navigating in the inner workings and principles of what is happening in the background.

From the Open energy monitor page I got this:

"As the name suggests, AC Voltage and current continually alternate. If we draw a picture of the voltage and current waveform over time, it will look something like the image below. Depending on the type of load consuming power, the current waveform - blue in the diagram below - is what you get if you look at a typical laptop computer power supply. (There’s an incandescent light bulb present, as well).

The image was made by sampling the mains voltage and current at high frequency, which is exactly what we do on the emontx or Arduino. We make between 50 and 100 measurements every 20 milliseconds. 100 if sampling only current. 50, if sampling voltage and current. We’re limited by the Arduino analog read command and calculation speed."

“We’re limited by the Arduino analog read command and calculation speed.”

So looking in the library .cpp file i came across this

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++;
  }


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;
}

Would it be of some benefit in order to enhance the number of samples the use of the analogReadFast library wich decreases the time for each analog reading from around 112uS to 17uS give or take?

My goal here is to use the faster analog read transitio to take more samples at a given interval and graph that RAW data into excel to see the sine waveform and see if I can catch some harmonic distortion

Bare in mind that I´m a newbie and enthusiastic about electronics so there should be a bunch here that I´m ignoring before hand

Link to analogReadFast Library
Link to Open Energy Documentation
Link to Open Energy Monitor Library

Regards

Would it be of some benefit in order to enhance the number of samples the use of the analogReadFast library wich decreases the time for each analog reading from around 112uS to 17uS give or take?

The increase in speed is not for free. You loose resolution. With analogReadFast you get about 7bit. Is the speed gain worth it?

My goal here is to use the faster analog read transitio to take more samples at a given interval and graph that RAW data into excel to see the sine waveform and see if I can catch some harmonic distortion

How do you get this data out of the Arduino? With analogReadFast you get a sampling rate of almost 50kHz. So you need a serial speed of 500000 baud to get this data to a PC in the ideal case. Do you really need 1000 samples per full wave?

I think this is a job for our SuperHero Software Guru's

if you use an SMT32 with it's blazing speed and on-board ADC, can you address the port faster ?

can you address the ADC faster if you do not use the Arduino software ?

I would like to monitor 8 (or 9 ) channels for current and get apparent power, so I am very interested in this thread.
I am data logging 4 channels now.

The analog read used by Emon is based on the sound card input with an analog connection to the PC they're reading directly to the PC and not using the Arduino.
I believe you're limited into how many channels you could use for that but it's in a much higher rate

pylon:
The increase in speed is not for free. You loose resolution. With analogReadFast you get about 7bit. Is the speed gain worth it?

How do you get this data out of the Arduino? With analogRead Fast you get a sampling rate of almost 50 kHz. So you need a serial speed of 500000 baud to get this data to a PC in the ideal case. Do you really need 1000 samples per full wave?

I store the raw values in an array the length of the samples taken. Then after filling the array I read it´s values and print them in the serial monitor.

Maybe 1000 samples per full wave it´s a bit overkill. I agree, but I want at least to scan the full wave (50Hz) at 300 Hz to see the third harmonics present (correct me if wrong, not a wise guy just a lot of reading)

For now I take 10 samples of a full sine wave, (each 2ms, 1960 uS to be exact to compensate the time it takes to read both voltage and current sensors)

If I decrease the window from 2ms to 1ms and graph in excel I already start to see noise in the sine wave.

Will analogRead Fast improve this situation?

Maybe 1000 samples per full wave it´s a bit overkill. I agree, but I want at least to scan the full wave (50Hz) at 300 Hz to see the third harmonics present (correct me if wrong, not a wise guy just a lot of reading)

300Hz is not much, the standard ADC if able to read that. But I guess that's not what you meant.

If I decrease the window from 2ms to 1ms and graph in excel I already start to see noise in the sine wave.

Post your code.

Will analogRead Fast improve this situation?

Yes and no. It will probably remove the noise as the ADC resolution will be decreased significantly but it won't solve your problem. You have to take a lot of other factors into account. In the end the exact circuit is also relevant.

Sorry, got busy with work

here is the code

Super_Medidor_de_Fase__Con_array_y_eMonlib.zip (4.13 KB)

It's not nice to name a RAR file .zip!

If I decrease the window from 2ms to 1ms and graph in excel I already start to see noise in the sine wave.

That is the code that decreases a window? It doesn't even call the muestreo() routine (whatever that name means).
Post the picture you get to let us see that noise too. What reference voltage do you use?

And as I said the analogReadFast() has a resolution of about 8bit. Is that enough for you?

The ADC is measuring an AC cycle with 2.5 volts as the middle Range Rover the voltage level of 0 that means you really only getting half of the full spin of the ADC if you use an op amp and turn the output into all positive voltage output you can use a greater span of the ADC if you're adding an op amp can't you just turn it into a amperage value and eliminate trying to monitor all the digital points of the RMS cycle and just have the op amp output the apparent current as a simple 0 to 5 volt value.
Text to speech from my cell phone