Go Down

Topic: È "efficiente" questa funzione? (Read 1 time) previous topic - next topic

NeXTWay

Salve a tutti,
sto lavorando con un laser ed una fotoresistenza: un pin analogico prende la tensione in uscita da un partitore (5v--->resistenza--->pinAnalogico<---fotoresistenza--->terra) e se il valore scende troppo, esegue una funzione.
Per evitare "disturbi" sul pin analogico ho scritto una funzione che ritorna la media del valore preso dal pin nell'arco di tempo di un secondo.

Code: [Select]
//"Debounces" analog readings
int average(char analog){
  int value1 = analogRead(analog);
  delay(250);
  int value2 = analogRead(analog);
  delay(250);
  int value3 = analogRead(analog);
  delay(250);
  int value4 = analogRead(analog);
  delay(250);
  int value5 = analogRead(analog);
  //return 5/(1/value1 + 1/value2 + 1/value3 + 1/value4 + 1/value5);
  return (value1+value2+value3+value4+value5)/5;
}


Il "problema" è che dichiaro cinque (5!) interi e faccio oziare il processore per un secondo: volevo sapere se è possibile renderla più efficiente.
Ovviamente non intendo utilizzare un unsigned char (mi servono i valori da 0 a 1023).
Idee? (:

ratto93

non puoi mettere tutto il codice?
A me è molto poco chiaro e capire cosa stai chiedenso senza vederlo interamente è difficile :)
Se corri veloce come un fulmine, ti schianterai come un tuono.

Michele Menniti


non puoi mettere tutto il codice?
A me è molto poco chiaro e capire cosa stai chiedenso senza vederlo interamente è difficile :)

Ratto, quand'è che sei morto o diventato un sorcio ad alta tensione?  :smiley-mr-green:
Ciò che vuole l'ha scritto chiaramente: per migliorare la precisione di lettura si affida a cinque letture successive nell'arco di un secondo e ne fa la media. Poiché in questo modo impegna troppo e inutilmente la CPU vuole sapere se esiste un modo più snello per fare la stessa cosa, a che ti serve il resto del codice?  XD
Guida alla programmazione ISP e seriale dei micro ATMEL (Caricare bootloader e sketch):
http://www.michelemenniti.it/Arduino_burn_bootloader.php
Guida alla Programmazione ATmega328 noP:
http://www.michelemenniti.it/atmega328nop.html
Articoli su Elettronica In:
http://www.michelemenniti.it/elettronica_in.html

Federico

La domanda e' chiara, e la fregatura risiede nel "secondo" di attesa.
Potresti fare cosi: tramite la funzione millis() valuti il tempo attuale, scrivi un "if" che dice, se dall'ultima lettura sono passati 250ms allora effettua una lettura, e incrementi una variabile in questo modo fino a 5, le varie letture le sommi sulla stessa variabile. Se ad un certo punto questo tuo valore originario di millis() supera il secondo, effettui la divisione per 5 e ottieni il risultato.

Se hai proprio bisogno mi sbatto anche per il codice, ma e' quasi ora di cena :-)
Federico - Sideralis
Arduino &C: http://www.sideralis.org
Foto: http://blackman.amicofigo.com

ratto93

Non son morto e l'HT non la prendo dalla scorsa estate.... non son schiattato ma non voglio riprovare... sentir la 220v che circola libera nel corpo è una sensazione... come dire... ehm... strana :P 8)
sarà un vizio che mi ha trasmesso il vecchio prof di informatica...... ma voglio sempre vedere tutto integro e non a frammenti... non per farmi gli affari altrui ma per essere sicuro di ciò che dico e per imparare qualcosa di nuovo ;)
sono sempre alla ricerca di qualche strano modo per fa codice più snello e funzionale anche in questo caso :P

invece di usare i delay può usare millis senza così dover fermare il programma .... no ?
Federico mi hai fregato.....  8)
Se corri veloce come un fulmine, ti schianterai come un tuono.

superlol


La domanda e' chiara, e la fregatura risiede nel "secondo" di attesa.
Potresti fare cosi: tramite la funzione millis() valuti il tempo attuale, scrivi un "if" che dice, se dall'ultima lettura sono passati 250ms allora effettua una lettura, e incrementi una variabile in questo modo fino a 5, le varie letture le sommi sulla stessa variabile. Se ad un certo punto questo tuo valore originario di millis() supera il secondo, effettui la divisione per 5 e ottieni il risultato.

Se hai proprio bisogno mi sbatto anche per il codice, ma e' quasi ora di cena :-)

Code: [Select]

unsigned long last;

int a[5];
int indice = 0;
int delay = 250;

int valore;


nel tuo loop metti:
Code: [Select]

if(millis() >= last+delay) {
if(indice == 4) {
valore = (a[0]+a[1]+a[2]+a[3]+a[4])/5;
indice = 0;
}
a[indice] = analogRead(analog);
indice++;
}

dovrebbe andare, ogni secondo ti si aggiorna il valore  8)
Il nuovo forum italiano sull'elettronica: http://www.electroit.tk/ <--- Nuovamente online!

Federico

meglio di come me l'ero immaginato!
Federico - Sideralis
Arduino &C: http://www.sideralis.org
Foto: http://blackman.amicofigo.com

lesto

