How to get sample rate of programm

Hello guys,

I’m using a arduino uno and a magnetic field sensor to measure the 50Hz alternating current of a wire cable. The rms value should be measured. My problem is I don’t know how to get the sample rate of the Programm… how can I plot the signal with time x axis in seconds and get the sample rate? Here is the code:

#include <Wire.h> //Einbindung der I2C Bibliothek

unsigned char CMPS2_address = 0x30; //I2C Adresse des Kompasses

/***********DEKLARATION DER VARIABLEN*************************************/

int taster = 7;
int tasterstatus = 0;
float data[3];             //Daten nach Umrechnung in mG
unsigned int raw[3];       //Rohdaten
float offset[3];

float current[3];          //Werte nach Feldunterdrückung
float field[3];
unsigned long zeit;
float rms;                 //Betrag von X,Y und Z
int Cycles = 0;
float mw[200];
float midrms = 0;      //Variable für den gleitenden midrms

float mid1 = 0;            //Mittelwert wenn Gerät Aus ist
float mid2 = 0;            //Mittelwert wenn Gerät An (ohne Sonden)
float mid3 = 0;            //Mittelwert wenn Sonden An
float schw1 = 0;           //1. Schwellwert
float schw2 = 0;           //2. Schwellwert

//Variablen für die Ermittlung der Mittelwerte
int aktiv = 0;
float speicher1 = 0;
float speicher2 = 0;
float speicher3 = 0;
int counter1 = 0;
int counter2 = 0;
int counter3 = 0;
float current2 = 0;

//Variablen für die Zustandsausgabe
static byte alterZustand = 255;           //a value that does not make sense so that the first change is noticed
int zustand = 0;                          // Zustandsvariable
const unsigned long ZeitInterval = 5000;  //Wiederholzeit des Zustand: soll eine Stunde betragen
unsigned long letzteZeit = 0;
int test;
int Strompin = A0;              //Stromsensorpin
float val = 0; 


/**********************INITIALISIERUNG*************************************/
void setup() {
  pinMode(Strompin, INPUT);
  Serial.begin(9600); // Kommunikation mit dem seriellen Monitor
  Serial.setTimeout(0);
  delay(10);
  CMPS2_init(); //Kompass initialisierung
  pinMode(taster, INPUT);
  Serial.println(F("*************Zustandserfassungssystem************"));
  Serial.println(F("Drücken sie den Taster um eine Feldunterdrückung durchzuführen"));
  Serial.println(F("Lassen sie das Gerät ausgeschaltet. Warten sie 10 Sekunden. Drücken sie die 1 wenn sie fertig sind."));

}


/*******************HAUPTPROGRAMM UND SCHLEIFE*****************************/
void loop()
{
  messung();
  Strommessung();
  //zeit=millis();
  //Serial.print(zeit);
  //Serial.print("  ");
  Serial.print(rms);

  Serial.print("  ");
  Serial.println(current2);
  
  //Schwellwertermittlung();

  float angle = CMPS2_getHeading();

  /*if (test == 52) {    //Wenn 4 gedrückt wurde dann Ausgabe der Zustände
    aktiv = 4;
  }
  if (aktiv == 4) {
    Zustandsausgabe();
  }*/
delay(100);
}



/**********6. Funktion für die Feldunterdrückung und Berechnung des gleitenden Mittelwerts anhand des rms*********/
void messung() {

  tasterstatus = digitalRead(taster);
  if (tasterstatus == LOW)
  {
    for (int i = 0; i < 3; i++)
    {
      field[i] = data[i];                //Wenn Taster gedrückt ist, soll jetzige Feld mit altem Feld gleichgesetzt werden
    }
  }

  for (int i = 0; i < 3; i++)
  {
    current[i] = data[i] - field[i];     //Magnetfeld des Kabels = Feld - altes Feld
  }

  rms = sqrt(sq(current[0]) + sq(current[1]) + sq(current[2]));                 //Betrag der drei magnetischen Flussdichten in x,y und z-Richtung

  //Bildung des gleitenden Mittelwerts nach jeweils 200 Messungen
  mw[Cycles++] = rms;
  if (Cycles >= 200)
  {
    Cycles = 0;
  }

  for (int i = 0; i < 200; i++)
  {
    midrms += mw[i];
  }

  midrms = midrms / 200;
  //Serial.println(midrms);

}



float CMPS2_getHeading(void) {
  CMPS2_read_XYZ();  //Auslesen x,y, und z-Daten des Magnetfeldes

  //Eliminierung Offset
  for (int i = 0; i < 3; i++)
  {
    data[i] = data[i] - offset[i];
  }


  float temp0 = 0;
  float temp1 = 0;
  float deg = 0;


}



