Author Topic: 50/60 Hz signals and ADC sampling frequency  (Read 8723 times)

0 Members and 1 Guest are viewing this topic.

Offline hamster_nz

  • Super Contributor
  • ***
  • Posts: 2812
  • Country: nz
Re: 50/60 Hz signals and ADC sampling frequency
« Reply #25 on: September 06, 2020, 11:12:53 am »
I know it doesn't meet your needs to find out the AC value in 1/50th or 1/60th of a second - this needs 1/10th.

However, here's what I was indirectly ranting about...

The update when you get a new sample is very simple:

Code: [Select]
static void include_new_sample(uint16_t new_data) {
       // Remove the oldest sample
   running_total         -= data[index];
   running_squared_total -= data[index]*data[index];
       // Add the new sample
   running_total         += new_data;
   running_squared_total += new_data*new_data;
       // Store the new data for when we remove it
   data[index] = new_data;
      // Update the index
   index = (index == N_POINTS-1) ? 0 : index+1;
}

Extracting the DC and AC RMS values is pretty simple too, (but only if you can use floating point, with integers only it will be a bit more tricky):

Code: [Select]
static void output_results(void) {
   double avg, total_power, dc_power, ac_power, ac_rms;

   avg         = running_total/(double)(N_POINTS);
   total_power = running_squared_total/((double)(N_POINTS));
   dc_power    = avg*avg;
   ac_power    = total_power - dc_power;
   ac_rms      = sqrt(ac_power);

   printf("%4i: Average is %6.2f, dc power is %9.1f, ac power is %8.1f, ac_rms %6.2f\n",
          sample_no, avg, dc_power, ac_power, ac_rms);
}

Here's the full test, in case you want to play with it. Note that it will of course take 100 samples to 'ramp up', and is using unsigned int values:

Code: [Select]
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <math.h>
#include <time.h>

#define N_POINTS 100
static uint16_t data[N_POINTS];
static uint16_t index;
static uint32_t running_total;
static uint32_t running_squared_total;
static uint32_t sample_no = 0;

static void include_new_sample(uint16_t new_data) {
       // Remove the oldest sample
   running_total         -= data[index];
   running_squared_total -= data[index]*data[index];
       // Add the new sample
   running_total         += new_data;
   running_squared_total += new_data*new_data;
       // Store the new data for when we remove it
   data[index] = new_data;
      // Update the index
   index = (index == N_POINTS-1) ? 0 : index+1;
}

static void output_results(void) {
   double avg, total_power, dc_power, ac_power, ac_rms;

   avg         = running_total/(double)(N_POINTS);
   total_power = running_squared_total/((double)(N_POINTS));
   dc_power    = avg*avg;
   ac_power    = total_power - dc_power;
   ac_rms      = sqrt(ac_power);

   printf("%4i: Average is %6.2f, dc power is %9.1f, ac power is %8.1f, ac_rms %6.2f\n",
          sample_no, avg, dc_power, ac_power, ac_rms);
}

uint16_t get_sample(int waveform) {
  uint16_t new_val = 0;

  switch(waveform) {
    case 1: // Random of +/- 50, DC of 100 , RMS of about 30
      new_val = rand()/(RAND_MAX/100)-50 + 100;
      break;
    case 2: // Sine of 20 samples (50Hz at 1kS/s), 70.7 units RMS, DC 200
      new_val = sin(2.0*M_PI * sample_no/20)*100 + 200;
      break;
    case 3: // Sine of 16.6 samples (60Hz @ 1kS/s) 70.7 units RMS DC 512
      new_val = sin(2.0*M_PI * sample_no/16.66)*100 + 512;
      break;
    default:
      new_val = 0;
      break;
  }
  sample_no++;

  return new_val;
}

int main(int argc, char *argv[]) {
   srand(time(NULL));  // Just in case we use rand()

   for(int i = 0; i < 1000; i++) {
      include_new_sample(get_sample(3));

      // Results only every 10 samples
      if(i %10 == 0) output_results();
   }
}
« Last Edit: September 06, 2020, 11:18:12 am by hamster_nz »
Gaze not into the abyss, lest you become recognized as an abyss domain expert, and they expect you keep gazing into the damn thing.
 

Offline NorthGuy

  • Super Contributor
  • ***
  • Posts: 3246
  • Country: ca
Re: 50/60 Hz signals and ADC sampling frequency
« Reply #26 on: September 06, 2020, 03:57:58 pm »
If someone uses the device in a place powered by a generator, the frequency may vary. Nominally, generator is 60 Hz, but as the load on the generator changes and the generator tries to adjust, the frequency may vary between 50 and 70 Hz, or even wider.
 

Offline David Hess

  • Super Contributor
  • ***
  • Posts: 17146
  • Country: us
  • DavidH
Re: 50/60 Hz signals and ADC sampling frequency
« Reply #27 on: September 07, 2020, 04:35:07 am »
If someone uses the device in a place powered by a generator, the frequency may vary. Nominally, generator is 60 Hz, but as the load on the generator changes and the generator tries to adjust, the frequency may vary between 50 and 70 Hz, or even wider.

Higher performance designs phase lock a local oscillator to the line frequency to provide a clean phase reference.  Today of course this is all done in the digital domain.
 

Offline Red_MicroTopic starter

  • Regular Contributor
  • *
  • Posts: 121
  • Country: ca
Re: 50/60 Hz signals and ADC sampling frequency
« Reply #28 on: September 07, 2020, 03:55:54 pm »
I also found this code that is attached that claims to calculate RMS using Walsh Functions. The author said it was tested on an Atmega328P. Anyways, Walsh Functions is a totally different monster for me so it would take a while for me to understand it. I think that code is only for 60 Hz. Not sure if it even works. Maybe someone can have a look and provide feedback.

