Hallo,
(es geht eigentlich nicht um den Datenbankteil, aber da ich in dem Projekt ein DataSet verwende habe ich das Thema hierhin gepackt.)
Ich hab hier ein Programm, das an sich funktioniert, bei dem ich mich aber recht abgemüht hab, und auch arg viel rechnen muss. Daher hoffe ich, dass ihr mir noch ein wenig Ratschläge dazu geben könntet.
Das Programm verarbeitet Statusdaten einer automatisierten Maschine mit vier Stationen. Jede Station hat zwei Stati
Die Änderung eines Status verursacht einen Eintrag in der Datenquelle mit Zeitstempel, den Stati, und der Station (Das macht das Programm nicht, es liest diese nur aus)
In dem Projekt habe ich damit ihr auch Beispielquelldaten habt (falls ihr die denn braucht), als Datenquelle eine csv genommen (aufbereitet.csv). (Diese Version läuft auch nur mit dem Start Button. Das Load-Event ist nur für den "Normalbetrieb")
Was das Programm ermitteln soll ist die Dauer, die die Maschine nicht gelaufen ist.
Wann die Maschine nicht läuft ist erstmal Definitionssache.
Momentan ist es so definiert: Da jede Statusänderung erfasst wird, und Statusänderungen während des Maschinenablaufs erfolgen, soll keine Statusänderung von Minute x bis Minute x+1 eine Minute Stillstand bedeuten.
Daher habe ich erstmal eine Tabelle
Die
Also Beispiel (Eintrag um 12:00:00 Status 3, um 12:00:09 Status 0, um 12:01:10 Status 3) ergibt für die ganze Minute 12:00 den Durschnittlichen Status 0.45
Diese komischen Durchschnittswerte haben den Vorteil, dass sie verraten ob in der Minute etwas passiert ist, wenn sich die Stati nämlich ändern kommen wilde Nachkommastellen dabei rum. Nur bei Stillstand gibt es schöne Ganzzahlen.
In der
Dann werden nur noch die Minuten gezählt wo alle Stationen gestoppt sind.
Als letzte Abwandlung werden die Stopminuten schichtweise ermittelt, denn die Maschine hat ja auch Stopzeiten wenn theoretisch gar keine Produktion vorgesehen ist.
Das Form ist übrigens nur zum Reingucken und Tüfteln gewesen. Eine Oberfläche braucht es eigentlich nicht. Es spuckt hintendrein das Ergebnis auch als csv wieder aus. Für die Beispiel-Quelldaten ergeben sich 94, 97, 52 Stop Minuten
Tja also wie gesagt an sich tuts schon, aber es sind natürlich auch offensichtliche Lücken drin. Eine StopMinute zählt z.b. nur wenn sie von 12:00:00 bis 12:01:00 geht, nicht aber wenn sie von 12:00:30 bis 12:01:30 geht, was recht willkürlich ist, aufgrund der Ungenauigkeit der ganzen Angelegenheit (Definition Stillstand) allerdings nicht wirklich ins Gewicht fällt. Ich hätte aber Interesse dran noch ein wenig zu basteln. Allerdings weiß ich nich wo ich es anpacken sollte.
Viele Grüße
PS: Der Code auch hier nochmal:
Spoiler anzeigen
(es geht eigentlich nicht um den Datenbankteil, aber da ich in dem Projekt ein DataSet verwende habe ich das Thema hierhin gepackt.)
Ich hab hier ein Programm, das an sich funktioniert, bei dem ich mich aber recht abgemüht hab, und auch arg viel rechnen muss. Daher hoffe ich, dass ihr mir noch ein wenig Ratschläge dazu geben könntet.
Das Programm verarbeitet Statusdaten einer automatisierten Maschine mit vier Stationen. Jede Station hat zwei Stati
SubStatus
und LEDStatus
.Die Änderung eines Status verursacht einen Eintrag in der Datenquelle mit Zeitstempel, den Stati, und der Station (Das macht das Programm nicht, es liest diese nur aus)
In dem Projekt habe ich damit ihr auch Beispielquelldaten habt (falls ihr die denn braucht), als Datenquelle eine csv genommen (aufbereitet.csv). (Diese Version läuft auch nur mit dem Start Button. Das Load-Event ist nur für den "Normalbetrieb")
Was das Programm ermitteln soll ist die Dauer, die die Maschine nicht gelaufen ist.
Wann die Maschine nicht läuft ist erstmal Definitionssache.
Momentan ist es so definiert: Da jede Statusänderung erfasst wird, und Statusänderungen während des Maschinenablaufs erfolgen, soll keine Statusänderung von Minute x bis Minute x+1 eine Minute Stillstand bedeuten.
Daher habe ich erstmal eine Tabelle
dtAvgMinute
erzeugt, die die Minuten des Tages denn überhaupt erstmal darstellt (Quelldaten sind ja nur Zeitpunkte):id
ist die jeweilige Stationsnr der Maschine. Und berechne für die Quelldaten, die noch eine Dummy-Spalte Dauer
beinhalten die Dauer, die zwischen zwei Statusänderungen lag.Die
AverageData
Methode soll dann aus der Dauer und den Stati, einen Durchschnittsstatus bilden für eine jeweilige Tagesminute einer Station.Also Beispiel (Eintrag um 12:00:00 Status 3, um 12:00:09 Status 0, um 12:01:10 Status 3) ergibt für die ganze Minute 12:00 den Durschnittlichen Status 0.45
Diese komischen Durchschnittswerte haben den Vorteil, dass sie verraten ob in der Minute etwas passiert ist, wenn sich die Stati nämlich ändern kommen wilde Nachkommastellen dabei rum. Nur bei Stillstand gibt es schöne Ganzzahlen.
In der
EvaluateStationStop
definiere ich genau das. Ganzzahlergebnis heißt die Station hat gestoppt. Da die Maschine aus vier Stationen besteht, die aufeinander auch warten müssen, heißt ein Stop einer Station also noch lange nicht ein Stop der ganzen Maschine. Daher fülle ich hier eine Tabelle dtStopMinuten
mit den Stationen, die zu den jeweiligen Tagesminuten gestoppt waren.Dann werden nur noch die Minuten gezählt wo alle Stationen gestoppt sind.
Als letzte Abwandlung werden die Stopminuten schichtweise ermittelt, denn die Maschine hat ja auch Stopzeiten wenn theoretisch gar keine Produktion vorgesehen ist.
Das Form ist übrigens nur zum Reingucken und Tüfteln gewesen. Eine Oberfläche braucht es eigentlich nicht. Es spuckt hintendrein das Ergebnis auch als csv wieder aus. Für die Beispiel-Quelldaten ergeben sich 94, 97, 52 Stop Minuten
Tja also wie gesagt an sich tuts schon, aber es sind natürlich auch offensichtliche Lücken drin. Eine StopMinute zählt z.b. nur wenn sie von 12:00:00 bis 12:01:00 geht, nicht aber wenn sie von 12:00:30 bis 12:01:30 geht, was recht willkürlich ist, aufgrund der Ungenauigkeit der ganzen Angelegenheit (Definition Stillstand) allerdings nicht wirklich ins Gewicht fällt. Ich hätte aber Interesse dran noch ein wenig zu basteln. Allerdings weiß ich nich wo ich es anpacken sollte.
Viele Grüße
PS: Der Code auch hier nochmal:
VB.NET-Quellcode
- Option Strict On
- Public Class Form1
- Private datum As DateTime
- Private StundenTagesAnfang As Single = 22.0 '22:00 fängt Nachtschicht an
- Private csv1 As New List(Of Csvline)
- Private Function GetToDo() As List(Of DateTime)
- Dim hold As New List(Of DateTime)
- Try
- Dim holddatum = DateTime.Parse(File.ReadAllText("StopInsert.txt")).AddDays(1)
- While holddatum < DateTime.Today.AddDays(-1).AddHours(StundenTagesAnfang)
- hold.Add(holddatum)
- holddatum = holddatum.AddDays(1)
- End While
- hold.Add(DateTime.Today.AddDays(-1).AddHours(StundenTagesAnfang))
- Return hold
- Catch ex As Exception
- File.WriteAllText("log.txt", ex.ToString)
- hold.Add(DateTime.Today.AddDays(-1).AddHours(StundenTagesAnfang))
- Return hold
- End Try
- End Function
- Private Sub Form1_Load(sender As Object, e As EventArgs) Handles Me.Load
- If Not Boolean.Parse(File.ReadAllText("AutoAufruf.txt")) Then
- Exit Sub
- End If
- Dim ToDo = GetToDo()
- For Each element In ToDo
- datum = element
- GetData()
- For id As Byte = 1 To 4
- AverageData(id)
- Next
- EvaluateStationStop()
- EvaluateDailyResult()
- Next
- Application.Exit()
- End Sub
- Private Sub btStart_Click(sender As Object, e As EventArgs) Handles btStart.Click
- 'datum = DateTime.Today.AddDays(-1).AddHours(StundenTagesAnfang) 'Sonst für tagesaktuellen Gebrauch
- datum = DateTime.Parse("2022-04-14T22:00:00")
- GetData()
- For id As Byte = 1 To 4
- AverageData(id)
- Next
- EvaluateStationStop()
- EvaluateDailyResult()
- End Sub
- Private Sub GetData()
- Dim hold As String() = File.ReadAllLines("aufbereitet.csv")
- For i = 1 To hold.Count - 1
- csv1.Add(New Csvline(hold(i).Split(";"c)))
- Next
- dgvStation.DataSource = DtAufbereitetBindingSource
- DtAufbereitetBindingSource.DataSource = csv1
- DtAufbereitetBindingSource.ResetBindings(False)
- 'Sonst mit Sql Datenquelle da.Fill(DS1.dtAufbereitet)
- Dim bis As DateTime
- Dim von As DateTime
- DS1.dtAvgMinute.Clear()
- Dim linquery As List(Of Csvline)
- Dim id As Byte
- For n As Byte = 1 To 4
- id = n
- For i = -1 To 1439
- DS1.dtAvgMinute.AdddtAvgMinuteRow(datum.AddMinutes(-i), -99, -99, id)
- Next i
- linquery = (From t In csv1 Where t.StationsID = id Order By t.Zeitstempel Descending).ToList
- If linquery.Count = 0 Then
- Continue For
- End If
- von = linquery(0).Zeitstempel
- 'erster Eintrag default
- Dim diff = TimeSpan.FromSeconds(99999) : linquery(0).Dauer = diff.TotalSeconds
- 'andere Einträge
- For i = 1 To linquery.Count - 1
- bis = linquery(i - 1).Zeitstempel
- von = linquery(i).Zeitstempel
- diff = bis - von
- linquery(i).Dauer = diff.TotalSeconds
- Next
- Next
- End Sub
- Private Sub AverageData(ID As Byte)
- Dim k As Integer = 0
- Dim avgSub As Double
- Dim avgLED As Double
- Dim linqAvgMinute = (From t In DS1.dtAvgMinute Where t.StationsID = ID Order By t.Zeit Descending).ToList
- Dim linqAufbereitet = (From t In csv1 Where t.StationsID = ID Order By t.Zeitstempel Descending).ToList
- Dim AktDatenzeile As Csvline
- Dim AktEvalzeile As DataSet1.dtAvgMinuteRow
- Dim NextEvalzeile As DataSet1.dtAvgMinuteRow
- For i = 0 To linqAvgMinute.Count - 2
- avgSub = 0
- avgLED = 0
- AktEvalzeile = linqAvgMinute(i)
- NextEvalzeile = linqAvgMinute(i + 1)
- For j = k To linqAufbereitet.Count - 1
- AktDatenzeile = linqAufbereitet(j)
- If AktDatenzeile.Zeitstempel >= NextEvalzeile.Zeit Then
- If AktDatenzeile.Zeitstempel >= AktEvalzeile.Zeit Then
- 'MessageBox.Show($"Berechnung frühzeitig beendet: Letzter Datenpunkt {AktDatenzeile.Zeit.ToString}")
- Exit Sub
- Else
- If AktDatenzeile.Zeitstempel.AddSeconds(AktDatenzeile.Dauer) >= AktEvalzeile.Zeit Then
- avgSub += (AktEvalzeile.Zeit - AktDatenzeile.Zeitstempel).TotalSeconds * AktDatenzeile.SubStatus / 60
- avgLED += (AktEvalzeile.Zeit - AktDatenzeile.Zeitstempel).TotalSeconds * AktDatenzeile.LEDStatus / 60
- Else
- avgSub += AktDatenzeile.SubStatus * AktDatenzeile.Dauer / 60
- avgLED += AktDatenzeile.LEDStatus * AktDatenzeile.Dauer / 60
- End If
- End If
- Else
- If AktDatenzeile.Zeitstempel.AddSeconds(AktDatenzeile.Dauer) >= AktEvalzeile.Zeit.AddMinutes(1) Then
- AktEvalzeile.SubStatus = AktDatenzeile.SubStatus
- AktEvalzeile.LEDStatus = AktDatenzeile.LEDStatus
- k = j
- Exit For
- ElseIf AktDatenzeile.Zeitstempel.AddSeconds(AktDatenzeile.Dauer) >= AktEvalzeile.Zeit Then
- k = j
- Exit For
- Else
- If AktDatenzeile.Zeitstempel.AddSeconds(AktDatenzeile.Dauer) >= NextEvalzeile.Zeit Then
- avgSub += (AktDatenzeile.Zeitstempel.AddSeconds(AktDatenzeile.Dauer) - NextEvalzeile.Zeit).TotalSeconds * AktDatenzeile.SubStatus / 60
- avgLED += (AktDatenzeile.Zeitstempel.AddSeconds(AktDatenzeile.Dauer) - NextEvalzeile.Zeit).TotalSeconds * AktDatenzeile.LEDStatus / 60
- k = j
- Exit For
- Else
- k = j
- Exit For
- MessageBox.Show($"Unmögliche Verarbeitung 2: Kontrolliere Daten {AktDatenzeile.Zeitstempel.ToString}")
- End If
- End If
- End If
- Next j
- NextEvalzeile.SubStatus = avgSub
- NextEvalzeile.LEDStatus = avgLED
- Next i
- End Sub
- Private Sub EvaluateStationStop()
- ''Filter auf Stop-Definitionen1:
- ''SubStatus = 8 oder -9 => Warte auf Material
- ''LEDStatus = 1 => Handbetrieb, normalerweise nur zum Anhalten genutzt
- ''LEDStatus = 4 => Not-Aus
- 'Dim filterStopzeit = From t In DS1.dtAvgMinute Where t.SubStatus = 8 OrElse t.SubStatus = -9 OrElse t.LEDStatus = 1 OrElse t.LEDStatus = 4 Order By t.Zeit Descending, t.StationsID Select t.Zeit, t.StationsID
- 'Filter auf Stop-Definitionen2:
- 'Stati bleiben unverändert
- Dim filterStopzeit = From t In DS1.dtAvgMinute Where t.SubStatus - Math.Floor(t.SubStatus) = 0 AndAlso t.LEDStatus - Math.Floor(t.LEDStatus) = 0 Order By t.Zeit Descending, t.StationsID Select t.Zeit, t.StationsID
- Dim recentlyAddedTime As DateTime = DateTime.Now.AddDays(2) 'Irgendein Datum in der Zukunft, wird dann garantiert überschrieben
- Dim update As DataSet1.dtStopMinutenRow
- For Each element In filterStopzeit
- If recentlyAddedTime = element.Zeit Then
- update = (From t In DS1.dtStopMinuten Where t.Zeit = recentlyAddedTime)(0)
- Select Case element.StationsID
- Case 1
- update.Station1 = True
- Case 2
- update.Station2 = True
- Case 3
- update.Station3 = True
- Case 4
- update.Station4 = True
- End Select
- Else
- recentlyAddedTime = element.Zeit
- Select Case element.StationsID
- Case 1
- DS1.dtStopMinuten.AdddtStopMinutenRow(recentlyAddedTime, True, False, False, False)
- Case 2
- DS1.dtStopMinuten.AdddtStopMinutenRow(recentlyAddedTime, False, True, False, False)
- Case 3
- DS1.dtStopMinuten.AdddtStopMinutenRow(recentlyAddedTime, False, False, True, False)
- Case 4
- DS1.dtStopMinuten.AdddtStopMinutenRow(recentlyAddedTime, False, False, False, True)
- End Select
- End If
- Next
- 'Dim test = New List(Of DataSet1.dtStopMinutenRow)
- 'For Each element In DS1.dtStopMinuten
- ' test.Add(element)
- 'Next
- ''Ausgabe csv
- 'For Each element In DS1.dtStopMinuten
- ' File.AppendAllText("ausgabe2.csv", $"{element.Zeit.ToString};{element.Station1.ToString};{element.Station2.ToString};{element.Station3.ToString};{element.Station4.ToString}{vbLf}")
- 'Next
- End Sub
- Private Sub EvaluateDailyResult()
- If DateTime.Parse(File.ReadAllText("StopInsert.txt")) >= DateTime.Now.AddDays(-1) Then
- Exit Sub
- End If
- Dim Gesquery, Pausequery As EnumerableRowCollection(Of DataSet1.dtStopMinutenRow)
- Dim sys As New SchichtSys(datum)
- Dim ZeitSumme As Integer
- Dim PauseSumme As Integer
- Dim filterStop = From t In DS1.dtStopMinuten Where t.Station1 AndAlso t.Station2 AndAlso t.Station3 AndAlso t.Station4
- Dim csv2 As New List(Of String)
- For Each schicht As SchichtSys.Schicht In System.Enum.GetValues(GetType(SchichtSys.Schicht))
- sys.SetSchicht(schicht)
- Gesquery = From t In filterStop Where t.Zeit >= sys.Schichtbeginn AndAlso t.Zeit < sys.Schichtende
- Pausequery = From t In filterStop Where t.Zeit >= sys.Pausenbeginn AndAlso t.Zeit < sys.Pausenende
- ZeitSumme = Gesquery.Count
- PauseSumme = Pausequery.Count
- ''hier sonst auch Sql Insert
- csv2.Add($"{datum.AddHours(-StundenTagesAnfang).ToString("yyyy-MM-ddTHH:mm:ss")};{sys.ChoiceToString},{ZeitSumme};{PauseSumme})")
- Next
- File.WriteAllLines("ergebnis.csv", csv2)
- File.WriteAllText("StopInsert.txt", datum.ToString)
- End Sub
- End Class
- Friend Class Csvline
- Property Zeitstempel As DateTime
- Property Dauer As Double
- Property SubStatus As Short
- Property Integral As Double
- Property LEDStatus As Short
- Property StationsID As Byte
- Sub New(line As String())
- Zeitstempel = DateTime.Parse(line(0))
- Dauer = Double.Parse(line(1))
- SubStatus = Short.Parse(line(2))
- Integral = Double.Parse(line(3))
- LEDStatus = Short.Parse(line(4))
- StationsID = Byte.Parse(line(5))
- End Sub
- End Class
Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „Haudruferzappeltnoch“ ()