跳到主要內容
WaterMirror
語言: 繁體中文
GitHub

用五項水質指標,讀懂一條河的水質。

WaterMirror 把溶氧、生化需氧量、氨氮、導電度與懸浮固體換算成 WQI5 分數、水質等級,以及每項指標的狀態。你可以使用 Android App、呼叫開放 API,或把整套服務跑在 Jetson Nano 上。

  • Android App 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

App 能做什麼

  • 手動輸入或上傳 CSV

    逐筆輸入五項數值,或上傳表頭為 DO,BOD,NH3N,EC,SS 的 CSV,一次評估多筆資料。

  • 選擇計算方式

    直接用 WQI5 公式計算,或改用六種訓練好的模型比較:線性回歸、多項式回歸、SVM、隨機森林、XGBoost、LightGBM。

  • 看懂分數代表什麼

    報表列出分數、等級與分數區間、各指標的評等、這筆資料在參考資料中的百分位,以及輸入警示。

  • 連到自己的伺服器

    在「後端設定」輸入後端位址,送出資料前先測試健康與就緒狀態;位址會儲存在手機上。

  • 支援四種語言

    英文、繁體中文、簡體中文與日文。

資料輸入畫面,展開模型清單
後端設定畫面與伺服器位址

一筆資料如何變成分數

  1. 1

    量測

    在採樣點取得 DO、BOD、NH₃-N、EC 與 SS。

  2. 2

    送出

    App 把數值送到 WQSurrogateModels API 的 /api/v2/assessment。

  3. 3

    評估

    API 檢查輸入後,用公式或你選的模型計算 WQI5。

  4. 4

    判讀

    App 顯示 API 回傳的分數、等級、分數區間、各指標狀態與警示。

WQI5 公式

每項指標先換算成 0 到 100 的子指數,WQI5 是五個子指數的等權平均,取到小數點後三位。

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

查看子指數換算式

App 本身不計算分數,一律以 API 的結果為準,所以每個用戶端拿到的答案都一樣。

系統架構

WaterMirror App

以 Expo 與 React Native 開發的 Android App

HTTP,/api/v2

WQSurrogateModels API

FastAPI 服務,提供公式與訓練好的模型

pip 或 Docker

API 的執行環境

一般 x86 伺服器或電腦

以 Docker 執行的 Jetson Nano 2GB(ARM64)

六個等級,各有適用用途

API 會把每個分數歸入六個等級之一,App 再說明該等級的水適合哪些用途。

WQI5 等級、分數區間與適用用途
優良85 < WQI5 ≤ 100可做各種用途,加氯消毒後可直接飲用。
良好70 < WQI5 ≤ 85可作為自來水水源,以及水產、工業、遊憩與灌溉用水。
中等50 < WQI5 ≤ 70經特別處理後可作為自來水水源;可養殖粗魚,並供工業、遊憩與灌溉用水。
不良30 < WQI5 ≤ 50僅適合灌溉或工業冷卻。
糟糕15 < WQI5 ≤ 30不會引起厭惡,可作環境保育用途。
惡劣0 ≤ WQI5 ≤ 15可能產生臭味。

公式是基準,模型用來比較

五項指標齊全時,預設且作為基準的是 WQI5 公式。另外訓練了六種回歸模型來近似公式,用來比較準確度與運算成本,也用在缺少指標的實驗情境。

五項指標齊全時的平均絕對誤差(越低越好)
模型MAER²
XGBoost0.2640.9996
LightGBM0.2880.9995
Random Forest0.3380.9990
SVM1.9160.9813
Polynomial regression5.1600.8995
Linear regression7.5560.7803

為五次重複切分的平均。誤差是對資料集的 Score 欄位計算;公式本身與該欄位也有差距(MAE 6.07),原因仍在調查,因此模型誤差較低不代表比公式更正確。

研究資料集與訓練好的模型檔不隨專案公開。公式可以直接使用;模型需自行在本機提供。

查看模型卡

少了一項指標時

公式需要五項指標齊全,但 BOD 要做五天的實驗室檢驗,氨氮通常也要送實驗室分析,現場資料常常不完整。研究測試了兩種補救方式:只用手上的指標重新訓練模型,或先用其他指標把缺的那一項補回來再評分。兩種方式都在 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 代表比一律猜平均分數還差。

氨氮可以從其他四項指標估回來,誤差約 2.4 分;BOD 不行,少了它誤差會升到 12 到 15 分,所以 BOD 是一定要量的指標。

以上為研究結果;目前 App 與 API 只對五項指標齊全的資料評分。

查看缺值實驗說明

在 2 GB 的 Jetson Nano 上實測

同一套 API 以 Docker 跑在 Jetson Nano 2GB(四核 Cortex-A57)上,只用 CPU 推論,模型訓練不在裝置上進行。

Nano 上的單筆請求回應時間
計算方式第 95 百分位中位數
Direct WQI57.42 ms6.41 ms
XGBoost17.42 ms15.52 ms
LightGBM17.57 ms15.67 ms
Random Forest163.81 ms146.90 ms

暖機後的單筆 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 棵樹的版本檔案小了三分之一,誤差只多 0.33%,在完整確認實驗之前仍維持候選。

查看完整實測報告

開始使用

安裝 App

下載 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 用戶端都能呼叫 App 使用的同一個端點。

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 文件