Stabilizzare misura temperatura - DS18B20

Ciao a tutti

Sto misurando la temperatura esterna di casa con una sonda DS18b20 collegata ad un WEMOS d1 Mini.
Leggo la temperatura ogni 30 secondi e la invio all app Blynk.

La sonda è collegata al +3.3V . GND e al pin D1 con la resistenza da 4.7K. Allego schema.

Il "problema" è che la temperatura non è stabile stabile, ovvero oscilla di 0,2/0,3 gradi ogni volta.
Io vorrei renderla il più stabile possibile. Allego grafico.

Qual'è il modo migliore per mediare il dato in modo da stabilizzarlo il più possibile ?

Grazie

collegamento.jpg

Per il Maxim DS18B20+ leggo nelle specifiche che ha una precisione di ±0.5°C quindi si, mi pare normale.

Per mediare è abbastanza banale, somma un certo numero di letture consecutive (es. 10 intervallate di qualche decimo di secondo) ed il totale lo dividi per il numero di letture (quindi valore = tot/10), poi il risultato in centigradi visto che ha una precisione di mezzo grado lo puoi approssimare al semi-intero (es. valore = int(valore2)/2) o e preferisci almeno al primo decimale (es. valore = int(valore10)/10).

Parto col dire che la sonda è digitale quindi l'alimentazione in questo caso ci incastra poco.
Essendo una temperatura esterna ambientale una grandezza che non è che varia con una velocità rapida io ti consiglio di fare quel che ho fatto io :slight_smile: ovvero:

  • Abbassa la precisione da 12 a 10 bit impiega meno tempo a leggerla e credo che 0,25°C di precisione siano più che accettabili per una tenperatura esterna
  • Esegui più letture e fai una media

Ci sono varie scuole di pensiero su come sia meglio trattare questi dati, io seguo questa logica, effettuo 12 letture e metto i valori in un array, scarto la massima e la minima rilevata prestando attenzione che non coincidano, ovvero l'indicce della temperatura massima non deve essere uguale all'indice della temperatura minima da scartare. faccio la somma degli altri dieci valori restanti e divido per dieci il risultato.

fabpolli

Interessante !

Come si fa ad abbassare la precisione ?

Non avendolo tu indicato io suppogo tu stia utilizzando la libreria DallasTemperature nella quale c'è il metodo setResolution, se guardi tra gli esempi c'è WaitForConversion2 che ne fa uso

Si scusa, uso la Dallas. Ok guardo !

Mentre per arrotondare ad una sola cifra decimale il valore letto, basta fare

valore = sensors.getTempCByIndex(0);

temperatura = (valore,1)

?

fabpolli:
Ci sono varie scuole di pensiero su come sia meglio trattare questi dati, io seguo questa logica, effettuo 12 letture e metto i valori in un array, scarto la massima e la minima rilevata prestando attenzione che non coincidano, ovvero l'indicce della temperatura massima non deve essere uguale all'indice della temperatura minima da scartare. faccio la somma degli altri dieci valori restanti e divido per dieci il risultato.

fammi capire, solo per curiosità:
il principio di scartare massima e minima lo ritengo valido, su un numero abbastanza grade di letture scartarne due non influisce molto sulla precisione della media, ma garantisce di eliminare eventuali errori casuali (che sarebbero molto diversi dalle altre misure)
se la temperatura massima coincide con la temperatura minima significa che tutte le letture sono tra loro uguali
e quindi scartarne due tra loro uguali non cambia di uno Jota la media
ammennocche tu non lo usi come indice che lo strumento si è "bloccato"

dimare_gabriele:
Si scusa, uso la Dallas. Ok guardo !

Mentre per arrotondare ad una sola cifra decimale il valore letto, basta fare

no

temperatura =(temperatura/10)*10;

ammesso che sia temperatura sia intera
altrimenti

temperatura =((int)temperatura/10)*10;

Standardoil:
fammi capire, solo per curiosità:

