Newsgroup: it.hobby.elettronica.digitale
Titolo: Calcolo della media senza usare tanta ram o occupare troppo il micro

Salve, vorrei avere il valore medio di un dato negli ultimi 10 minuti 
(circa).
Il dato viene campionato ogni 10ms.
Come fareste a eseguire il calcolo su un micro (in C) ?
L'algoritmo dovrebbe essere tale da occupare poca ram e non saturare le 
capacità di alcolo di un micro, deve fare anche tante altre cose :-)
garzie 
 
 


Io lo farei con code multiple.
Ad esmpio, ogni minuto salvi un valore che sarà la media di 60 valori
corrispondenti a 60 secondi.
Ogni secondo verrà effettuata la media di 100 valori (10 ms).
Con 170 valori si implementa, quindi, ma non è detto che per forza si
debbano usare code così "lunghe".
Poi, non occorre ogni volta risommare tutti gli elementi delle code:
basta sottrarre il valore più vecchio e sommare il nuovo alla vecchia
somma totale.
Credo che con tre code, comunque, risolvi la cosa.
Ovviamente, ogni coda circolare avrà due puntatori ed una variabile
somma.
Con i valori indicati puoi aggiornare la media ogni secondo.
 
Piccio.


Ti serve davvero la *media* degli ultimi 10 minuti (60.000 campioni)?
Oppure ti basta un passa-basso IIR?
 
y[n] = x[n] * b0 + y[n-1] * a1
 
 
Marco


Usa una media mobile.


Una vera media mobile richiederebbe una fifo da 60.000 celle, non direi 
che occupi poco RAM :-)
 
Se non gli serve veramente una media matematica, ma gli basta un filtro 
passa basso la soluzione di Marco è ottimale.
 
-- 
  _|/ Francesco Sacchi - Develer S.r.l.
   |\
http://www.develer.com/
 - 
http://www.bertos.org/
 


perche? basta sommare al valore precedente il valore
acquisito nel ciclo a 10ms.
Poi si divide subito per 2 o si tiene un contatore di
punti da usare per effettuare la divisione su n campioni
quando si raggiunge una soglia inferiore al valore di
saturazione dell' accumulatore usato.
Al massimo di usa una variabile per l' accumulatore
e una per il contatore di punti.
 
A.
 

 Poi si divide subito per 2 
 
Perché non coincidono. Magari all'OP va bene come compromesso ma come 
hanno già suggerito è da valutare.

 hanno già suggerito è da valutare.
why?
Se fa la media 'mobile' sul tempo di campionamento che
gli serve, avra' esattamente la media aritmetica dei campioni
(60000), se non vuole trascinarsi il primo valore dopo il primo
loop, puo' azzerare ogni volta l' accumulatore...
A.
 
 


Perché gli esempi che hai indicato *non* sono esempi di implementazione 
di una media mobile propriamente detta. Per ottenere la media mobile di 
60.000 campioni, ad ogni nuovo campione in ingresso devi buttare via il 
più vecchio, e quindi ti devi tenere tutta la storia passata. Ad ogni 
nuovo campione in ingresso viene calcolato un nuovo valore di media.
 
Negli esempi che hai citato, il primo è un filtro IIR; il secondo è una 
media a blocchi di 60.000 campioni (ovvero produce un nuovo valore di 
media ogni 10 minuti e non ogni 10 ms, credo che la differenza sia 
evidente :-) )
 
L'OP ha chiesto un algoritmo di media mobile, che vuol dire una cosa ben 
precisa. Può darsi però che la necessità sia solo di smussare un po' i 
dati, e allora andrebbe benissimo un semplice IIR come quello che hai 
indicato tu.


 indicato tu.
 
Grazie a Francesco e a tutti per le cortesi risposte.
Effettivamente il filtro IIR può forse andare bene, devo però quantificare 
l'errore rispetto alla media calcolata correttamente per chiedere se può 
andar bene.
Sinceramente pensavo fosse un problema più semplice da risolvere :-(
Ho provato qualche soluzione con vettori ma il micro viene occupato troppo!
Mi chiedo: ma non ci sono dei micro con delle periferiche hardware che fanno 
gia ste cose? Mi sembra assurdo consumare il 20% della base tempi (tempo 
ciclo) del micro per fare la media di un dato .. boh .. sto pensando ad un 
buffer di N byte che gestisca da solo il meccanismo FIFO che appena gli 
mando un dato mi trovo la media in uscita, da caricare con dma da agganciare 
all'ad converter e via ...
 
 

 all'ad converter e via ...
 
 
Le risposte possono essere corrette, è la domanda che è sbagliata :)
 
Puoi spiegare a cosa ti serve la media di 60k campioni? Che cosa 
acquisisci e cosa ci devi fare?
 
Ciao!
Marco
 


