Archive for gennaio 2022
Interpolazione dati stazione meteo
Buon anno cari lettori di questo blog. Come sapete ho una stazione meteo costruita con i fascicoli della De Agostini tra il 2008 e il 2010.
Il Datalogger raccoglie ogni 5 minuti i dati che gli arrivano dai vari sensori esterni.
Tuttavia succede che a causa dello scaricamento delle batterie, in invio, o in ricezione, alcuni dati siano, purtroppo, andati persi.
Ma se l’intervallo di dati mancanti è abbastanza breve, possiamo recuperarli per interpolazione.
Ho quindi sviluppato un piccolo programma in VB.NET per recuperare questi dati e cancellare il più possibile le celle bianche.
In questo articolo, vado quindi a descrivere come funziona questo programma, nel caso anche altri avessero avuto il mio stesso problema.
Apriamo Visual Studio 2019 e creiamo un nuovo progetto WPF, XAML (.NET Framework) e VB.NET.
Aggiungiamo poi la mappatura Entity Data Model (First Database), con origine dati a un server SqlServer.
Io ho sul Cloud questi dati.
Lo XAML è semplicemente un pulsante.
Nel code-behind mettiamo il codice di gestione del pulsante all’evento Click:
Private Sub Button_Click(sender As Object, e As RoutedEventArgs)
ritorna:
Lista.Clear()
Dim enti As New crystalweb_it_meteoEntities
Dim numerovuoti As Integer = 0
Dim uuu = (From hhh In enti.DataLog Select hhh.idLog, hhh.Ch1_Hum, hhh.Realtime Where idLog > 15749).ToList
Dim ValoreInizialePrimaDellaSequenzaVuota As String
Dim ValoreFinaleDopoLaSequenzaVuota As String
Collezione.Source = (From hhh In enti.DataLog Select hhh.idLog, hhh.Ch1_Hum, hhh.Realtime).ToList
For Each sss In uuu
If sss.Ch1_Hum = "" Then
Collezione.View.MoveCurrentTo(sss)
idPrimoVuoto = sss.idLog
Collezione.View.MoveCurrentToPrevious()
ValoreInizialePrimaDellaSequenzaVuota = Collezione.View.CurrentItem.Ch1_Hum
NumeroSpazivuoti = CercaNumeroSpaziVuotiConsecutivi()
If NumeroSpazivuoti > 2 * 24 * 12 Then MessageBox.Show("Periodo troppo lungo senza dati, saltiamo l'interpolazione. Idlog=" & idPrimoVuoto) : Exit Sub
ValoreFinaleDopoLaSequenzaVuota = CercaValoreFinaleDopoLaSequenzaVuota(idPrimoVuoto, NumeroSpazivuoti)
Collezione.View.MoveCurrentTo(sss)
Call CalcolaValoriNellaSequenzaVuota(idPrimoVuoto, NumeroSpazivuoti, ValoreInizialePrimaDellaSequenzaVuota, ValoreFinaleDopoLaSequenzaVuota)
Call RegistraNelDBNuoviValori(idPrimoVuoto)
GoTo ritorna
End If
Next
End Sub
Come potete vedere, ho spezzettato vari segmenti di codice in base a quello che deve fare.
Come prima cosa dichiariamo variabili e oggetti:
Public Property idPrimoVuoto As Integer
Public Property NumeroSpazivuoti As Integer
Dim Collezione As New System.Windows.Data.CollectionViewSource
Dim Lista As New List(Of ListaDaAggiungere)
Facciamo una query per individuare il primo “buco”. Dobbiamo ora cercare l’ultimo buco della sequenza. Verifichiamo che la sequenza senza dati non sia troppo lunga.
Otteniamo quindi il valore iniziale e il valore finale.
Calcoliamo quindi l’interpolazione e quindi salviamo i dati sul database.
Il resto del codice è il seguente:
Private Sub RegistraNelDBNuoviValori(idPrimoVuoto As Integer)
For Each zzz In Lista
Dim rti As New crystalweb_it_meteoEntities
Dim vol = rti.DataLog.First(Function(c) c.idLog = zzz.idDataLog)
vol.Ch1_Hum = zzz.Umidita
rti.SaveChanges()
Next
End Sub
Private Sub CalcolaValoriNellaSequenzaVuota(idPrimoVuoto As Integer, NumeroSpazivuoti As Integer, ValoreInizialePrimaDellaSequenzaVuota As Integer, ValoreFinaleDopoLaSequenzaVuota As Integer)
Dim diffe = ValoreFinaleDopoLaSequenzaVuota - ValoreInizialePrimaDellaSequenzaVuota
Dim salto = diffe / (NumeroSpazivuoti + 1)
Dim ValoreReale As Double = ValoreInizialePrimaDellaSequenzaVuota
Dim ValoreArrotondato As Integer = ValoreReale
For ty = 1 To NumeroSpazivuoti
ValoreReale = ValoreReale + salto
ValoreArrotondato = Math.Round(ValoreReale, 0)
Lista.Add(New ListaDaAggiungere(Collezione.View.CurrentItem.idLog, ValoreArrotondato))
Collezione.View.MoveCurrentToNext()
Next
End Sub
Private Function CercaValoreFinaleDopoLaSequenzaVuota(idPrimoVuoto As Integer, numeroSpazivuoti As Integer) As String
Dim enti As New crystalweb_it_meteoEntities
Dim ccc = (From hhh In enti.DataLog Where hhh.idLog > (idPrimoVuoto - 1) Take (numeroSpazivuoti) + 1 Select hhh.idLog, hhh.Ch1_Hum, hhh.Realtime).ToList
Dim ritorna As String
ritorna = ccc.LastOrDefault.Ch1_Hum
Return ritorna
End Function
Private Function CercaNumeroSpaziVuotiConsecutivi() As Integer
Dim NumeroSpazivuoti As Integer = 0
ciclo:
Collezione.View.MoveCurrentToNext()
If Collezione.View.CurrentItem.Ch1_Hum = "" Then<br>NumeroSpazivuoti = NumeroSpazivuoti + 1
GoTo ciclo
Else
GoTo EsceFunzione
End If
EsceFunzione:
Return NumeroSpazivuoti
End Function
End Class
Class ListaDaAggiungere
Private _idDataLog As Integer
Private _Umidita As String
Public Sub New(ByVal idDataLog As Integer, ByVal Umidita As String)
_idDataLog = idDataLog
_Umidita = Umidita
End Sub
Public Property idDataLog As Integer
Get
Return _idDataLog
End Get
Set(value As Integer)
_idDataLog = value
End Set
End Property
Public Property Umidita As String
Get
Return _Umidita
End Get
Set(value As String)
_Umidita = value
End Set
End Property
End Class
Sicuramente ci saranno altri metodi per ottenere le interpolazioni, questo è il metodo al quale ho pensato.
Se avete pensato di scrivere il codice in modo differente, fatemi sapere.
Alla prossima.
