本文へスキップ
WaterMirror
言語: 日本語
GitHub

5 つの測定値から、川の水質を読み解く。

WaterMirror は溶存酸素、BOD、アンモニア態窒素、電気伝導度、浮遊物質から、WQI5 スコアと水質ランク、指標ごとの状態を求めます。Android アプリで使うことも、オープン API を呼び出すことも、サービス全体を Jetson Nano で動かすこともできます。

  • Android アプリ 2.3.7
  • API 2.3.0(PyPI)
  • x86 と ARM64 に対応
WQI5 の量水標。スコア 61.48、ランクは「普通」10085705030150優秀良好不良悪い極めて悪い61.48普通
サンプルの測定値に対する WaterMirror のレポート:WQI5 の式で直接計算した総合評価 61.48(普通)、パーセンタイルのグラフ、参照データにおける各ランクの割合。
DO
溶存酸素
% 飽和度
BOD
生物化学的酸素要求量
mg/L
NH₃-N
アンモニア態窒素
mg/L
EC
電気伝導度
µS/cm
SS
浮遊物質
mg/L

アプリでできること

  • 測定値を入力、または CSV をアップロード

    5 つの値を手入力するか、ヘッダーが DO,BOD,NH3N,EC,SS の CSV をアップロードして、まとめて評価できます。

  • スコアの計算方法を選ぶ

    WQI5 の式で直接計算するか、学習済みの 6 つのモデル(線形回帰、多項式回帰、SVM、ランダムフォレスト、XGBoost、LightGBM)と比較できます。

  • スコアの意味がわかる

    レポートには、スコア、ランクとスコア範囲、指標ごとの評価、参照データの中での位置(パーセンタイル)、入力に関する警告が表示されます。

  • 自分のサーバーにつなぐ

    「バックエンド設定」でバックエンドのアドレスを入力し、データを送る前にヘルスチェックと準備状態を確認できます。アドレスは端末に保存されます。

  • 4 つの言語に対応

    英語、繁体字中国語、簡体字中国語、日本語。

モデル一覧を開いたデータ入力画面
サーバーアドレスを入力したバックエンド設定

測定値がスコアになるまで

  1. 1

    測定

    採水地点で DO、BOD、NH₃-N、EC、SS を測ります。

  2. 2

    送信

    アプリが値を WQSurrogateModels API の /api/v2/assessment に送ります。

  3. 3

    評価

    API が入力を検証し、式または選んだモデルで WQI5 を計算します。

  4. 4

    確認

    API が返したスコア、ランク、スコア範囲、指標ごとの状態、警告をアプリが表示します。

WQI5 の式

各指標を 0〜100 のサブ指数に換算し、5 つのサブ指数を同じ重みで平均したものが WQI5 です。小数点以下 3 桁に丸めます。

WQI5 = (QDO + QBOD + QNH₃-N + QEC + QSS) ÷ 5

サブ指数の換算式を見る

アプリ自体はスコアを計算しません。結果はすべて API が決めるため、どのクライアントでも同じ答えになります。

システム構成

WaterMirror アプリ

Expo と React Native で作った Android アプリ

HTTP、/api/v2

WQSurrogateModels API

式と学習済みモデルを提供する FastAPI サービス

pip または Docker

API の実行環境

一般的な x86 サーバーや PC

Docker で動く Jetson Nano 2GB(ARM64)

6 つのランクと、それぞれの用途

API はすべてのスコアを 6 つのランクのいずれかに分類し、アプリがそのランクの水に適した用途を説明します。

WQI5 のランク、スコア範囲、適した用途
優秀85 < WQI5 ≤ 100あらゆる用途に使えます。塩素消毒すれば飲用できます。
良好70 < WQI5 ≤ 85水道水源のほか、水産、工業、レクリエーション、かんがいに使えます。
普通50 < WQI5 ≤ 70特別な処理をすれば水道水源になります。水質への要求が低い魚の養殖、工業、レクリエーション、かんがいに使えます。
不良30 < WQI5 ≤ 50かんがいや工業用の冷却水にのみ適しています。
悪い15 < WQI5 ≤ 30不快感を与えるほどではなく、環境保全に利用できます。
極めて悪い0 ≤ WQI5 ≤ 15悪臭が発生するおそれがあります。

式が基準。モデルは比較のために。

5 つの測定値がそろっているときは、WQI5 の式が既定の方法であり基準です。式を近似する 6 種類の回帰モデルも学習させ、精度と計算コストを比べられるようにしました。指標が欠けた状況の実験にも使っています。

5 つの入力がそろったときの平均絶対誤差(小さいほど良い)
モデルMAER²
XGBoost0.2640.9996
LightGBM0.2880.9995
Random Forest0.3380.9990
SVM1.9160.9813
Polynomial regression5.1600.8995
Linear regression7.5560.7803

5 回の繰り返し分割の平均です。誤差はデータセットの Score 列に対して計算しています。式そのものも Score 列とずれがあり(MAE 6.07)、原因は調査中です。そのため、モデルの誤差が小さくても、式より正しいとは言えません。

研究用データセットと学習済みモデルのファイルは公開していません。式はそのまま使えますが、モデルはローカルで用意する必要があります。

モデルカードを見る

指標が 1 つ欠けたとき

式は 5 つの測定値がそろわないと使えません。しかし BOD の測定には 5 日間の室内試験が必要で、アンモニア態窒素もふつうは試験室で分析するため、現場のデータは欠けがちです。研究では 2 つの方法を試しました。手元の指標だけでモデルを学習し直す方法と、欠けた指標をほかの指標から先に補ってから評価する方法です。どちらも、学習に使っていない 10,714 件のデータで検証しました。

  • NH₃-N が欠けた場合

    使う指標:DO、BOD、EC、SS

    推定値として使える

    欠けた指標なしで再学習
    MAE 2.37R² 0.95
    ほかの指標から先に補完
    MAE 2.40R² 0.95
  • BOD が欠けた場合

    使う指標:DO、NH₃-N、EC、SS

    信頼できない

    欠けた指標なしで再学習
    MAE 14.12R² −0.02
    ほかの指標から先に補完
    MAE 12.14R² 0.10
  • BOD と NH₃-N が欠けた場合

    使う指標:DO、EC、SS

    信頼できない

    欠けた指標なしで再学習
    MAE 14.72R² −0.14
    ほかの指標から先に補完
    MAE 12.89R² −0.01

MAE は WQI5 のスコア単位で、小さいほど良い値です。R² が 0 未満なら、常に平均値を答えるより悪いことを意味します。

アンモニア態窒素は、ほかの 4 指標から約 2.4 ポイントの誤差で推定できます。BOD はできません。BOD がないと誤差は 12〜15 ポイントに広がるため、BOD は必ず測るべき指標です。

以上は研究結果です。現在のアプリと API は、5 つの指標がそろったデータだけを評価します。

欠測指標の実験について読む

2 GB の Jetson Nano で実機検証

同じ API を Docker で Jetson Nano 2GB(4 コア Cortex-A57)上に載せ、CPU だけで推論しています。モデルの学習はデバイス上では行いません。

Nano での 1 リクエストあたりの応答時間
計算方法95 パーセンタイル中央値
Direct WQI57.42 ms6.41 ms
XGBoost17.42 ms15.52 ms
LightGBM17.57 ms15.67 ms
Random Forest163.81 ms146.90 ms

ウォームアップ後の 1 行ずつの HTTP リクエスト、デバイス内のループバック経由、MAXN 電源モード、各方法 300 回。モデルのコールドロードは別に測定しています。

610 件中 597 件

再実行結果が x86 と一致

実験一式を Nano で再実行し、絶対誤差 1e-6 を基準に x86 と比較しました。一致しなかった 13 件は、いずれも欠測指標を再構成する条件の線形・多項式モデルで、悪条件の係数がごく小さな浮動小数点の差を増幅していました。

2.1.4 → 3.2.0

誤ったスコアを検出

Nano への最初のデプロイでは XGBoost 2.1.4 を使っていました。モデルはエラーなく読み込めたものの、スコアが誤っていました。x86 の参照結果との比較で見つかり、3.2.0 に固定して修正しました。

1.05 GB

最も重いのはランダムフォレスト

これは本番用ランダムフォレストのモデルファイルの大きさです。コールドロードに 168 秒かかり、メモリのピークは 1.2 GiB ですが、デバイスのメモリは 1.9 GiB しかありません。木を 200 本にした版はファイルが 3 分の 1 小さく、誤差の増加は 0.33% でした。完全な確認実験が終わるまでは候補のままです。

ベンチマークの詳細を見る

はじめる

アプリをインストール

APK をダウンロードして「バックエンド設定」を開き、動いている API のアドレス(例:http://192.168.1.20:8001)を入力します。

API を動かす

Python 3.10 以降が必要です。式だけを使う場合、モデルファイルは不要です。

git clone https://github.com/KageRyo/WQSurrogateModels.git
cd WQSurrogateModels
uv sync
uv run python main.py

ランタイムは PyPI でも wqsurrogatemodels として公開しています。

どこからでも呼び出せる

アプリと同じエンドポイントを、どの HTTP クライアントからも呼び出せます。

curl -X POST http://localhost:8001/api/v2/assessment \
  -H "Content-Type: application/json" \
  -d '{"DO":70,"BOD":2,"NH3N":0.3,"EC":400,"SS":10,
       "model_type":"direct_wqi5"}'

{"score": 75.685, "category": "Good",
 "rating_range": "70 < WQI5 ≤ 85", ...}

API リファレンスを見る