Newsgroup: it.comp.lang.c
Titolo: calcolo della media

Salve a tutti, sto cercando delle funzioni in C da cui trarre spunto per il 
calcolo della media di un numero elevato di campioni.
 
Dettaglio:
Ho una dato che viene campionato ogni 10ms.
Vorrei fare una media di 10 campioni e avere quindi la media degli ultimo 
100ms.
Poi su un vettore metterei 10 campioni da 100ms, e ogni volta che metto un 
dato dentro calcolo la media dei dati del vettore ed ho la media dell'ultimo 
secondo.
E cosě via ...
 
Non č che sia una cosa complicata, solo che magari essendo una cosa di 
utilizzo comune, potrebbe esserci in rete un algoritmo ottimizzato a cui non 
ho pensato.
Grazie 
 
 

aggiungo un dettaglio che forse è importante far notare:
non posso permettermi di consumare troppa ram per avere la media, 
l'applicazione è rivolta al mondo embedded (microcontrollori)
 
Devo avere la media negli ultimi 10 minuti di un dato che leggo ogni 10ms
 
 


La media è definita SommaValori/NumeroDati.
Se vuoi aggiungere un valore alla media, basta fare:
(MediaPrecedente*(NumeroDati-1)+NuovoValore)/NumeroDati
Quindi per avere una "running average" non c'è bisogno di memorizzare altro che la media corrente e il numero di campioni.
Ciao!

 che la media corrente e il numero di campioni.
 
No, è una approssimazione. Ad esempio calcolando la media su tre 
campioni per la sequenza "1 1 10 109":
 
media(1, 1, 10) = (1 + 1 + 10) / 4
media(1, 10, 109) = (1 + 10 + 109) / 3 = 40
media_campioni_precedenti(1, 10, 109) = (4 * (3 - 1) + 109) / 3 = 39


Certamente: supponevo che la decisione di prendere solo N campioni fosse solo per risparmiare memoria. Se bisogna farla *esattamente* su N campioni ovviamente è necessario averli tutti in memoria :-) Anche in quel caso la soluzione è semplice; un vettore largo N sul quale si fa la media più un indice che punta all'ultimo campione inserito e torna a zero quando arriva a N.
Ciao!
 
P.S. Per rispondere ho utilizzato google groups, sperando che nel frattempo abbiano sistemato i noti problemi: se non fosse così mi scuso fin da subito, per favore fatemi sapere che in caso cerco alternative (visto che non trovo più il modo per tornare alla vecchia versione..)

 Certamente: supponevo che la decisione di prendere solo N campioni fosse solo per risparmiare memoria. Se bisogna farla *esattamente* su N campioni ovviamente è necessario averli tutti in memoria :-) Anche in quel caso la soluzione è semplice; un vettore largo N sul quale si fa la media più un indice che punta all'ultimo campione inserito e torna a zero quando arriva a N.
 
Inoltre non occorre nemmeno scorrersi tutti gli N elementi, la media si calcola con una semplice formula:
 
media = media + (nuovo - vecchio) / N
 
dove nuovo e' il valore appena letto e vecchio e' il valore piu' vecchio nel buffer che verra' eliminato.
 
ciao
Giacomo
 
 

Vi ringrazio delle risposte!
Purtroppo non ho sufficente memoria per N campioni, potrebbe essere 
accettabile usare la formula suggerita:
Media = (MediaPrecedente*(NumeroDati-1)+NuovoValore)/NumeroDati
Sarei perň curioso di capire... si puň quantificare l'errore della media 
cosě calcolata?
 
grazie 
 
 

 grazie
 
Uhm... con la deviazione standard? :-)
Se la tua situazione è così disperata da non poter memorizzare pochi campioni, forse ti conviene usare un approccio meno informatico e più pratico, come loggare un numero sufficiente di dati, effettuare un'analisi non run-time e stabilire il margine d'errore medio...
M2C
Ciao!

 E così via ...
 
Stai parlando di una media aritmetica "pesante" nel mondo dei 
microcontrollori.  Scommetto che stai acquisendo una tensione analogica 
con un ADC integrato nel microcontrollore, ottieni dei valori troppo 
"rumorosi" e la media ti sembra l'unica via d'uscita per poter avere un 
valore sufficientemente stabile a video.
 
Prima di affrontare il problema in digitale (con filtri numerici), sei 
sicuro di non avere problemi nella sezione analogica?
Il reference dell'ADC è sufficientemente stabile?  E' ricavato 
dall'alimentazione, oppure hai proprio un reference di tensione?  Se è 
ricavato direttamente dall'alimentazione, l'hai disaccoppiato con una 
buona ferrite per evitare che i disturbi sull'alimentazione digitale 
passino come disturbi nella sezione analogica e producano errori di 
conversione?  Hai inserito correttamente condensatori di 
disaccoppiamento sul reference e sulle alimentazioni?  Potresti anche 
pensare di avere una massa analogica separata da quella digitale con una 
ferrite per separare meglio i disturbi.
 
Tornando alla sezione digitale. In funzione dell'applicazione potresti 
pensare di campionare ogni 1ms e accumulare 10 campioni in una 
variabile. Alla fine dovresti semplicemente dividere per 10 e poi 
ricominci da capo.  Avresti sempre un campione ogni 10ms già filtrato e 
senza la necessità di memorizzare 10 campioni... naturalmente non è la 
stessa cosa di una media aritmetica mobile.
 
Altro suggerimento: sicuro che devi lavorare con il numero 10?  Perchè 
non fai la media su 8 o su 16 campioni?  In questo modo la divisione è 
decisamente più veloce (e su micro dove non riesci ad allocare 10 
campioni, molto probabilmente non hai una divisione hw).
 
Altra possibilità è quella di passare da un semplice filtro IIR, anche 
del primo ordine.  Con meno campioni, riesci ad avere un filtraggio 
migliore alle basse frequenze.
 
Infine, in funzione dell'applicazione e dei disturbi che vuoi filtrare, 
potresti pensare ad un filtro mediano, diverso dalla media.
 
http://embeddedgurus.com/stack-overflow/2010/10/median-filtering/