summaryrefslogtreecommitdiff
path: root/android-app/app/src/main/kotlin
diff options
context:
space:
mode:
Diffstat (limited to 'android-app/app/src/main/kotlin')
-rw-r--r--android-app/app/src/main/kotlin/com/example/androidapp/tide/HarmonicTideCalculator.kt88
-rw-r--r--android-app/app/src/main/kotlin/org/terst/nav/data/model/TideConstituent.kt9
-rw-r--r--android-app/app/src/main/kotlin/org/terst/nav/data/model/TidePrediction.kt7
-rw-r--r--android-app/app/src/main/kotlin/org/terst/nav/data/model/TideStation.kt11
-rw-r--r--android-app/app/src/main/kotlin/org\/terst\/nav/data/model/TideConstituent.kt0
-rw-r--r--android-app/app/src/main/kotlin/org\/terst\/nav/data/model/TidePrediction.kt0
-rw-r--r--android-app/app/src/main/kotlin/org\/terst\/nav/data/model/TideStation.kt0
7 files changed, 115 insertions, 0 deletions
diff --git a/android-app/app/src/main/kotlin/com/example/androidapp/tide/HarmonicTideCalculator.kt b/android-app/app/src/main/kotlin/com/example/androidapp/tide/HarmonicTideCalculator.kt
new file mode 100644
index 0000000..2bdbf6c
--- /dev/null
+++ b/android-app/app/src/main/kotlin/com/example/androidapp/tide/HarmonicTideCalculator.kt
@@ -0,0 +1,88 @@
+package com.example.androidapp.tide
+
+import com.example.androidapp.data.model.TidePrediction
+import com.example.androidapp.data.model.TideStation
+import kotlin.math.cos
+
+/**
+ * Computes harmonic tide predictions using the standard formula:
+ * h(t) = Z0 + Σ [ Hi × cos( ωi × (t − t0) − φi ) ]
+ *
+ * where:
+ * Z0 = datum offset (mean water level above chart datum, metres)
+ * Hi = amplitude of constituent i (metres)
+ * ωi = angular speed of constituent i (degrees / hour)
+ * t = hours elapsed since [EPOCH_MS] (2000-01-01 00:00 UTC)
+ * φi = phase lag (degrees)
+ */
+object HarmonicTideCalculator {
+
+ /** Reference epoch: 2000-01-01 00:00:00 UTC in Unix milliseconds. */
+ internal const val EPOCH_MS = 946_684_800_000L
+
+ /**
+ * Predict the tide height at a single moment.
+ *
+ * @param station Tide station with harmonic constituents.
+ * @param timestampMs Unix epoch milliseconds for the desired time.
+ * @return Predicted height in metres above chart datum.
+ */
+ fun predictHeight(station: TideStation, timestampMs: Long): Double {
+ val hoursFromEpoch = (timestampMs - EPOCH_MS) / 3_600_000.0
+ var height = station.datumOffsetMeters
+ for (c in station.constituents) {
+ val angleDeg = c.speedDegPerHour * hoursFromEpoch - c.phaseDeg
+ height += c.amplitudeMeters * cos(Math.toRadians(angleDeg))
+ }
+ return height
+ }
+
+ /**
+ * Predict tide heights over a time range at regular intervals.
+ *
+ * @param station Tide station.
+ * @param fromMs Start of range (Unix milliseconds, inclusive).
+ * @param toMs End of range (Unix milliseconds, inclusive).
+ * @param intervalMs Time step in milliseconds (must be positive).
+ * @return List of [TidePrediction] ordered by ascending timestamp.
+ */
+ fun predictRange(
+ station: TideStation,
+ fromMs: Long,
+ toMs: Long,
+ intervalMs: Long
+ ): List<TidePrediction> {
+ require(intervalMs > 0) { "intervalMs must be positive" }
+ require(fromMs <= toMs) { "fromMs must not exceed toMs" }
+ val predictions = mutableListOf<TidePrediction>()
+ var t = fromMs
+ while (t <= toMs) {
+ predictions += TidePrediction(t, predictHeight(station, t))
+ t += intervalMs
+ }
+ return predictions
+ }
+
+ /**
+ * Find high and low water events from a pre-computed prediction series.
+ *
+ * Detects local maxima (high water) and minima (low water) by comparing
+ * each interior sample with its immediate neighbours.
+ *
+ * @param predictions Ordered list of tide predictions (at least 3 points).
+ * @return Subset list containing only high/low turning points.
+ */
+ fun findHighLow(predictions: List<TidePrediction>): List<TidePrediction> {
+ if (predictions.size < 3) return emptyList()
+ val result = mutableListOf<TidePrediction>()
+ for (i in 1 until predictions.size - 1) {
+ val prev = predictions[i - 1].heightMeters
+ val curr = predictions[i].heightMeters
+ val next = predictions[i + 1].heightMeters
+ val isMax = curr >= prev && curr >= next
+ val isMin = curr <= prev && curr <= next
+ if (isMax || isMin) result += predictions[i]
+ }
+ return result
+ }
+}
diff --git a/android-app/app/src/main/kotlin/org/terst/nav/data/model/TideConstituent.kt b/android-app/app/src/main/kotlin/org/terst/nav/data/model/TideConstituent.kt
new file mode 100644
index 0000000..deb73d6
--- /dev/null
+++ b/android-app/app/src/main/kotlin/org/terst/nav/data/model/TideConstituent.kt
@@ -0,0 +1,9 @@
+package com.example.androidapp.data.model
+
+/** A single harmonic tidal constituent used in harmonic tide prediction. */
+data class TideConstituent(
+ val name: String, // e.g. "M2", "S2", "K1"
+ val speedDegPerHour: Double, // angular speed in degrees per hour
+ val amplitudeMeters: Double, // amplitude in metres
+ val phaseDeg: Double // phase lag (kappa) in degrees
+)
diff --git a/android-app/app/src/main/kotlin/org/terst/nav/data/model/TidePrediction.kt b/android-app/app/src/main/kotlin/org/terst/nav/data/model/TidePrediction.kt
new file mode 100644
index 0000000..51eea44
--- /dev/null
+++ b/android-app/app/src/main/kotlin/org/terst/nav/data/model/TidePrediction.kt
@@ -0,0 +1,7 @@
+package com.example.androidapp.data.model
+
+/** A predicted tide height at a specific point in time. */
+data class TidePrediction(
+ val timestampMs: Long, // Unix epoch milliseconds
+ val heightMeters: Double // predicted water height above chart datum in metres
+)
diff --git a/android-app/app/src/main/kotlin/org/terst/nav/data/model/TideStation.kt b/android-app/app/src/main/kotlin/org/terst/nav/data/model/TideStation.kt
new file mode 100644
index 0000000..c9f96a6
--- /dev/null
+++ b/android-app/app/src/main/kotlin/org/terst/nav/data/model/TideStation.kt
@@ -0,0 +1,11 @@
+package com.example.androidapp.data.model
+
+/** A tide station with harmonic constituents for offline tide prediction. */
+data class TideStation(
+ val id: String,
+ val name: String,
+ val lat: Double,
+ val lon: Double,
+ val datumOffsetMeters: Double, // mean water level above chart datum (Z0)
+ val constituents: List<TideConstituent>
+)
diff --git a/android-app/app/src/main/kotlin/org\/terst\/nav/data/model/TideConstituent.kt b/android-app/app/src/main/kotlin/org\/terst\/nav/data/model/TideConstituent.kt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/android-app/app/src/main/kotlin/org\/terst\/nav/data/model/TideConstituent.kt
diff --git a/android-app/app/src/main/kotlin/org\/terst\/nav/data/model/TidePrediction.kt b/android-app/app/src/main/kotlin/org\/terst\/nav/data/model/TidePrediction.kt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/android-app/app/src/main/kotlin/org\/terst\/nav/data/model/TidePrediction.kt
diff --git a/android-app/app/src/main/kotlin/org\/terst\/nav/data/model/TideStation.kt b/android-app/app/src/main/kotlin/org\/terst\/nav/data/model/TideStation.kt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/android-app/app/src/main/kotlin/org\/terst\/nav/data/model/TideStation.kt