RMS di un sensore analogico generico.

Vorrei fare una RMS di un insieme di valori rilevati da un sensore analogico. Ad esempio di un accelerometro.

Come posso fare un'operazione del genere?

In teoria so cosa si deve fare per calcolarlo ma non so tradurre il tutto in linguaggio di programmazione per Arduino!

Perché una RMS che calcola il valore efficace? Non basta la media aritmetica od altri metodi simili?

In merito alle vibrazioni:

"La RMS è la misura più significativa di ampiezza in quanto tiene conto della storia dell’onda nel tempo e dà un valore di ampiezza direttamente correlata al contenuto energetico della vibrazione".

Che uscita ti fornisce l'accelerometro?

sossio89:
In merito alle vibrazioni:

"La RMS è la misura più significativa di ampiezza in quanto tiene conto della storia dell’onda nel tempo e dà un valore di ampiezza direttamente correlata al contenuto energetico della vibrazione".

Significa solo che devi campionare il segnale con una frequenza sufficientemente alta da includere tutti i transitori in essa contenuti e poi fare la media aritmentica che altro non è che la media integrale del segnale in funzione al tempo

sossio89:
In merito alle vibrazioni:
"La RMS è la misura più significativa di ampiezza in quanto tiene conto della storia dell’onda nel tempo e dà un valore di ampiezza direttamente correlata al contenuto energetico della vibrazione".

l'rms non serve a nulla nell'analisi delle vibrazioni, questo perché il calcolo del rms lavora nel dominio del tempo mentre per una corretta analisi delle vibrazioni devi lavorare nel dominio della frequenza e ottenere un spettrogramma della vibrazione, questo si che ti fornisce tutte le informazioni.

So bene che da un segnale vibrazionale costruire uno spettro in frequenza mi darebbe info dettagliate del segnale.

Ora però ho bisogno dell RMS.

il segnale proviene da un sensore analogico.

Come potrei scriverlo in linguaggio C?

Per ottenere il valore RMS, il segnale viene elevato al quadrato, si esegue la sommatoria dei
valori nel tempo, ed infine viene eseguita la radice quadrata della media risultante.

RMS=sqrt[(1/N)*sum(xi)]

Non riesco a capire quel termine xi che sono i diversi valori assunti dal segnale come inserirli nella formula.

Cioè l'RMS è funzione del tempo e dipende dai valori precedentemente assunti?

Illuminatemi!

sossio89:
Cioè l'RMS è funzione del tempo e dipende dai valori precedentemente assunti?

La stessa definizione di rms dice come calcolarlo, è la radice della media dei quadrati, ovvero devi raccogliere un numero sufficienti di campioni, quanti dipende dalla frequenza di campionamento e da come varia il segnale, elevarli al quadrato, sommarli, farne la media ed estrarre la radice.
Esempio pratico, per semplicità ipotizziamo di avere 10 campioni di cui i primi quattro valgono 3, i due seguenti valgono 4, i seguenti sempre 3.
Prima fai la somma dei quadrati dei dieci valori:

9+9+9+9+16+16+9+9+9+9 = 104

Poi fa la media: 104/10 = 10.4 ed estrai la radice, sqr(10.4) = 3.225, questo è il tuo valore rms.
Tieni presente che Arduino, nelle versioni 8 bit, va subito in crisi con quadrati, divisioni con valori float e radici fatti in sequenza in questo modo, difficilmente riesci a calcolare più di 200-300 rms al secondo con serie di campioni non maggiori di 15-20 valori.

Questo che ti indico è la RMS nel dominio del tempo:

int Offset = 511;   // metà di 10 bit
unsigned long Somma = 0;
unsigned int N = 0;

...
<inizio loop>
int ValoreADC = analogRead(A0) - Offset   // valore tra 0 e 512 
N ++;
Somma += ValoreADC * ValoreADC;
<fine loop>

float RMSt = sqr(Somma / N);  // dominio del tempo

Per il dominio della frequenza devi operare in modo diverso (vedi teorema di Parseval).

Carica tutte le N letture ValoreADC in un array e di questo calcoli la FFT discreta per M valori.

Sommi tutti gli M valori elevati al quadrato e

float RMSf = sqr(SommaM2 / N / N); // dominio della frequenza

cyberhs:

int Offset = 511;   // metà di 10 bit

unsigned long Somma = 0;
unsigned int N = 0;

...

int ValoreADC = analogRead(A0) - Offset  // valore tra 0 e 512
N ++;
Somma += ValoreADC * ValoreADC;

