Carissimi,
è tanto che non scrivo... con l'occasione di chiedere il vostro aiuto per risolvere il problemino che vi sottopongo, auguro a tutti delle splendide feste !
Ho creato una piccola centralina per un amico che ha alcune piante di Kiwi e deve essere avvisato se la temperatura scende sotto i 2 gradi.
Nonostante io esegua 15 letture ad 1 secondo di distanza l'una dall'altra e nonostante abbia inventato una soluzione che elimini ogni lettura che abbia uno scarto di +- 3 gradi rispetto alla media delle 15 letture... ho, una volta ogni 2-3 ore circa, un errore (in eccesso o in difetto) che fa scattare l'allarme senza "motivo".
In pratica, e lo potete vedere subito col grafico che vi mostro, ogni tanto "impazzisce" e segna un valore (può durare perfino 1 minuto) che mi fa sballare il sistema e lo induce in errore.
A prescindere dal codice (che spero di poter scrivere abbastanza tranquillamente) vi viene un'idea del perchè ottengo queste anomalie e come poterle by-passare da un punto di vista logico?
Ho pensato di "eliminare" oltre alle singole letture anomale (di ogni secondo) che formano la media (di 15 secondi), addirittura le stesse medie anomale che si discostano di più del 20% dalla media precedente, ma anche così (se l'anomalia dovesse durare qualche minuto) non risolverei.
Allora potrei "allungare ad un tempo di diversi minuti tutto il sistema", ossia leggere ogni minuto per 15 minuti, ma così la "reattività" sarebbe elefantiaca.
Ogni idea è ben accetta.
Grazie
PS Sonda DS1820
Bisognerebbe vedere il programma e come hai collegato la sonda...
DATman grazie della risposta.
Il programma "gira" per Blynk ed in questo momento è relativo.
La sonda è una banale DS 1820 di cui ti mostro lo schema.
Come ho spiegato il problema non è che il listato non funziona, anzi funziona perfettamente; solo che ogni tot ore (una volta 2 ore, un'altra 6 ore) ha un malfunzionamento (potrebbe perfino essere di natura elettrica i.e. sbalzo di tensione) che crea questa problematica.
Io avrei bisogno di una mano per "correggerla" da un punto di vista "logico".
Allungo i tempi o creo una correzione percentuale sulla media precedente?
Con il Dallas 18B20, tipicamente quando fallisce una lettura si ottiene un valore di -127
Se non ne stai tenendo debitamente conto e lo aggiungi alla tua media, ti ritrovi con dei dati che non sono coerenti e quindi la media ti viene "sballata".
Grazie cotestant.
Il "core" del codice è questo (perdonate l'uso del delay, ma non deve fare altro e l'ho scritto di fretta).
In quale caso capita che "fallisca una lettura" col DS 18B20?
In che senso dici "Se non ne stai tenendo debitamente conto e lo aggiungi alla media"?
void letture()
{
sensors.requestTemperatures();
t1=sensors.getTempCByIndex(0);
delay(1000);
sensors.requestTemperatures();
t2=sensors.getTempCByIndex(0);
delay(1000);
sensors.requestTemperatures();
t3=sensors.getTempCByIndex(0);
delay(1000);
sensors.requestTemperatures();
t4=sensors.getTempCByIndex(0);
delay(1000);
sensors.requestTemperatures();
t5=sensors.getTempCByIndex(0);
delay(1000);
sensors.requestTemperatures();
t6=sensors.getTempCByIndex(0);
delay(1000);
sensors.requestTemperatures();
t7=sensors.getTempCByIndex(0);
delay(1000);
sensors.requestTemperatures();
t8=sensors.getTempCByIndex(0);
delay(1000);
sensors.requestTemperatures();
t9=sensors.getTempCByIndex(0);
delay(1000);
sensors.requestTemperatures();
t10=sensors.getTempCByIndex(0);
delay(1000);
sensors.requestTemperatures();
t11=sensors.getTempCByIndex(0);
delay(1000);
sensors.requestTemperatures();
t12=sensors.getTempCByIndex(0);
delay(1000);
sensors.requestTemperatures();
t13=sensors.getTempCByIndex(0);
delay(1000);
sensors.requestTemperatures();
t14=sensors.getTempCByIndex(0);
delay(1000);
sensors.requestTemperatures();
t15=sensors.getTempCByIndex(0);
delay(1000);
t_parz=(t1+t2+t3+t4+t5+t6+t7+t8+t9+t10+t11+t12+t13+t14+t15)/15;
if (t1 < (t_parz - scarto) || t1 > (t_parz + scarto)) { t1=t_parz; }
if (t2 < (t_parz - scarto) || t2 > (t_parz + scarto)) { t2=t_parz; }
if (t3 < (t_parz - scarto) || t3 > (t_parz + scarto)) { t3=t_parz; }
if (t4 < (t_parz - scarto) || t4 > (t_parz + scarto)) { t4=t_parz; }
if (t5 < (t_parz - scarto) || t5 > (t_parz + scarto)) { t5=t_parz; }
if (t6 < (t_parz - scarto) || t6 > (t_parz + scarto)) { t6=t_parz; }
if (t7 < (t_parz - scarto) || t7 > (t_parz + scarto)) { t7=t_parz; }
if (t8 < (t_parz - scarto) || t8 > (t_parz + scarto)) { t8=t_parz; }
if (t9 < (t_parz - scarto) || t9 > (t_parz + scarto)) { t9=t_parz; }
if (t10 < (t_parz - scarto) || t10 > (t_parz + scarto)) { t10=t_parz; }
if (t11 < (t_parz - scarto) || t11 > (t_parz + scarto)) { t11=t_parz; }
if (t12 < (t_parz - scarto) || t12 > (t_parz + scarto)) { t12=t_parz; }
if (t13 < (t_parz - scarto) || t13 > (t_parz + scarto)) { t13=t_parz; }
if (t14 < (t_parz - scarto) || t14 > (t_parz + scarto)) { t14=t_parz; }
if (t15 < (t_parz - scarto) || t15 > (t_parz + scarto)) { t15=t_parz; }
t=(t1+t2+t3+t4+t5+t6+t7+t8+t9+t10+t11+t12+t13+t14+t15)/15;
Blynk.virtualWrite(V2, t);
}
Senza offesa però mi sembra un gran bel pasticcio...
Non potevi semplicemente usare un array e fare un ciclo for?
Vabbè, algoritmo a parte, il problema è che l'istruzione sensors.getTempCByIndex(0) può saltuariamente restituire un valore pari a -127
È un fatto ben noto e siccome che anche con tutti gli accorgimenti elettrici/elettronici può ancora accadere, la cosa piu semplice è gestire questa eventualità via software e scartare il valore -127
Con un algoritmo del genere è un bagno di sangue perché dovresti inserire un if prima di assegnare il valore alle variabili t1-t15 ragione per cui ti consiglio di implementare la cosa in modo più efficiente.
Nessuna offesa figurati!
So bene che si dovrebbe programmare in modo stringato.
In questo caso credo che non ci sia nessun "pasticcio"... è solo molto più prolisso.
Se sei d'accordo concentriamoci sulla sostanza e non sulla forma (anche se, come giustamente dici, dovrebbe avere la dovuta attenzione).
Quello che non mi torna nel tuo discorso è che lo spike avviene quasi sempre verso l'alto.
Nel grafico che vi ho mostrato passa da una placida media di 3.8 a 9.5... il valore -127 non dovrebbe produrre sempre spikes verso il basso???
Quando ho scritto "Bisogna vedere come hai collegato la sonda" intendevo anche dire che se hai usato tre pezzi di filo volanti per collegarla a tre o più metri di distanza, può succedere di tutto... Devi usare un cavetto 2+schermo, per esempio per impianti antifurto o per audio bilanciato, usando la calza per la massa. Se, invece, stai facendo queste prove con la sonda collegata direttamente alla scheda Arduino, è un altro problema, ma comunque dovrai usare, poi, il cavetto schermato come ti ho detto.
Nella programmazione strutturata come il C/C++ la forma è sostanza perché per qualcuno che non è l'autore del codice, delineare l'algoritmo sottointeso risulta molto molto più immediato e semplice da fare.
Per quanto riguarda l'osservazione sullo spike in effetti ha senso quello che dici, ma questo dipende anche da come hai dichiarato le variabili t1-t15 senza contare il quadro completo che non vediamo (resto del codice + hardware).
Ad ogni modo questo era il mio suggerimento:
Implementare una verifica del dato letto come quello del -127 o l'altro sistema che avevi implementato, in questo modo è immediato e non devo ripetere lo stesso pezzo di codice per 15 volte.
Grazie Datman.
La sonda è questa. Ha il cavetto di 50 cm in dotazione. Dici che dovrei schermarlo anche così corto?
Comunque il concetto è che mi piaceva risolvere il problema, non evitando le letture anormali che sappiamo bene essere "insite" nel sistema Arduino (per mille ragioni che non stiamo qui a sindacare non le riusciamo ad evitare... ad esempio nel 2016 feci un pdf apposito qui nel Forum esattamente per risolvere le interferenze elettromagnetiche causate dall'uso di elettrovalvole... grande risoluzione la dettero le reti snubber), bensì risolvendolo da un punto di vista "logico".
Ossia come potremmo "smorzare" i picchi anche se durano 2 minuti?
Dilatando i tempi fra le letture?
Resettando i valori percentualmente superiori o inferiori ad un tot?
Vi viene qualche altra idea?
Mah... Io sono del parere che ci si debba, per prima cosa, impegnare per evitare gli errori in ingresso. "Garbage in, garbage out": immondizia entra, immondizia esce!...
https://www.google.com/search?&q=garbage+in+garbage+out
Qui si parla degli errori di lettura delle DS18B20:
Sembra che ci siano anche delle parti dalle temporizzazioni critiche: se è così, potrebbe anche dipendere dall'economicissimo risuonatore ceramico comunemente usato al posto del quarzo nelle schede Arduino anche originali.
Il problema è che il valore -127 non è immondizia purtroppo, è il valore ritornato dalla libreria nel caso in cui ci sia un errore sul bus che non consente la lettura del sensore che viene visto come non connesso.
Considerando che il bus 1-Wire è implementato via software usando dei delayMicroseconds() bisogna tenere conto che in determinati momenti la lettura può fallire perché magari subentra un interrupt o chissà cosa e il micro è impegnato a fare altro.
Beh... Se si tratta solo di scartare i -127, ci vuole poco... Qui, però, ci sono altri valori sbagliati!
Se il problema sono gli interrupt, non si può semplicemente disabilitarli un attimo prima della lettura e riabilitarli subito dopo, leggendo ogni secondo o ogni 10?
[edit: rimosso intervento errato]
Ciao, Ale.
Comunque qui non bisogna cancellare il rumore, ma scartare letture errate: fai 4 letture una dietro l'altra e se una è molto diversa dalle altre la scarti; delle tre che restano puoi semplicemente prendere la prima o l'ultima.
Puoi anche fare rapidamente tre letture consecutive: scarti la minima e la massima e prendi quella che resta.
sostituisci la sonda con una analogica , ptc, ntc, rtd, sono ovunque ti giri , nei condizionatori, nelle caldaie, nei crotermostati, nei elettrodomestici, ovunque in ambiente industriale (insieme alle TC) perchè vi ostinate ad usare queste dallas 18b20 ?
Grazie cotestatnt.
Il listato che gentilmente proponi (al di là della bellissima forma) elimina solo il -127, e nel nostro caso non ci aiuta
Grazie DatMan.
Se in effeti guardi il mio codice elimina esattamente tutte le letture che sono maggiori o minori di uno scarto di tot gradi (sto usando 3 gradi) rispetto alla media... addirittura riportando il suo valore alla media in caso di anomalia.
Purtroppo non risolve perchè si vede che i dati sfalzati durano fino a 2 minuti e quindi tutte le letture riflettono (pur riportando alla media) una propagata serie di medie errate.
Per questo all'inizio del post vi chiedevo se fosse sensato dilatare il tempo di lettura fino a qualche minuto (anzicchè 15 secondi)... intaccando però la reattività.
Grazie icio e ben trovato dopo tanto.
Mi mostri il link ad una sonda stagna che secondo te farebbe al caso mio?
Abbracci
Il listato che propongo è solo a scopo dimostrativo per evidenziare come si può facilmente implementare un controllo sui valori con poche righe invece che con decine.
Ad ogni modo, secondo me dovresti tentare di capire prima di tutto la radice del problema: ad esempio invece di fare il grafico della media che lo nasconde, semplifica tutto e usa ogni singola lettura così da avere tutti i dati disponibili.
A quel punto capisci subito il comportamento della sonda e quali sono i valori fuori scala.
Sinceramente io trovo strano che non funzioni correttamente fino a 2 minuti.
Mi è capitato di usare sensori di temperatura di ogni tipo, Dallas, PTC, NTC, termocoppie, PIR, BME280, etc etc ed il massimo dell'elaborazione dati a cui sono arrivato è una media ponderata esponenziale (che preferisco alla media aritmetica) inserita più per sfizio che per necessità reale.
Per questo tutto 'sto algoritmo così complesso non mi convince.