/********************5. Messungen des Magnetfeldes in x,y und z-Richtung auslesen*********************/
void CMPS2_read_XYZ(void) {

  //command internal control register 0 bit 0 (measure)
  Wire.beginTransmission(CMPS2_address);
  Wire.write(0x07);
  Wire.write(0x01);
  Wire.endTransmission();
  delay(8);

  //Warten bis Messung fertig ist
  bool flag = false;
  while (!flag) {
    //In Status Register springen
    Wire.beginTransmission(CMPS2_address);
    Wire.write(0x06);
    Wire.endTransmission();

    //Werte auslesen
    Wire.requestFrom(CMPS2_address, (uint8_t)1);
    int temporal = 0;
    if (Wire.available()) {
      temporal = Wire.read();
    }

    //Wenn der letzte Bit 1 ist, sind die Daten bereit
    temporal &= 1;
    if (temporal != 0) {
      flag = true;
    }
  }

  //Den Adressen Pointer zur ersten Adresse bewegen
  Wire.beginTransmission(CMPS2_address);
  Wire.write(0x00);
  Wire.endTransmission();

  //Daten speichern
  Wire.requestFrom(CMPS2_address, (uint8_t)6);
  byte tmp[6] = {0, 0, 0, 0, 0, 0}; //array für Rohdaten
  if (Wire.available()) {
    for (int i = 0; i < 6; i++) {
      tmp[i] = Wire.read();
    }
  }

  //Rohdaten rekonstruieren
  raw[0] = tmp[1] << 8 | tmp[0]; //x
  raw[1] = tmp[3] << 8 | tmp[2]; //y
  raw[2] = tmp[5] << 8 | tmp[4]; //z

  //Rohdaten in milliGauss konvertieren
  for (int i = 0; i < 3; i++) {
    data[i] = 0.48828125 * (float)raw[i];
  }
}

/***********************3. Kompass initialisieren und kalibrieren************************/
void CMPS2_init(void) {
  float out1[3];
  float out2[3];
  int i;

  Wire.begin(); // I2C Initialisation

  //Kalibration: SET
  Wire.beginTransmission(CMPS2_address);
  Wire.write(0x07);
  delay(10);
  Wire.write(0x80);
  Wire.endTransmission();
  delay(80);

  Wire.beginTransmission(CMPS2_address);
  Wire.write(0x07);
  delay(10);
  Wire.write(0x20);
  Wire.endTransmission();
  delay(10);

  CMPS2_read_XYZ();
  for (i = 0; i < 3; i++)
  {
    out1[i] = data[i];
  }

  //Kalibration: RESET
  Wire.beginTransmission(CMPS2_address);
  Wire.write(0x07);
  delay(10);
  Wire.write(0x80);
  Wire.endTransmission();
  delay(60);

  Wire.beginTransmission(CMPS2_address);
  Wire.write(0x07);
  delay(10);
  Wire.write(0x40);
  Wire.endTransmission();
  delay(10);

  CMPS2_read_XYZ();
  for (i = 0; i < 3; i++)
  {
    out2[i] = data[i];
  }


  //Offset Berechnung
  for (i = 0; i < 3; i++)
  {
    offset[i] = (out1[i] + out2[i]) * 0.5;
  }

  //command internal control register 0 for set operation
  Wire.beginTransmission(CMPS2_address);
  Wire.write(0x07);
  delay(10);
  Wire.write(0x40); //SET
  Wire.endTransmission();
  delay(10);

  //command internal control register 1 to 16 bit resolution, 8ms Messungszeit
  Wire.beginTransmission(CMPS2_address);
  Wire.write(0x08);
  delay(10);
  Wire.write(0x00);
  Wire.endTransmission();
  delay(10);
}

If you uncomment this, you will print the current time (in milliseconds).

Easy solution: you take samples in fixed time intervals, then also the plot reflects the time properly.

In a free running loop you have a problem with equidistant values in the Serial Plotter. No problem if you use a graphic display with scalable x and y axis.

Use millis() or micros().

Count the number of samples taken.

Record the value of millis() or micros() at the moment the first and last samples are taken.

The sample rate is number-of-samples / (last-sample-time - first-sample-time)

Do you have any idea how to increase the sample rate if it is too low ? I have 87 samples per second.

That's impossible. You have a 100ms delay in loop(). That would dictate a maximum rate of 10 samples per second.

To start with, get rid of the delay(100) in loop(). That limits your sample rate to less than 10 Hz.

Best not ignore reply #3. It's annoying when someone's questions are answered, and they ask more questions instead of responding.

Also previous observations suggest that you are not measuring it correctly. So how are you measuring it?

You should sample a 50hz signal at a minimum of 100hz. This translates to every 10ms. You should use millis() to make sure you sample at this rate. Since you have the baud rate set to 9600bps for the serial interface every character you print will cost you ~1ms once the serial buffer is full and may cause you to exceed the 10ms period.

You stop printing stuff in the sample loop. You gather all your samples into to a buffer, using the free running mode and then you do stuff to the buffer afterwards.

What stuff to you actually want to do to the data in the buffer anyway?

You speed sampling up by altering the number in the A/D's clock pre-scaler register.

It must be more than 2f (>100Hz). At exactly 100Hz you get the same magnitude with every scan, not related to the peak or RMS value. 3f (150Hz) is a reasonable minimum scan rate.

It must be much much more than 2f if there is no anti-aliasing filter at the input to the A/D. There will be extreme beat frequency interference at any small integer multiple of f, without any filter.

The Nyquist criterion applies only to bandwidth limited signals.

I concede after looking into it. I'm not an expert at frequency sampling for unfiltered signals. I have seen that a non-integer multiple >2f is better for RMS calculation in academic articles. Not something I have done.

You are 100% correct about one thing, you can not ever sample at less than a 2f rate, no matter what filter or even no filter is present. That is an absolute minimum.

1 Like

I think that this is true only if you want to reproduce the input wave. For the determination of the peak voltage of a 50Hz sine it's acceptable to sample with any non-harmonic lower frequency. Sooner or later you'll hit the peak of a wave.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.