float RMSt = sqr(Somma / N);  // dominio del tempo

inizio/fine loop che hai scritto intendi che devo inserire tutto all'interno del void loop?

int Offset = 511;   // metà di 10 bit
unsigned long Somma = 0;
unsigned int N = 0;

void setup() {
  
Serial.begin(9600);
}

void loop() {
int ValoreADC = analogRead(A0) - Offset;   // valore tra 0 e 512 
N ++;
Somma += ValoreADC * ValoreADC;
}

float RMSt = sqrt(Somma / N);

Questo è quello che ho scritto. Non mi da alcun problema. Solo che vorrei vedere i valori che mi tira fuori.

const int Offset = 511;   // metà di 10 bit
unsigned long Somma;
unsigned int n;
int ValoreADC;
float RMSt;

void setup() {
  Serial.begin(9600);
  Somma = 0;
  n = 0;
}

void loop() {
  ValoreADC = analogRead(A0) - Offset;   // valore tra 0 e 512
  n++;
  Somma += ValoreADC * ValoreADC;
  RMSt = sqrt(Somma / n);
  Serial.println(RMSt);
}

Funziona fino all'overflow di n (int) o di somma (unsigned long).... quello che viene prima. :slight_smile:

Nell'IDE 1.6.7 c'è la funzione di plotter seriale nel menù strumenti.

Ho indicato un generico che può essere un gruppo for oppure un while oppure ancora un do e comunque limitato nel numero di iterazioni N.

Quello di cui ti ho fatto un esempio è il calcolo della RMS nel dominio del tempo.

E' chiaro che se devi fare una prima una FFT discreta devi eseguire l'altro tipo di routine.

Grazie.

In teoria dopo un certo N di iterazioni il sistema si bloccherà giusto?

Allora appena potrò lo proverò con un accelerometro. Vi farò sapere.

Allora ragazzi sto usando un MMA

leggo i dati con codice:

#include <AcceleroMMA7361.h>
AcceleroMMA7361 accelero;
int x;
int y;
int z;

void setup()
{
  Serial.begin(9600);
  
  accelero.begin(13, 12, 11, 10, A0, A1, A2);
  accelero.setARefVoltage(5); //sets the AREF voltage to 3.3V
  accelero.setSensitivity(HIGH); //sets the sensitivity to +/-6G
  accelero.calibrate();
   
}
void loop()
{
  x = accelero.getXAccel();
  y = accelero.getYAccel();
  z = accelero.getZAccel();


Serial.print("\nx: ");
Serial.print(x);
Serial.print(" \ty: ");
Serial.print(y);
Serial.print(" \tz: ");
Serial.print(z);
Serial.print("\tG*10^-2");
 


delay(50); //make it readable
}

Come secondo voi posso realizzare un RMS del segnale che ottengo ad esempio lungo x?

Il codice da voi indicato lo modificherei nella parte loop nel seguente modo(dopo aver dichiarato opportunamente le variabili come voi stesso mi avete indicato):

void loop() {
  ValoreADC = analogRead(x) - Offset;   // valore tra 0 e 512
  n++;
  Somma += ValoreADC * ValoreADC;
  RMSt = sqrt(Somma / n);
  Serial.println(RMSt);

Giusto?

icio:
Significa solo che devi campionare il segnale con una frequenza sufficientemente alta da includere tutti i transitori in essa contenuti e poi fare la media aritmentica che altro non è che la media integrale del segnale in funzione al tempo

Non é la media geometrica che devi usare per ottenere il valore efficace?
Ciao Uwe

Cosa intendi per media geometrica?

rms di un segnale discreto si ottiene dalla formula che ho indicato precedentemente

PaoloP:

const int Offset = 511;   // metà di 10 bit

unsigned long Somma;
unsigned int n;
int ValoreADC;
float RMSt;

void setup() {
  Serial.begin(9600);
  Somma = 0;
  n = 0;
}

void loop() {
  ValoreADC = analogRead(A0) - Offset;  // valore tra 0 e 512
  n++;
  Somma += ValoreADC * ValoreADC;
  RMSt = sqrt(Somma / n);
  Serial.println(RMSt);
}




Funziona fino all'overflow di n (int) o di somma (unsigned long).... quello che viene prima. :) 

Nell'IDE 1.6.7 c'è la funzione di plotter seriale nel menù strumenti.

Ho provato questa formula. La quale è molto sensibile nei primi istanti di campionamento per poi avere un andamento decrescente convergente. Insensibile ad agni variazione della vibrazione.