Campionamento sinusoide 50Hz e RMS- problema sketch

Ciao a tutti
Ho un arduino UNO R3, sto cercando di misurare una corrente alternata 50Hz, rilevata tramite il sensore allegato.
Con i valori campionati voglio calcolare il valore efficacie nel periodo e farlo apparire a serial monitor.
Il sensore lavora correttamente, in allegato scope con oscilloscopio direttamente ai capi del sensore chiuso su resistenza di 100ohm ( il datasheet da i valori nominali su R=10ohm, ma con 100ohm o anche 1kohm si ottiene un segnale apprezzabile e comuqnue non distorto).
Dopo vari tentativi non fruttuosi sullo sketch, sono arrivato con questo sketch:

int voltmax=5; // i millivolt massimi leggibili sono 5 (o 3.3V)
int pin=0; //il sensore è collegato al pin 0
int number_of_samples=100;//campioni nel periodo
int K=5; //mV/A
int A=10; //amplificazoine R=10ohm-->R=100ohm
float inst_current;
float squared_current;
float sum_squared_current;
float sum_med_rms;
float mean_med_rms;
float mean_square_current;
float root_mean_square_current;

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

void loop() //
{
for (int j=0; j<5;j++) //prendo 5 periodi fatti ognuno di 100 campioni
{
while (analogRead(pin)>0)
{
for (int n=0; n<number_of_samples; n++) //campiono 100 valori sun mezzo periodo, faccio il quadrato e li sommo
{
inst_current=((analogRead(pin)*voltmax)/1023/K/A);
squared_current = inst_current * inst_current;
sum_squared_current += squared_current;
delayMicroseconds(100);
}
}
mean_square_current = sum_squared_current / number_of_samples; //calcolo la media della dei quadrati dei 100 campioni su mezzo periodo
root_mean_square_current = sqrt(mean_square_current); //faccio la radice della media -->valore efficacie dei primi 100 campioni
Serial.println(root_mean_square_current);

sum_med_rms += root_mean_square_current;//sommo i 5 rms dei 5 periodi

}
mean_med_rms=sum_med_rms/5; //medio i 5 rms dei 5 periodi
Serial.print('media-->');
Serial.println(mean_med_rms);
}

L’idea è sempre quella di avere 100 campioni a semiperiodo (per ora elimino i valori negativi, ho provato anche ad aggiungere 2,5Vcc con un AOP come da schema allegato, ma il segnale mi risulta disturbato)
Considerando i 16Mhz di arduino, ipotizzando un tempo HW di ritardo di analogread, mi sono fermato a campionare 100 campioni ogni 10ms, ovviamente solo i valori positivi.

Il problema è che ottengo questo a serial monitor:
0.00
0.00
0.00
0.00
0.00
115820.00
0.00
0.00
0.00
0.00
0.00
115820.00
0.00
0.00
0.00
0.00
0.00
115820.00
0.00
0.00
0.00
0.00
0.00
115820.00
0.00
0.00
0.00
0.00
0.00
115820.00
0.00
0.00
0.00
0.00
0.00
115820.00

Qui mi sono bloccato, dopo vari tentativi e ricerche in rete.
Qualche suggerimento su dove sto sbagliando?
grazie
PS: sto misurando la corrente assorbita da un phon, 1800W di potenza, la pinza amperomentrica esterna che ho attaccato misura 7.86 A

V2H2_100ohm.bmp (252 KB)

ECS1030-L72-SPEC.pdf (274 KB)

Ho appena affrontato il problema e vedo che in giro ci sono diverse correnti di pensiero.

Per avere RMS affidabili devi campionare all'interno di un un certo numero N intero di periodi e campionare in modo costante (tempo di campionamento il più breve possibile) e con una frequenza di campionamento di almeno 2 volte la frequenza del segnale (2x50=100) dal teorema di Nyquist.

L'ADC di Arduino campiona alla velocità massima di 9600 sample/s corrispondenti a circa 192 sample/periodo.

