Difference Equation Analyzer
Difference Equation Analyzer 是用來設計、檢視與驗證離散時間濾波器的工具。它同時支援浮點係數、fixed-point 係數、時域 CSV 驗證,以及透過 Web Serial 將係數寫入 MCU。
Backend 使用 FastAPI、NumPy、SciPy 與 Pandas;Frontend 使用 Vue 3、Vite、Tailwind CSS 與 Plotly。
Features
- 設計 Lowpass、Highpass、Bandpass、Notch、1P1Z、2P1Z、2P2Z、PID、SOGI 濾波器。
- 比較 Ideal Float 與 Fixed-Point 的 Bode 頻率響應。
- 支援多個 cascade stages 的頻率響應與時域模擬,並可個別啟用或 bypass。
- 手動微調 b/a 係數、a1/a2、δ/r、Q-format 位元數與 fixed-point 整數係數。
- 上傳 CSV 時域資料,繪製輸入、Ideal Float 輸出與 Mimic Integer 輸出。
- 匯出包含理想浮點與定點整數模擬輸出的 CSV;cascade workflow 可匯出乾淨的 4 欄 CSV。
- 使用瀏覽器 Web Serial API 將 fixed-point 係數寫入 MCU。
- 時域圖表支援 zoom 後以
start_idx/end_idx向後端重取可視區間資料,保留 IIR 完整歷史狀態。 - 支援 Dark Mode 與響應式 UI。
Quick Start
cd /home/wisetop/diff-eq-analyzer
python3 -m venv .venv
.venv/bin/pip install -r requirements.txt
npm install
npm run build
bash certs/generate_cert.sh
.venv/bin/uvicorn dea_api:app --host 0.0.0.0 --port 8000 --ssl-keyfile certs/key.pem --ssl-certfile certs/cert.pem
開啟:
https://192.168.2.58:8000/ui/
本專案固定從 FastAPI 提供的 HTTPS UI 使用。不要用 Vite dev server URL 測試 CSV 或 MCU 功能,否則 /api/... 可能會回 Not Found。
自簽憑證會讓瀏覽器顯示安全性警告,第一次開啟時需手動信任或選擇繼續前往。
Project Layout
dea_api.py FastAPI 入口與 HTTP route
dea/ 後端核心模組
bode.py 頻率響應計算
config.py 限制值與伺服器端 serial 設定
csv_processing.py CSV 快取、驗證、單濾波器/cascade 濾波與匯出
filter_design.py 濾波器設計
mcu.py MCU serial port 列表與命令寫入
schemas.py Pydantic request schema
security.py LAN 存取限制與安全標頭
validation.py 係數、頻率與有限值驗證
src/ Vue 3 前端原始碼
certs/ HTTPS 自簽憑證與產生腳本
static/build/ Vite production build 輸出
tests/ unittest 測試
dea.service systemd service 範例
chirp_signal.csv CSV 上傳測試範例
Architecture
| Layer | Responsibility |
|---|---|
| FastAPI | 提供 API、serve /ui/、套用 LAN 存取限制與安全標頭 |
dea/ |
濾波器設計、單濾波器/cascade Bode plot、CSV 處理、fixed-point simulation、驗證 |
| Vue UI | 管理係數、Q-format、CSV workflow、Plotly 圖表與 Web Serial 狀態 |
| Vite build | 將 src/ 打包到 static/build/,由 FastAPI 在 production 提供 |
CSV workflow:
- 前端選擇 CSV。
- 前端只讀取檔案前段內容建立欄位與 preview,避免為了 preview 把大型 CSV 全部載入瀏覽器記憶體。
- 前端呼叫
POST /api/csv/upload,後端將檔案暫存並回傳file_id。 - 上傳完成前,filter 按鈕會保持 disabled,避免尚未取得
file_id就送出處理。 - 後續
POST /api/filter與POST /api/filter/download使用file_id,避免反覆傳大檔。
CSV 預設暫存在:
/tmp/diff-eq-analyzer-csv/
可用環境變數覆寫:
DEA_TEMP_CSV_DIR=/path/to/csv-cache
暫存 CSV 預設保留 24 小時。可用環境變數調整,設為 0 可停用清理:
DEA_TEMP_CSV_TTL_SECONDS=86400
Usage
Filter Design
在左側控制面板選擇濾波器類型並調整參數。系統會更新 b/a 係數,並繪製 Ideal Float 與 Fixed-Point 的頻率響應。
支援濾波器:
Lowpass, Highpass, Bandpass, Notch,
1P1Z, 2P1Z, 2P2Z,
PID, SOGI-Alpha, SOGI-Beta
a1/a2 Fine Tuning
針對二階濾波器,UI 支援 δ/r 參數化微調。
| Mode | Formula |
|---|---|
| Float | a1 = -1 - r, a2 = r + δ |
| Fixed | a1 = -a0 - r, a2 = r + δ |
反推關係:
| Mode | δ | r |
|---|---|---|
| Float | a1 + a2 + 1 |
-1 - a1 |
| Fixed | a1 + a2 + a0 |
-a0 - a1 |
桌機可用 Shift + 滑鼠滾輪微調;觸控裝置可按住數值面板上下拖曳。
Cascade Stages
UI 以 cascade stage accordion 管理多段濾波器。每個 stage 顯示序號、濾波器型態、Active/Bypass 狀態、係數摘要與 Q-format 摘要;可用上移/下移調整串接順序。
完整的濾波器設計、浮點係數、fixed-point 係數與 MCU 寫值控制只會出現在目前選取的 active stage accordion 內。同時間只有一個 active stage 承載完整 editor,避免多份表單同時修改同一組全域 active-stage state。展開非 active stage 時,UI 會先切換該 stage 為 active stage。
送出 Bode 或 CSV 時,前端會先同步目前 active stage,再把所有 stages 依畫面順序打包送到後端。單一 stage 時仍等同 legacy 單濾波器 workflow。
後端相容兩種路徑:
| Mode | API Behavior |
|---|---|
| Legacy single filter | /api/bode、/api/bode/compare、/api/filter 仍接受原本的 b/a/b_int/a_int 參數 |
| Cascade | /api/bode/compare_cascade 接受 stages;/api/filter 與 /api/filter/download 可接受 stages form payload |
Cascade 設計刻意不直接 merge origin/cascadedfilters 的整包檔案,而是在 main 上重作功能,避免帶入大型 CSV、暫存檔、log、舊文件與 build noise。
Fixed-Point Time Simulation
時域分析同時計算兩條路徑:
| Path | Description |
|---|---|
| Ideal Float | 使用 SciPy signal.lfilter() 作為理想浮點參考 |
| Mimic Integer | 將輸入與係數量化為整數,模擬 MCU / DSP fixed-point 差分方程 |
Q-format 參數:
| Parameter | Meaning |
|---|---|
shift_in |
輸入訊號量化位元數 |
shift_out |
輸出訊號量化位元數 |
shift_b |
前饋 b 係數量化位元數 |
shift_a |
回授 a 係數量化位元數 |
use_round |
右移時使用 Floor (SRA) 或 Round (+0.5) |
整數模擬採高精度狀態變數架構:前饋項保留在 Q_in+b 精度,回授項除以 A0 對齊,再於最終輸出依 Q_out 縮放。
Time-Domain LOD Zoom
時域圖表使用 Plotly zoom / pan 時,前端會把目前可視時間範圍換算成 sample index,透過 /api/filter 傳送 start_idx 與 end_idx。後端仍先用完整訊號計算 IIR 輸出,保留濾波器歷史狀態正確性,再只切出可視區間並 downsample 回傳,避免 zoom in 後只能看到粗略的全域降採樣資料。
時間軸單位會在首次完整載入時鎖定為 s、ms 或 μs,避免 zoom 後重新換單位造成 Plotly uirevision 座標錯位。前端也使用 isRedrawingTimePlot 避免 Plotly.react() 觸發 relayout callback 造成重繪迴圈。
CSV Workflow
限制與行為:
| Item | Value |
|---|---|
| 檔案大小上限 | 300 MB |
| 時域運算列數上限 | 1,200,000 rows |
| 圖表點數上限 | 5000 points |
| 格式要求 | 必須有標題列與至少一筆資料 |
若第一欄像 time、t、sec、x、index,前端會預設選第二欄作為訊號欄位。
首頁會自動嘗試載入 .scratch/examples/preset_signals.csv 作為 preset waveform;若檔案不存在,UI 仍可正常手動上傳 CSV。preset 路徑可用環境變數覆寫:
DEA_PRESET_CSV_PATH=/path/to/preset_signals.csv
範例 CSV 不再放在 Git 追蹤路徑。大型範例請放在本機 ignored 目錄:
.scratch/examples/
常用範例欄位格式:
time,value
可從歷史 commit 匯出範例到本機 ignored 路徑使用:
mkdir -p .scratch/examples
git show 075f20d:chirp_signal.csv > .scratch/examples/chirp_signal.csv
git show 0140b049:chirp_signal_small_s.csv > .scratch/examples/chirp_signal_small_s.csv
git show 0140b049:step_signal.csv > .scratch/examples/step_signal.csv
git show 8caa8918:static/preset_signals.csv > .scratch/examples/preset_signals.csv
.scratch/ 已被 .gitignore 忽略,適合放大型 CSV、手動測試資料與暫存分析檔。
CSV Export
/api/filter/download 預設保留 legacy 行為:輸出原始 CSV 欄位,並新增 [欄位]_filtered_ideal 與 [欄位]_filtered_fixed。
若前端傳送 compact=true,後端會輸出專供分析用的 4 欄 CSV:
| Column | Meaning |
|---|---|
Time (s) |
由 sample index 與前端傳入的 fs 計算 |
| 原輸入欄位 | 選定訊號欄位原始值 |
[欄位]_filtered_ideal |
Ideal Float 輸出 |
[欄位]_filtered_fixed |
Mimic Integer / fixed-point 輸出 |
MCU Web Serial
Web Serial 是主要 MCU 寫入方式,伺服器不需要 serial 權限。
| Action | Description |
|---|---|
| 連線 | 點擊「選擇連接埠並連線」,在瀏覽器彈窗選擇 MCU |
| 寫值 | 點擊「寫值到 MCU」 |
| 限制 | Chrome / Edge,且必須透過 HTTPS 或 localhost |
寫入命令格式:
bodeplot=b0,b1,b2,a1,a2
API
| Method | Endpoint | Purpose |
|---|---|---|
POST |
/api/design |
依濾波器參數產生 b/a 係數 |
POST |
/api/bode |
計算單組 b/a 頻率響應 |
POST |
/api/bode/compare |
比較單一濾波器 Ideal Float 與 Fixed-Point 頻率響應 |
POST |
/api/bode/compare_cascade |
比較 cascade stages 的 Ideal Float 與 Fixed-Point 頻率響應 |
GET |
/api/csv/preset |
讀取本機 ignored preset CSV metadata,供首頁自動載入 |
POST |
/api/csv/upload |
上傳 CSV 並回傳 file_id |
POST |
/api/filter |
使用 file_id 回傳單濾波器或 cascade 時域圖表資料;可傳 start_idx/end_idx 做 LOD zoom |
POST |
/api/filter/download |
使用 file_id 匯出結果 CSV;可傳 compact=true 匯出 4 欄 CSV |
GET |
/api/mcu/ports |
列出伺服器端 serial ports |
POST |
/api/mcu/write |
後端模式寫入 MCU 命令 |
Development
Frontend
npm install
npm run test:frontend
npm run build
開發模式:
npm run dev
CSV 與 API 流程保留 dev-v2 的兩段式設計:先 upload 取得 file_id,再用 file_id filter 或 download。vite.config.js 仍保留 main 的 HTTPS deployment 設定,不在 Vite 內設定 /api proxy。因此 npm run dev 只適合檢查前端畫面;CSV upload、filter API、MCU API 請固定使用:
https://192.168.2.58:8000/ui/
Backend
.venv/bin/pip install -r requirements.txt
.venv/bin/uvicorn dea_api:app --host 0.0.0.0 --port 8000 --ssl-keyfile certs/key.pem --ssl-certfile certs/cert.pem
HTTPS Certificate
bash certs/generate_cert.sh
會在 certs/ 產生:
cert.pem
key.pem
systemd
sudo cp dea.service /etc/systemd/system/
sudo systemctl daemon-reload
sudo systemctl enable dea.service
sudo systemctl start dea.service
查看狀態:
sudo systemctl status dea.service
sudo journalctl -u dea.service -f
Backend Serial Fallback
若無法使用 Web Serial,可改用後端 serial API。環境變數:
MCU_SERIAL_PORT=/dev/ttyUSB2
MCU_BAUD_RATE=115200
MCU_WRITE_TIMEOUT=1.0
systemd 可在 [Service] 加入:
Environment="MCU_SERIAL_PORT=/dev/ttyUSB2"
Environment="MCU_BAUD_RATE=115200"
Environment="MCU_WRITE_TIMEOUT=1.0"
Testing
Python syntax check:
.venv/bin/python -m py_compile dea_api.py tests/test_dea_api.py
Backend tests 使用 Python 內建 unittest:
.venv/bin/python -m unittest discover -s tests
Frontend build check:
npm run build
建議完整驗證:
.venv/bin/pip install -r requirements.txt
.venv/bin/python -m unittest discover -s tests
npm run build
sudo systemctl restart dea.service
Security And Limits
| Item | Value |
|---|---|
| Network access | 只允許 private / loopback IP |
| CSV size | 300 MB |
| Time-domain rows | 1,200,000 rows |
| Plot points | 5000 points |
| Coefficients | 最多 64 個 |
HTTP responses 會加上 CSP、Referrer-Policy、X-Content-Type-Options: nosniff、X-Frame-Options: DENY。
Troubleshooting
CSV 上傳顯示 Not Found
請確認目前網址是:
https://192.168.2.58:8000/ui/
如果從 http://localhost:5173 或其他 Vite dev server URL 開啟,/api/csv/upload 會送到前端 dev server,而不是 FastAPI,因此會回 Not Found。
無法連線 MCU
- 確認使用
https://192.168.2.58:8000/ui/。 - 確認瀏覽器支援 Web Serial API。
- 使用 Chrome 或 Edge。
- 檢查 USB 線與 MCU 裝置狀態。
頁面沒有更新
- 執行
npm run build。 - 重啟服務:
sudo systemctl restart dea.service。 - 瀏覽器按
Ctrl+F5強制重新整理。
systemd 顯示 status=203/EXEC
通常是 .venv 或 uvicorn 路徑不正確。可重建 venv:
rm -rf .venv
python3 -m venv .venv
.venv/bin/pip install -r requirements.txt
sudo systemctl restart dea.service
找不到 pytest
本專案不使用 pytest。請改用:
.venv/bin/python -m unittest discover -s tests