Un modo molto brutale che assomiglia al filtro passa-basso di Marco è fare:
 
y[n] = ( x[n] + y[n-1] ) / 2
 
cioè la media tra il valore attuale e quello calcolato in precedenza.
Il problema del sistema è che la frequenza di taglio del filtro dipende dal 
periodo di campionamento.
 
Oppure, della serie "soluzioni un tanto al quintale" potresti pensar di 
sommare la lettura attuale ad un accumulatore (opportunamente grande), al 
decimo minuto dividere per 60000, estrarre il dato e azzerare 
l'accumulatore. Questa è una media *vera* però devi calcolare bene che 
accumulatore ti serve (es. per letture a 16 bit è sufficiente un intero 
senza segno a 32 bit). Se nella divisione non perdi informazioni in questo 
modo aumenti drasticamente i bit effettivi della misura. Se la lettura è 
affetta da calibrazione e/o cambi scala nessuno ti impedisce di applicarli 
alla media calcolata. Ogni 10ms devi solo fare una somma, e al decimo minuto 
una divisione intera.
 
Ciao
CG 
 
 

 troppo!
 
Leggiti la mia.... :)
 
Ciao
CG 
 
 

 indicato tu.
Non mi pare proprio che abbia chiesto questo!
solo il valore medio di 10minuti ottenuto con campioni
a 10ms :-)
Tra l'altro la media mobile puo' essere calcolata in parecchi modi
- media mobile semplice, ponderata, adattaiva, esponenziale etc.....
 
A.
 
 

 oppure o capito male ???
 
 
Infatti: negli *ultimi* 10 minuti. E ogni 10 ms gli ultimi 10 minuti 
cambiano.
 
Marco
 

 a 10ms :-)
 
Non mi supercazzolare, su i ng i post rimangono scritti, e basta 
leggerli per vedere che non è come dici :-)


 Non mi supercazzolare, 
 
-Scusi infermiera, prematurato il logaritmo binario o scherziamo?-


In realtà mi sa che ho preso una grossa cantonata, perché rileggendo il 
post originale non c'è nessun riferimento diretto alla "media mobile".
 
Eppure ero straconvintissimo di averlo letto. Mah, mi sa che sto 
diventando vecchio...


 all'ad converter e via ...
 
A parte l'occupazione di RAM, non vedo particolari problemi di
calcolo.
Il FIFO lo gestisci con due puntatori e la media la calcoli sommando
al valore della sommatoria il dato nuovo che entra e sottraendo il
dato
vecchio che esce. Poi dividi per il numero di campioni e ottieni la
tua
media mobile. Un micro decente impieghera' qualche decina di us in
tutto.

 cambiano.
 
Questa è bella :)
 
Comunque continuo a ripetere che il metodo migliore è creare un accumulatore 
e ogni 10ms sommarci la lettura.
Al decimo minuto dividere per 60000, estrarre il valore, azzerare 
l'accumulatore e ripartire.
Media aritmetica semplice: spendi poco e godi molto :)
 
Se la lettura son 2 byte, con 60 mila campioni basta un accumulatore da 4 
byte e praticamente ZERO risorse
 
Ciao
CG 
 
 

 può fare se non hai una fifo di questa lunghezza.
  :-)
Non e' cosi',perche' fare la media dei campioni man mano che
arrivano e fare la media di n campioni alla fine e' esattamente
la stessa cosa (se ti serve solo il valore finale).. a parte le
approssimazioni introdotte dalla divisione ad interi.
Non e' necessario avere una fifo di 60000 o 100000 campioni,
basta un accumulatore in cui si sommano i campioni desiderati
posto che sia adeguatamente dimensionato ...
E' matematica elementare :-)
A.
 

 l'accumulatore e ripartire.
 
 
Siamo d'accordo, ma sono due calcoli differenti.
Non sapendo che deve fare vanno bene tutti!
 
Marco
 

 Non sapendo che deve fare vanno bene tutti!
 
Mi puzza molto di roba tipo temperature da campionare velocemente per avere 
un buon campione ogni secondo (x esempio) ma anche evidenziare la 
temperatura media in un periodo piů lungo.
 
La cosa che mi sembra strana č come mai il valore viene campionato ogni 
10ms, cioč con banda passante di 50Hz !
 
Ciao
CG 
 
 

 10ms, cioè con banda passante di 50Hz !
 
Dirotto il thread, che ho seguito con interesse perche' ho realizzato un 
termometro interrogabile via cellulare. Ho risolto il problema 
dell'eccessiva sensibilita' dei DS18B20 mettendo un opportuno 
dissipatore (senza contare il calore prodotto durante la conversione, 
soprattutto se alla massima risoluzione), ma avrei volentieri usato un 
algoritmo di media mobile (con finestra temporale che trasla nel tempo). 
Algoritmo non implementato perche' e' stata anticipata la "spedizione" 
per l'installazione del termometro :-)
 