Il problema è che questo accade per letture continue, mentre nella realtà questo non accade poiché, ad esempio, ci sono le istruzioni di somma, per non parlare di eventuali interrupt.

Anziché leggere tot campioni (che potrebbero leggere, ad esempio, 1.3 periodi falsando la misura) conviene campionare (il più velocemente possibile) entro una finestra temporale di N periodi (ad esempio 2 periodi cioè 100ms).

Per ridurre il tempo di calcolo ti conviene convertire solo la somma finale ottenuta sommando i quadrati delle misure ripulite delle sola componente continua. Non sarebbe male inserire un filtro passa basso hardware con taglio a 4.8 kHz sulla linea ADC.

Ci sarebbe altro da dire, ma non posso andare oltre: il PowerMeter da me ideato fa parte di un progetto per un mio cliente.

Solo alcune note:

  • il phon introduce armoniche indesiderate nella sinusoide, sicuramente non ha un fattore di potenza unitario
  • cambiando il prescaler è possibile aumentare la frequenza dell'ADC, oltre certi valori si iniziano a perdere bit di risoluzione
  • è importante il filtro antialiasing
  • non andare troppo vicino alla frequenza di Nyquist, non esistono filtri antialiasing perfetti

Ciao

sicuri che usando analogRead si arrivi solo a 9600 campioni al secondo?
da dove arriva? prove sul campo?

edit: trovato questo:http://forum.arduino.cc/index.php/topic,99690.0.html

sicuri che usando analogRead si arrivi solo a 9600 campioni al secondo?
da dove arriva? prove sul campo?

Nei processori Atmel 8 bit il tempo di conversione ADC è 13 us (min) sino a 260 us (max) in free running mode.

Ho letto da qualche parte quel dato di circa 10kHz con Arduino (non ricordo dove), ma comunque sono confortato dalle mie "prove sul campo".

Considerando due letture nel ciclo (tensione e corrente), il tempo di un periodo (20ms) e relativi calcoli, i campioni sono stati 83 (sia per la corrente che per la tensione) usando un Arduino MEGA.

Poiché siamo un po' al di sotto della frequenza minima di campionamento, ho compensato con la scelta di N=2 periodi ed i risultati sono stati piuttosto buoni: non solo tensione e corrente precise ma anche il "famigerato" cosFi.

Sto sviluppando ora una versione dell'apparecchio usando un Arduino MICRO.

con tutto ottimizzato solo 83campioni?
vuol dire un periodo di 240us.
è necessario il real time? sennò si potrebbe fare acquisizione in un periodo e calcoli nel periodo successivo. 200 300 campioni in ram se a 8 bit stanno tranquilli col programma se non è una cosa astrusa

Io farei i calcoli mentre si aspetta l'ADC se il tempo basta, quando la lettura è ultimata un interrupt ADC_vect ci avvisa e si passa ad elaborare il nuovo dato, in questo modo si riducono i tempi morti e si migliora il numero di campioni elaborati al secondo.

In alternativa se si vogliono risultati migliori si passa ad un micro maggiormente veloce computazionalmente e nelle letture analogiche dell'ADC ]:smiley:

Ciao

il problema è che per far così bisogna mettere mano direttamente alla conversione a livello di registri.. non si può fare il classico analogRead :wink:

Vorrei completare parzialmente quanto detto prima.

Il prescaler dell'ADC in Arduino è stato fissato su 128 è di conseguenza il clock ADC vale 125kHz.

Il tempo normale di acquisizione della misura impiega 13+1.5 cicli corrispondenti a circa 8620 sample/s (e non 9600 come erroneamente affermato in precedenza).

Di conseguenza il numero massimo di campioni è 8620 / 50 = 172 sample/periodo.

E' possibile aumentare l'ADC clock a 250kHz usando un prescaler a 64. Purtroppo però si perde in precisione (cosa che nel nostro caso non è consigliabile).