Lo scopo è quello di eliminare eventuali letture anomale.
La precisazione che gli indici non siano uguali deriva da una cappellata che feci una volta, scansione dell'array per determinare l'indice dell'array per il valore minimo e massimo con relativo salvataggio in due variabili appoggio.
Successiva scansione del solito array con somma e divisione per 10 per tutti gli indici differenti dall'indice del massimo e del minimo, se (come da te indicato) le temperature lette sono identiche e l'indici memorizzato in emtrambe le variabili è il medesimo sommi undici valori e dividi per dieci :frowning:
Ovvio che puoi anche scartare solo un indice per temperature identiche ma devi saperlo e dividere per 11, ma io ho preferito scartarne comunque due.
Faccio letture ben più distanti dei trenta secondi, una al minuto per la precisione, e ottengo cinque letture all'ora che per farmi sapere da dentro casa che temperatura c'è fuori è molto più che sufficiente (per me) e in questo modo ho notato che il dato rilevato all'ombra, a nord, non è influenzato negativamente da folate di vento improvvise o eventi transitori.
Sta viaggiando allegramente da più di un anno e il riscontro con altri termometri commerciali evidenzia una certa precisione ed affidabilità del dato

La sonda è molto piccola e di plastica, quindi reagisce rapidamente alle variazioni di temperatura. Il vento proveniente da un lato o dall'altro può avere temperature leggermente differenti. Per vedere se è un difetto della sonda oppure sta leggendo vere variazioni di temperatura, puoi fare due cose:

  1. Mettila dentro casa, in un posto tranquillo, e vedi se il valore letto è costante
  2. Mettila in una piccola scatola (di metallo, plastica, cartone...) e vedi se la temperatura rimane costante a breve termine.

Standardoil:
temperatura=((int)temperatura/10)*10;

Per fare una vera approssimazione, non solo in difetto, bisogna prima aggiungere 0,5:

temperatura=(int((temperatura*10)+0.5)/10.0;

scusate, mi potete spiegare questa funzione che non la capisco ?

temperatura=(int(temperatura+0.5)/10)*10;

Comunque la sonda è quella interna al cappuccio di metallo, come in foto

Il "+0,5" serve per ottenere una approssimazione in difetto o in eccesso a seconda che la parte decimale del valore sia minore o maggiore di 0,5.

Non esattamente....

Se assumiamo che "temperatura" sia almeno float (visto che parliamo di decimi di temperatura) questa istruzione è tutta sbagliata..

temperatura=((int)temperatura/10)*10;

Intanto perché viene prima eseguito il cast a int della variabile "temperatura" e poi diviso per 10, quindi moltiplicato per 10. Pertanto approssima erroneamente ai 10 gradi inferiori (es. se ho 13.65 mi resituisce 10)!!!

Per approssimare ad un decimale bisogna fare il contrario, prima moltiplicare per 10, prendere la parte intera, e poi dividere per 10, in ogni caso forzando una divisione float (10.0):

temperatura=(int)(temperatura*10)/10.0;

L'approssimazione al mezzo grado inferiore si fa semplicemente con:

temperatura=(int)(temperatura*2)/2.0;

per una approssimazione al mezzo grado più vicino:

temperatura=(int)(temperatura*2+1)/2.0;

Sono andato a correggere solo un particolare che mi è saltato all'occhio senza notare il resto... E sì che ne ho fatte, eh! :slight_smile:
Ho corretto il messaggio precedente per come ho fatto io quando mi è servito.

ma se io volessi semplicemente un valore con un decimale dopo la virgola, senza approssimare o arrotondare, ma un semplice taglio come devo fare ?

Devi moltiplicare per 10, fare l'intero e dividere per 10.

dimare_gabriele:
ma se io volessi semplicemente un valore con un decimale dopo la virgola, senza approssimare o arrotondare, ma un semplice taglio come devo fare ?

Scusa, ma leggi il mio post #10 (ma li leggi i messaggi?) dove ti ho dato tre alternative, con il codice esatto...

ok scusami !!

mi ero perso..

temperatura=(int)(temperatura*10)/10.0;

grazie

dimare_gabriele:
mi ero perso..

Ok! :slight_smile: