Local-first tidal prediction with multi-station NOAA validation, written in MoonBit.
moon 0.1.20261012
moonc v0.10.15+943464bfagit clone https://github.com/WYT-ai-nb/moontide.git
cd moontide
moon version --all
moon check --target wasm-gc
moon test --target wasm-gc
moon build --target wasm-gcmoon run cmd/moontide --target wasm-gc -- predict \
--station demo \
--date 2026-10-12 \
--tz 8 \
--hours 24moontide list
moontide validate --station demo
moontide predict --station demo --date 2026-10-12 --tz 8 --hours 24
moontide stats --station demo --date 2026-10-12 --hours 48
moontide events --station demo --date 2026-10-12 --format csv
moontide curve --station demo --date 2026-10-12
moontide plan --station demo --date 2026-10-12
moontide export --station demo --date 2026-10-12 --format ics
moontide validate-reference \
--metadata validation/noaa-8518750/metadata.json \
--harcon validation/noaa-8518750/harcon.json \
--datums validation/noaa-8518750/datums.json \
--predictions validation/noaa-8518750/predictions-20261012-20261015.json \
--tolerance 0.12moon run cmd/moontide --target wasm-gc -- validate-reference \
--metadata validation/noaa-8518750/metadata.json \
--harcon validation/noaa-8518750/harcon.json \
--datums validation/noaa-8518750/datums.json \
--predictions validation/noaa-8518750/predictions-20261012-20261015.json \
--tolerance 0.12# MoonTide NOAA Validation
- Station: The Battery (8518750)
- Source: NOAA CO-OPS station 8518750; harmonic constants + published datums
- Datum offset (MSL - MLLW): 0.78 m
- Harmonic constituents: 37 total, 11 used, 26 ignored
- Ignored by the current catalog: MK3, S4, MN4, NU2, S6, MU2, 2N2, OO1, LAM2, S1, M1, J1, MM, SSA, SA, MSF, MF, RHO, T2, R2, 2Q1, 2SM2, M3, L2, 2MK3, M8
- Samples: 96
- Bias: -0.08 m
- Mean absolute error: 0.09 m
- Root mean square error: 0.10 m
- Maximum absolute error: 0.20 m
- Mean-error tolerance: 0.12 m
- Result: **PASS**moon run cmd/moontide --target wasm-gc -- validate-reference \
--metadata validation/noaa-8443970/metadata.json \
--harcon validation/noaa-8443970/harcon.json \
--datums validation/noaa-8443970/datums.json \
--predictions validation/noaa-8443970/predictions-20261012-20261015.json \
--tolerance 0.12# MoonTide NOAA Validation
- Station: Boston (8443970)
- Source: NOAA CO-OPS station 8443970; harmonic constants + published datums
- Datum offset (MSL - MLLW): 1.59 m
- Harmonic constituents: 37 total, 11 used, 26 ignored
- Samples: 96
- Bias: -0.04 m
- Mean absolute error: 0.07 m
- Root mean square error: 0.09 m
- Maximum absolute error: 0.21 m
- Mean-error tolerance: 0.12 m
- Result: **PASS**moontide/
astro.mbt 天文基本参数
time.mbt 儒略日、日期转换和本地时间
constituent.mbt 分潮定义和速度
harmonic.mbt 平衡潮角、结点改正和潮高计算
station.mbt 站点模型与示例站点
noaa.mbt NOAA 数据接入、误差统计和验证报告
extreme.mbt 高低潮查找
analysis.mbt 潮汐状态、速率、统计和时间窗
planner.mbt 活动评分和推荐计划
exporter.mbt CSV、ICS 和 Markdown 导出
validation.mbt 站点与参数校验
station_search.mbt 距离计算、站点检索和质量评分
solar.mbt 日出日落近似
activity.mbt 活动推荐规则
render.mbt Markdown、JSON 和 ASCII 曲线
moontide.mbt 高层预测接口
cmd/moontide/ CLI 入口
validation/ New York 与 Boston 的 NOAA 离线验证数据pub struct ActivityPlan {
activity : String
windows : Array[ScoredWindow]
note : String
} derive(Debug)pub struct Harmonic {
constituent : Constituent
amplitude : Double
phase_lag : Double
} derive(Debug)pub struct TideStats {
min_height : Double
max_height : Double
mean_height : Double
range : Double
max_flood_rate : Double
max_ebb_rate : Double
rising_fraction : Double
} derive(Debug)pub struct ValidationStats {
sample_count : Int
bias : Double
mean_absolute_error : Double
root_mean_square_error : Double
max_absolute_error : Double
tolerance : Double
passed : Bool
} derive(Debug)fn beach_plan(extremes : Array[TideExtreme], sunrise : Double, sunset : Double, tz : Double, range : Double) -> ActivityPlanfn birding_plan(extremes : Array[TideExtreme], sunrise : Double, sunset : Double, tz : Double) -> ActivityPlanfn catalog_size() -> Intfn compare_with_reference(station : Station, references : Array[ReferencePrediction], tolerance : Double) -> ValidationStats?fn coordinate_label(lat : Double, lon : Double) -> Stringfn distance_km(lat1 : Double, lon1 : Double, lat2 : Double, lon2 : Double) -> Doublefn find_extremes(station : Station, start_jd : Double, duration_hours : Double, step_hours : Double) -> Array[TideExtreme]fn find_next_extreme(station : Station, jd : Double, horizon_hours : Double, step_hours : Double) -> TideExtreme?fn fishing_activity_plan(extremes : Array[TideExtreme], sunrise : Double, sunset : Double, tz : Double, station : Station) -> ActivityPlanfn format_local_datetime(jd : Double, tz_offset : Double) -> Stringfn format_local_time(jd : Double, tz_offset : Double) -> Stringfn high_water_windows(extremes : Array[TideExtreme], before_hours : Double, after_hours : Double) -> Array[TideWindow]fn is_neap(tidal_range : Double, mean_range : Double) -> Boolfn is_spring(tidal_range : Double, mean_range : Double) -> Boolfn jd_to_calendar(jd : Double) -> (Int, Int, Int, Double)fn julian_day_utc(year : Int, month : Int, day : Int, utc_hour : Double) -> Doublefn local_hour_of(jd : Double, tz_offset : Double) -> Doublefn low_water_windows(extremes : Array[TideExtreme], before_hours : Double, after_hours : Double) -> Array[TideWindow]fn nearest_station_summary(lat : Double, lon : Double) -> Stringfn predict_on(station : Station, date : String, tz : Double, duration_hours : Double) -> Prediction?fn recommend(extremes : Array[TideExtreme], sunrise : Double, sunset : Double, tz : Double) -> Array[Activity]fn render_curve(station : Station, start_jd : Double, duration_hours : Double, step_hours : Double, tz : Double) -> Stringfn sample_series(station : Station, start_jd : Double, duration_hours : Double, step_hours : Double) -> Array[TideSample]fn score_fishing_window(window : TideWindow, sunrise : Double, sunset : Double, tz : Double, flood_rate : Double) -> Doublefn score_low_tide_window(window : TideWindow, sunrise : Double, sunset : Double, tz : Double, height_span : Double) -> Doublefn solar_declination(day_of_year : Int) -> Doublefn sunrise_sunset(lat_degrees : Double, day_of_year : Int) -> (Double, Double)?fn tide_coefficient(tidal_range : Double, mean_range : Double) -> Doublefn window_around(extreme : TideExtreme, before_hours : Double, after_hours : Double, label : String) -> TideWindowInstall
Download zipLocal-first tidal prediction with multi-station NOAA validation, written in MoonBit.