Source of the code: https://www.avrfreaks.net/forum/adc-calculating-rms-dc-biased-signal
« Last Edit: September 07, 2020, 04:34:09 pm by Red_Micro »
 

Offline hamster_nz

  • Super Contributor
  • ***
  • Posts: 2812
  • Country: nz
Re: 50/60 Hz signals and ADC sampling frequency
« Reply #29 on: September 08, 2020, 09:59:20 pm »
I also found this code that is attached that claims to calculate RMS using Walsh Functions. The author said it was tested on an Atmega328P. Anyways, Walsh Functions is a totally different monster for me so it would take a while for me to understand it. I think that code is only for 60 Hz. Not sure if it even works. Maybe someone can have a look and provide feedback.

Source of the code: https://www.avrfreaks.net/forum/adc-calculating-rms-dc-biased-signal

Had a look at the math behind this. It's much like a single FFT bin at f/4, but with a tiny twist to make the math cleaner.

- Take four samples 90 degrees apart (so will need different samples for different frequencies

- Multiply samples by sin() and cos(), but at 45, 135, 225, 315 degrees (e.g. 0.707, 0.707, -0.707, -0.707 for sin()) rather than the usual 0,90,180,270 degrees.

- However, these are pre-scaled by the 1/(RMS of a sine wave), which is 0.707, making the coefficients (1,1,-1,-1) fir sin() and (1, -1, -1, 1) for cos(). This turns the mults into just adds and subtracts.

- Then compute the magnitude of the resulting vector

So the code ends up being the relatively simple:

Code: [Select]
CAL = x0 - x1 - x2 + x3
SAL = x0 + x1 - x2 - x2
RMS = sqrt(CAL*CAL + SAL*SAL)

Pretty cute.
Gaze not into the abyss, lest you become recognized as an abyss domain expert, and they expect you keep gazing into the damn thing.
 

Offline Red_MicroTopic starter

  • Regular Contributor
  • *
  • Posts: 121
  • Country: ca
Re: 50/60 Hz signals and ADC sampling frequency
« Reply #30 on: September 08, 2020, 11:36:18 pm »
I also found this code that is attached that claims to calculate RMS using Walsh Functions. The author said it was tested on an Atmega328P. Anyways, Walsh Functions is a totally different monster for me so it would take a while for me to understand it. I think that code is only for 60 Hz. Not sure if it even works. Maybe someone can have a look and provide feedback.

Source of the code: https://www.avrfreaks.net/forum/adc-calculating-rms-dc-biased-signal

Had a look at the math behind this. It's much like a single FFT bin at f/4, but with a tiny twist to make the math cleaner.

- Take four samples 90 degrees apart (so will need different samples for different frequencies

- Multiply samples by sin() and cos(), but at 45, 135, 225, 315 degrees (e.g. 0.707, 0.707, -0.707, -0.707 for sin()) rather than the usual 0,90,180,270 degrees.

- However, these are pre-scaled by the 1/(RMS of a sine wave), which is 0.707, making the coefficients (1,1,-1,-1) fir sin() and (1, -1, -1, 1) for cos(). This turns the mults into just adds and subtracts.

- Then compute the magnitude of the resulting vector

So the code ends up being the relatively simple:

Code: [Select]
CAL = x0 - x1 - x2 + x3
SAL = x0 + x1 - x2 - x2
RMS = sqrt(CAL*CAL + SAL*SAL)

Pretty cute.

Makes sense. It looks like it works good only for 60 Hz not for 50 Hz.
 

Offline hamster_nz

  • Super Contributor
  • ***
  • Posts: 2812
  • Country: nz
Re: 50/60 Hz signals and ADC sampling frequency
« Reply #31 on: September 08, 2020, 11:58:33 pm »
I also found this code that is attached that claims to calculate RMS using Walsh Functions. The author said it was tested on an Atmega328P. Anyways, Walsh Functions is a totally different monster for me so it would take a while for me to understand it. I think that code is only for 60 Hz. Not sure if it even works. Maybe someone can have a look and provide feedback.

Source of the code: https://www.avrfreaks.net/forum/adc-calculating-rms-dc-biased-signal

Had a look at the math behind this. It's much like a single FFT bin at f/4, but with a tiny twist to make the math cleaner.

- Take four samples 90 degrees apart (so will need different samples for different frequencies

- Multiply samples by sin() and cos(), but at 45, 135, 225, 315 degrees (e.g. 0.707, 0.707, -0.707, -0.707 for sin()) rather than the usual 0,90,180,270 degrees.

- However, these are pre-scaled by the 1/(RMS of a sine wave), which is 0.707, making the coefficients (1,1,-1,-1) fir sin() and (1, -1, -1, 1) for cos(). This turns the mults into just adds and subtracts.

- Then compute the magnitude of the resulting vector

So the code ends up being the relatively simple:

Code: [Select]
CAL = x0 - x1 - x2 + x3
SAL = x0 + x1 - x2 - x2
RMS = sqrt(CAL*CAL + SAL*SAL)

Pretty cute.

Makes sense. It looks like it works good only for 60 Hz not for 50 Hz.

... and most likely only if you have tightly band-passed the signal to the target frequency before sampling.
Gaze not into the abyss, lest you become recognized as an abyss domain expert, and they expect you keep gazing into the damn thing.
 


Share me

Digg  Facebook  SlashDot  Delicious  Technorati  Twitter  Google  Yahoo
Smf