I miei campionamenti sono ogni 30 secondi, quindi con banda passante di 
0,016 Hz.
 
*Domanda*: perche' ti sembra strana una banda di 50 Hz su un sensore di 
temperatura?
 
PaoloC

 posto che sia adeguatamente dimensionato ...
 
Se vuoi solo un risultato sì, ma mi sembra che si stia parlando di due 
scenari diversi.
 
Tu proponi di campionare dieci minuti ed avere poi il valore della 
media. In questo caso un accumulatore è sicuramente sufficiente.
 
Quello di cui parlava Francesco Sacchi invece era campionare i primi 
dieci minuti e poi ogni 10 ms produrre la media dei 10 minuti 
precedenti. Qui c'è bisogno di un buffer lungo, se si vuole la media 
esatta.

 esatta.
Be, non erano indicati requisiti particolari, salvo l' economia
di gestione memoria e di calcoli :-)
BTW, per avere una media di 10minuti scartando poi il valore
piu' vecchio (sample a 10ms), basta tenersi il valore piu' vecchio
da sottrare alla media corrente: non e' necessario tenersi
un buffer da ricalcolarsi tutte le volte...specie con risorse
limitate (Ammesso che lo scarto di un punto su 60000 abbia senso).
Lavorando con aritmetica ad interi, per evitare di perdere
risoluzione, si puo' applicare un adeguato fattore moltiplicativo.
A.
 
 

 temperatura?
 
Perchč č superiore di un bel po' dell'inerzia termica di qualsiasi sensore o 
sistema che conosca!
Puň aver senso, a mio parere, andare cosě veloci per poter fare tante medie 
e aumentare la risoluzione (ogni 2^n o 2^n+1 medie, non ricordo, si aumenta 
di un bit effettivo la risoluzione)
 
 
Ciao
CG 
 
 

 60000 abbia senso).
 
Credo anche io che abbia poco senso, ma era per parlarne dal punto di 
vista teorico.

 
 
segni la media attuale e il numero di campioni. Quando arriva un nuovo dato  
rimoltiplichi la media per il numero di campioni, aggiungi l'ultimo e 
dividi per il numero di campioni + 1. aggiorni entrambi i dati e li tieni 
fino al prossimo dato in entrata.
 
Puoi fare lo stesso anche se invece di "ogni campione" aggiorni i dati 
precedenti ogni X campioni, con i dovuti accorgimenti.
 
-- 
"Non è mai troppo tardi per imparare a suonare..."
"Sì bhè, magari alle 3 di notte evita."

 
 
noto perň che potresti avere problemi di overflow a calcolarti la 
somma...puoi aggirare il problema dividendo il dato in entrata per n+1 
(dove n rappresnta il numero di campioni arrivati fino a quell'istante) e 
aggiungerlo alla media precedente.
la ram richiesta č nell'ordine di qualche byte, quelli necessari a tenere i 
dati in memoria
 
-- 
"Non č mai troppo tardi per imparare a suonare..."
"Sě bhč, magari alle 3 di notte evita."

 
 
se ho capito ciò che intendi questa non è una media.
Se hai 5 campioni, esempio 1 2 3 4 5, e fai la media viene
somma[campioni] / numero campioni = 15 / 5 = 3
se arriva un altro campione, diciamo 6 e fai
3 + 6 / 2 la media ti risulta 4.5 mentre in realtà dovrebbe essere 3.5
 
-- 
"Non è mai troppo tardi per imparare a suonare..."
"Sì bhè, magari alle 3 di notte evita."

 3 + 6 / 2 la media ti risulta 4.5 mentre in realtą dovrebbe essere 3.5
 
Infatti assomiglia molto di pił ad un filtro passa-basso.
 
Ho perņ specificato che se serve la media aritmetica ogni 10 minuti, il 
miglior modo a mio parere e con meno dispendio di risorse č:
 
1) allocare un accumulatore, grande almeno    2^(n. bit ADC) * numero 
campioni da accumulare. Es. con i campioni a 16 bit e 60000 campioni č 
sufficiente un accumulatore che possa visualizzare  65536*60000 = 3932160000 
quindi 31.87 bit (es. unsigned long di 32 bit)
2) azzerare l'accumulatore
3) sommare ogni campione all'accumulatore
4) al campione 60000 dividere l'accumulatore per 60000
5) ripetere dal punto 2
 
Cosģ si ottiene la media nei 10 minuti precedenti. Non č tenuto di conto, 
nella media successiva, del valore precedentemente calcolato.
Una media mobile sarebbe molto pił accurata ma dispendiosa, in quanto i 60 
mila campioni vanno tenuti in un registro a scorrimento
 
Ciao
CG