Labor – Array-Verwaltung mit LEER_WERT: Messreihe Temperatursensor

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 Abscließ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).

TempSensorLEER_WERT: bytemesswerte: byte[]Konstruktor()Konstruktor(kapazitaet: int)add(messwert : byte): booleanDatenerfassungremove(idx: int): boolean // false wenn idx ungültigsetFirst(messwert: byte)setLast(messwert: byte)removeIfBad(idx: int): char // siehe BeschreibungBereinigungmaxUsedIdx(): intminWert(): bytemaxWert(): bytemittelWert(): floatAuswertungenprintMesswerte(spalten: int)printDiagramm(startIdx: int, endIdx: int)Ausgabe
  • LEER_WERT …​ 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 LEER_WERT

  • Konstruktor(…​) …​ legt Array mit gegebener Kapazität an, (min. 6=3h, max 336=7*24*2=1Wo Werte)

  • add(messwert: byte): boolean …​ Datenerfassungsmethode (wird vom Sensor aufgerufen). Dabei wird das Array nach der ersten Zelle mit Inhalt LEER_WERT 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ückgabewert false, sonst true.

  • remove(idx: int): boolean …​ ersetzt den Zell-Wert durch LEER_WERT. Falls davor schon LEER_WERT enthalten war oder ein ungültiger Index übergeben wurde, wird false zurückgeliefert, sonst true.
    Zusätzlich Fehlermeldung, wenn idx ungültig war.

  • setFirst(messwert: byte) …​ setzt die erste Zelle auf den übergebenen Wert.

  • setLast(messwert: byte) …​ setzt die letzte Zelle auf den übergebenen Wert.

  • removeIfBad(idx: int): char …​prüft, ob idx gültig ist. Das heißt, er muss größer als 0 und kleiner als maxUsedIdx() sein, damit jede Zelle "links und rechts" Nachbarn hat.
    Wenn idx 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. Die Bei zu großer Abweichung wird der Zellwert auf LEER_WERT gesetzt. Es gibt 4 mögliche Rückgabewerte (daher nicht boolean, sondern char):

    • 'i' …​ idx ungültig, kein Zell-Wert wird verändert

    • 'n' …​ eine oder beide Nachbarzellen haben LEER_WERT, kein Zell-Wert wird verändert

    • '$' …​ Wert war ok, nichts wird geändert

    • '_' …​ Wert war ungültig, musste entfernt (auf LEER_WERT gesetzt) werden

  • maxUsedIdx(): int …​ liefert den Index der letzten genutzten Zelle

  • minWert(): 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 in aktuellMin gespeichert und dient ab nun als Vergleichsbasis. Am Ende wird dieser Wert zurückgeliefert.

  • maxWert(): byte …​ größter Wert aller Zellen (analog zu minWert(…​) )

  • mittelWert(): float …​

  • printMesswerte(spalten: int) …​ mehrspaltige Ausgabe der Messwerte. Siehe dazu z.B. Arrays-Intro: Kapazitätserhöhung, Methode printArray(…​).
    Für spalten=4 sollte bei 9 Messwerten z.B. folgende Ausgabe erzeugt werden:

Anzahl Messwerte: 9
-5, -3, -1, 1,
2, 4, 5, 7,
8
  • printDiagramm(startIdx: int, endIdx: int) …​ "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 geht man so vor:

  • Es muss zeilenweise von oben nach unten ausgegeben werden.

  • Die erste Zeile hat den Inhalt " °C ^"

  • Die 0°-Zeile erfordert Sonderbehandlung (siehe Beispiel).

  • 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

  • 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 ' '.

  • ungültige Werte liegen naturgemäß nicht im aktuellen Werte-Intervall, es wird also ebenfalls ' ' ausgegeben.