ancora meglio, se non ti serve conservare i singoli valori: (ah manca l'aggiornamento di last nel codice di superlol)

Code: [Select]

int somma=0;
int media=0;
int pausa = 250;

void setup(){
   //precalcolo la media
   for (int i=0;i<5;i++){
       somma+= analogRead(analog);
       delay(pausa);
   }
   media=somma/5;
}

void loop(){
  if(millis() >= last+pausa) {
     somma-=media;
     somma+= analogRead(analog);
     media=somma/5;
     last=millis();
  }
}


così hai un valore di media aggiornato ogni 250 ms, pena però 250*5 ms di attesa prima che parta il loop
sei nuovo? non sai da dove partire? leggi qui: http://playground.arduino.cc/Italiano/Newbie

NeXTWay







Grazie a tutti: non mi aspettavo tutte queste risposte (:
Per il codice ho preso quello di superlol, corretto un buggetto (si rifiutava di confrontare l'output di millis con la somma di last e delay), tradotte le variabili, aggiunto un return ed il suo nome al commento della funzione (se desideri che lo rimuova, lo cancello subito).
Grazie ancora :D

lesto

ricordati di aggiungere  last=millis(); altrimenti dopo la prima lettura, quelle successive avvengono come se non ci fosse delay!
sei nuovo? non sai da dove partire? leggi qui: http://playground.arduino.cc/Italiano/Newbie

superlol


ancora meglio, se non ti serve conservare i singoli valori:...
...

accidenti è vero  XD pardon  :smiley-roll-blue:


...
Per il codice ho preso quello di superlol, corretto un buggetto (si rifiutava di confrontare l'output di millis con la somma di last e delay), tradotte le variabili, aggiunto un return ed il suo nome al commento della funzione (se desideri che lo rimuova, lo cancello subito).
Grazie ancora :D


ancora meglio sarebbe fare una media dei valori a seguire, intendo fai la media in 250ms, poi arriva il terzo valore e fai la media tra la media dei primi 2 e lo medi col secondo, vai a vanti col terzo ecc.. però è relativo a come deve variare il sensore e che scopo ha.

comunque il mio nome puoi toglierlo perchè è una cavolatina e non voglio prendermi meriti per cose a cui neanche do troppo peso  :P
Il nuovo forum italiano sull'elettronica: http://www.electroit.tk/ <--- Nuovamente online!

leo72

Questo sistema ha un errore di base. Se per caso una lettura è atipica, ti sballa tutto il codice.
Mettiamo che tu legga:
50
55
800
60
45
La media è 202, assolutamente inesatta.
Potresti fare così: prendi 5 letture, dopodiché le metti in ordine e prendi quella nel mezzo.
Code: [Select]
int lettoreSensore() {
byte contatore;
int letture[4];
byte i,j;
int temporaneo;
    for (i=0; i<5; i++) {
        letture[i]=analogRead(sensore);
    }
    //bubble sort
    for (i=0; i<4; i++) {
        for (j=i+1; j<5; j++) {
            if (letture[i]>letture[j]) {
                temporaneo=letture[j];
                letture[j]=letture[i];
                letture[i]=temporaneo;
            }
        }
    }
    return (letture[2]);
}

In questo modo hai una specie di media ma, soprattutto, scarti valori assurdi.
La funzione, nel caso di prima, restituisce infatti 55, che è quasi la media vera di tutti i valori "normali" letti:
45+50+55+60=52,5

superlol

rimane da capire che sensore è ed in che campo deve lavorare, se è un sensore di temperatura è un conto, sui giri un'altro e cosa deve fare di conseguenza? secondo me è meglio sapere queste cose
Il nuovo forum italiano sull'elettronica: http://www.electroit.tk/ <--- Nuovamente online!

lesto


Questo sistema ha un errore di base. Se per caso una lettura è atipica, ti sballa tutto il codice.
Mettiamo che tu legga:
[...]


Il principio di funzionamento della media è proprio questo: normalizzare i dati.
Per intenderci, se metti i valori letti in un grafico avrai una specie di grafico molto altalenante (zoomando i particolari).
Più aumenti il numero di dati su cui effettuare la media ARITMETICA (perchè ne esistono altri tipi) più il grafico sarà curvilineo e "stabile" su di un valore.
Poi, oltre ai vari tipi di media, c'è la moda e la mediana (più o meno quello che suggerisci), ma quì ci stiamo buttando nella statistica... un'altra mia grossa lacuna :P
sei nuovo? non sai da dove partire? leggi qui: http://playground.arduino.cc/Italiano/Newbie

astrobeed


50
55
800
60
45
La media è 202, assolutamente inesatta.


Non funziona così, se uno dei valori letti è molto maggiore, o minore,  rispetto agli altri valori hai un problema con la modalità di acquisizione.
Mi spiego meglio se prevedi di fare la media di tot valori per compensare l'onnipresente rumore, che normalmente ha valore medio quasi 0, prendi questi campioni con una velocità pari a n volte (n = numero di campioni) di quella prevista dalla banda del sensore, altrimenti non ha senso farlo, se uno dei valori presi varia moltissimo vuol dire che hai problemi di transienti veloci dovuti a disturbi esterni oppure che stai campionando troppo lento rispetto alla velocità del segnale.
Se il problema è dovuto a sporadici transienti veloci si elimina facilmente verificando che ogni valore letto sia pari al valore medio precedente +/- la variazione massima possibile durante un singolo campionamento, se non è così il campione viene gettato e al suo posto inserito il valore medio precedente.

Go Up