Labor – Array-Verwaltung mit LEER_WERT
Erläuterungen dazu siehe Arrays verwalten - Markierung ungenutzter Zellen mit LEER_WERT
Ein Temperatursensor speichert in Abständen von 30 Minuten Messwerte der Außentemperatur. Eine gelegentlich auftretende Störung führt zu unbrauchbaren "Ausreißern". Zur Korrektur mit Methode removeIfBad(…)
wird jeder Wert mit seinen Nachbarwerten verglichen. Wenn er um mehr als 2°C vom Mittelwert seiner Nachbarwerte abweicht, wird er gelöscht.
Dabei wird angenommen, dass wegen Kürze und geringer Häufigkeit der Störungen praktisch nie 2 direkt hintereinander auftreten.
Bereinigungen werden erst NACH Abschließen der Messungen vorgenommen.
Erste und letzte Messung werden zu Beginn händisch mit printMesswerte(…)
kontrolliert und bei Bedarf mittels setFirst(…)
, setLast(…)
korrigiert, sodass die Kontrolle vom 2. bis zum vorletzten Wert automatisch erfolgen kann.
Anschließend werden einige Auswertungen mit den Daten durchgeführt.
Die Daten liegen als byte-Werte vor (-128 bis 127), wobei der mögliche Temperaturbereich von -40°C bis +60°C liegt. Die Konstante Byte.MIN_VALUE
ist daher ein guter LEER_WERT (als Konstante zu definieren).
-
EMPTY_VAL … Konstante mit niedrigstem Byte-Wert (Konstante verwenden, nicht Zahlenwert direkt!)
-
Konstruktor() … legt ein Array für 24 Stunden (48 Messwerte) an und initialisiert es mit EMPTY_VAL
-
Konstruktor(…) … legt Array mit gegebener Kapazität an, (min. 6=3h, max 336=7*24*2=1Wo Werte)
-
add(sensorValue: byte): boolean … Datenerfassungsmethode (wird vom Sensor aufgerufen).
Dabei wird das Array nach der ersten Zelle mit InhaltEMPTY_VAL
gesucht und der übergebene Wert darin gespeichert (damit ist die Zelle als genutzt erkennbar) und wird für den nächsten Aufruf nicht mehr genutzt. Wenn keine freie Zelle mehr gefunden wird, ist der Rückgabewertfalse
, sonsttrue
.
Bei Verwendung nachcleanData()
wird nichts hinzugefügt undfalse
zurückgeliefert, da sonst neue Werte in eventuell entstandene Lücken gesetzt würden! -
remove(idx: int): boolean … ersetzt den Zell-Wert durch
EMPTY_VAL
. Falls davor schon EMPTY_VAL enthalten war oder ein ungültiger Index übergeben wurde, wirdfalse
zurückgeliefert, sonst true.
Zusätzlich Fehlermeldung, wennidx
ungültig war. -
setFirst(sensorValue: byte) … setzt die erste Zelle auf den übergebenen Wert.
-
setLast(sensorValue: byte) … setzt die letzte Zelle auf den übergebenen Wert.
-
removeIfBad(idx: int): char … prüft Wert in Zelle
idx
und entfernt ihn bei Bedarf.Die Prüfung erfolgt durch Vergleich mit den beiden Nachbar-Werten. Somit beginnt die Prüfung bei der zweiten und endet bei der vorletzten Zelle.
Wennidx
gültig und sein "linker" und "rechter" Nachbar gültige Werte sind, wird der Durchschnitt der beiden Nachbarzell-Werte gebildet und mit dem Wert verglichen.
Zellwerte sind gültig, wenn ihre Abweichung (nach oben und unten) von diesem Durchschnitt nicht größer als 2 ist.
Wenn nicht beide Nachbarn da sind, wird der Wert als nicht prüfbar (wird verwendet) angesehen.
Bei zu großer Abweichung wird der Zellwert aufEMPTY_VAL
gesetzt.
Es gibt 4 mögliche Rückgabewerte (daher nicht boolean, sondern char):-
'i'
…idx
ungültig, kein Zell-Wert wird verändert -
'?'
… eine oder beide Nachbarzellen habenEMPTY_VAL
, Zell-Wert bleibt unverändert -
'$'
… Wert war ok, Zell-Wert bleibt unverändert -
'_'
… Wert war ungültig, musste entfernt (auf EMPTY_VAL gesetzt) werden
-
-
cleanData() … durchläuft für alle Daten zwischen erster und letzter Zelle (diese sind nicht dabei) und wendet removeIfBad(..) an. Es wird auf den Bildschirm protokolliert mit Index, Rückgabewert (
'i'
,'?'
,'$'
,'_'
): und finaler Zell-Wert.
Am Ende wirddataCleaned
auftrue
gesetzt. -
maxUsedIdx(): int … liefert den Index der letzten genutzten Zelle
-
minValue(): byte … kleinster Wert aller Zellen. + Implementierungsmöglichkeit: In einer Hilfsvariabeln (z.B.
aktuellMin
) wird zu Beginn der "gegenüberliegende Extremwert des Datentyps" (hier Byte.MAX_VALUE) gespeichert und dann jede Zelle damit verglichen. Falls ihr wert kleiner, wird er inaktuellMin
gespeichert und dient ab nun als Vergleichsbasis. Am Ende wird dieser Wert zurückgeliefert. -
maxValue(): byte … größter Wert aller Zellen (analog zu
minWert(…)
) -
average(): float … MittelWert – Summe aller gültigen Werte geteilt durch deren Anzahl
-
printSensorData(columns: int) … mehrspaltige Ausgabe der Messwerte. Siehe dazu z.B. Arrays-Intro: Kapazitätserhöhung, Methode printArray(…).
Fürspalten=4
sollte bei 9 Messwerten z.B. folgende Ausgabe erzeugt werden:
Anzahl Messwerte: 9 -5, -3, -1, 1, 2, 4, 5, 7, 8
-
printDiagram(startIdx: int, endIdx: int) … Optionale Bonus-Aufgabe!
"zeichnet" ein Diagramm (Genauigkeit 5°/Zeile) wie folgt:
°C ^ +60| | +50| | +40| | +30| | **** ********** ** +20| ** ***** ***** *** | ***** +10| ** | ** 0 +--*---------------------------------------------> Zeit (Einheit 1/2h) | * -10|* | -20| | -30| | -40|
Zur Lösung kann man folgendermaßen vorgehen:
-
Es muss zeilenweise von oben nach unten ausgegeben werden.
-
Die erste Zeile hat den Inhalt
" °C ^"
-
Jede reguläre Zeile repräsentiert ein 5°-Intervall, das von 2° oberhalb bis 3° unterhalb des Zeilen-Nennwerts reicht. Die Nenn-Werte laufen von 60, 55, 50, 45, … -30, -35, 40.
-
Die regulären Zeilen alternieren bezüglich der Achsenbeschriftung.
-
Jede reguläre Zeile beginnt mit der Achsen-Ausgabe:
-
Wenn Zeilen-Nennwert durch 10 teilbar und > 0, wird das
" +"
gefolgt vom Zahlenwert gefolgt von"|"
ausgegeben -
bei negativen Temperaturen analog (
" -"
statt" +"
) -
Die 0°-Zeile erfordert Sonderbehandlung (siehe Beispiel-Diagramm).
-
anderenfalls wird nur
" |"
ausgegeben -
danach folgt für jede Zeile der "Daten-Teil":
-
Für jede Zeile wird der beim Methodenaufruf festgelegte Index/Zeit-Bereich an Array-Werten durchlaufen. Falls der jeweilige Array-Wert im aktuellen 5°-Intervall liegt, wird ein
'*'
ausgegeben, anderenfalls ein' '
(bei der 0°-Zeile statt' '
ein'-'
). -
ungültige Werte liegen naturgemäß nicht im aktuellen Werte-Intervall, es wird also ebenfalls
' '
ausgegeben.