Python 環境與模擬程式庫 Python Environment
See also:notation(函式參數對應的符號)、各模擬 lab 頁(如 lab_01)會引用這裡的
common/函式|跑全部圖:python scripts/run_all_sims.py
本站所有圖都是用 Python 的教學用 toy model(pedagogical toy model,非 transistor-level)
跑出來的。這頁告訴你:怎麼把環境建起來、目錄長什麼樣、一鍵重跑全部圖、以及 common/
裡每個模組與函式在做什麼。所有函式名稱都對應真實存在的程式碼,可以直接 import 來驗算。
設計哲學:模擬不是為了「像真電路」,而是為了把公式變成可以動手摸的數字與圖。 每個 lab 都把一條 ISF 公式拆成最小可跑的程式,固定亂數種子讓結果完全可重現。
1. 建環境
需要 Python 3.12,三個套件即可:
# 建議用虛擬環境
# python3.12 -m venv .venv && source .venv/bin/activate
# 然後安裝:
# pip install numpy scipy matplotlib
| 套件 | 版本建議 | 用途 |
|---|---|---|
numpy | 1.26+ | 向量化數值運算、FFT、亂數 |
scipy | 1.11+ | scipy.signal.welch(PSD 估計)、積分、插值 |
matplotlib | 3.8+ | 出圖到 static/figures/ |
為什麼只要三個套件:刻意保持最小相依,讓任何人都能在乾淨的 Python 3.12 上一行裝完、 一鍵重現所有圖。沒有用到深度學習框架或電路模擬器(SPICE 等)——再次強調,這是 toy model。
2. CJK 字型(Heiti TC)
圖上有中文標籤(軸名、圖例),matplotlib 預設字型不含中文會出現「豆腐方塊」。本站在 macOS 上 用系統內建的 Heiti TC(黑體-繁):
import matplotlib.pyplot as plt
plt.rcParams["font.family"] = "Heiti TC" # 繁體中文字型 (macOS 內建)
plt.rcParams["axes.unicode_minus"] = False # 避免負號變方塊
axes.unicode_minus=False很關鍵:matplotlib 預設用 Unicode 減號 U+2212,很多字型缺這個 glyph,會讓「 dBc/Hz」的負號變方塊;設成False改用 ASCII 連字號就正常。- 非 macOS 平台:把
"Heiti TC"換成系統有的 CJK 字型(如 Linux 的"Noto Sans CJK TC"、 Windows 的"Microsoft JhengHei")。TODO: manual verification needed—— 跨平台字型名稱請依 實際系統fc-list結果調整。
3. 目錄結構
# simulations/
# common/
# isf_utils.py # ISF 形狀、傅立葉、impulse->phase
# noise_utils.py # 噪訊產生、PSD、jitter 積分、dBc/Hz
# oscillator_models.py # toy 振盪器、ISF 萃取、ring edge times
# lab_01_sinusoidal_oscillator.py
# lab_02_lc_oscillator_isf.py
# lab_03_ring_oscillator_toy_model.py
# lab_04_impulse_injection_sweep.py
# lab_05_fourier_decomposition.py
# lab_06_white_noise_phase_noise.py
# lab_07_flicker_upconversion.py
# lab_08_jitter_integration.py
# scripts/
# run_all_sims.py # 一鍵重跑全部 lab,產生所有圖
# static/figures/ # 產出的 .png(網站用 /figures/<name>.png 引用)
common/放可重用的核心函式,三個 lab 共用;各 lab 只負責「擺參數、呼叫 common、出圖」。 這樣公式只實作一次,任何 lab 改參數都用同一份權威實作。- 圖的輸出一律落在
static/figures/,網站頁面用引用 (見 [authoring spec 第 4 節] 的圖表清單)。
4. 一鍵重跑全部圖
# 在專案根目錄執行:
# python scripts/run_all_sims.py
scripts/run_all_sims.py 會依序跑 lab_01 ~ lab_08 的 main() / fig_*(),把全部 14 張 PNG
重新產生到 static/figures/。要重現網站上的任何一張圖,這一行就夠。各圖對應的 script 與函式:
| 圖檔 | script | function |
|---|---|---|
limit_cycle_phase_amplitude.png | lab_01_sinusoidal_oscillator.py | fig_limit_cycle |
waveform_with_impulse_markers.png | lab_01_sinusoidal_oscillator.py | fig_impulse_markers |
lc_waveform_and_isf.png | lab_02_lc_oscillator_isf.py | main |
ring_oscillator_timing_noise_accumulation.png | lab_03_ring_oscillator_toy_model.py | fig_accumulation |
lc_vs_ring_isf_comparison.png | lab_03_ring_oscillator_toy_model.py | fig_lc_vs_ring_isf |
sinusoidal_impulse_phase_sweep.png | lab_04_impulse_injection_sweep.py | fig_isf_sweep |
isf_impulse_sweep_sinusoidal.png | lab_04_impulse_injection_sweep.py | fig_isf_sweep |
lti_vs_ltv_impulse_response.png | lab_04_impulse_injection_sweep.py | fig_lti_vs_ltv |
isf_fourier_reconstruction.png | lab_05_fourier_decomposition.py | fig_reconstruction |
isf_fourier_coefficients.png | lab_05_fourier_decomposition.py | fig_coefficients |
symmetric_vs_asymmetric_isf_c0.png | lab_05_fourier_decomposition.py | fig_symmetric_vs_asymmetric |
white_noise_phase_noise_psd.png | lab_06_white_noise_phase_noise.py | main |
flicker_upconversion_symmetric_vs_asymmetric.png | lab_07_flicker_upconversion.py | main |
phase_noise_to_jitter_integration.png | lab_08_jitter_integration.py | main |
5. common/ 模組與函式一覽
以下函式名稱與簽名取自作者規範第 5 節,是真實存在的 API,請勿杜撰其他函式。
5.1 simulations/common/isf_utils.py —— ISF 的形狀與相位轉換
| 函式 | 做什麼 | 對應公式 |
|---|---|---|
wrap_phase | 把相位包進 或 | — |
gamma_symmetric | 對稱波形的 ISF() | [P1] Eq.(12) |
gamma_asymmetric(alpha) | 不對稱 ISF(, 控制不對稱度 ) | flicker upconversion |
gamma_lc_ideal | 理想 LC 的 ISF | |
gamma_triangular(n_stages) | ring 的三角形 ISF(敏感度集中在 transition) | [P2] Fig. 5 |
impulse_to_phase_step(dq, gamma, qmax) | [P1] Eq.(10)/(11) | |
integrate_phase_from_noise(t, i, gamma_vals, qmax) | 把 noise 電流積分成相位 | [P1] Eq.(11) |
apply_isf_weighting(t, i, gamma_func, qmax, omega0) | 對 noise 乘上 的權重 | [P1] Eq.(11) |
compute_fourier_coefficients(theta, gamma, n_harmonics) | 回傳 (a0, a, b, c, phase) | [P1] Eq.(12) |
reconstruct_from_fourier | 由 重建 | [P1] Eq.(12) |
gamma_rms(theta, gamma) | 數值算 | [P1] Eq.(20) |
effective_isf(gamma, alpha) | (cyclostationary) | [P1] cyclostationary 節 |
對應頁:isf_definition、 fourier_series_of_isf、 effective_isf。
5.2 simulations/common/noise_utils.py —— 噪訊、PSD、jitter
| 函式 | 做什麼 | 對應公式 |
|---|---|---|
white_noise(n, psd, fs, rng) | 產生白噪序列(指定單邊 PSD) | |
flicker_noise(n, fs, k_flicker, ...) | 產生 flicker 噪訊 | [P1] Eq.(22) |
estimate_psd(x, fs, nperseg) | 用 Welch 法估 PSD | Wiener–Khinchin |
phase_psd_to_l_dbc_per_hz(s_phi) | ||
phase_to_time_error(phi, f0) | spec Eq.(17) | |
integrate_rms_jitter(f, l_dbc, f0, fmin, fmax) | 回傳 (sigma_t, sigma_phi) | spec Eq.(18)/(19) |
leeson_one_over_f2(f, Lref, fref) | 產生 skirt 形狀 | Leeson(對照用) |
對應頁:psd_phase_noise_jitter、 white_noise_to_phase_noise、 numerical_feeling。
5.3 simulations/common/oscillator_models.py —— toy 振盪器與 ISF 萃取
| 函式 | 做什麼 | 對應頁 |
|---|---|---|
sinusoidal_oscillator | 最簡正弦振盪器(建立 limit cycle 直覺) | lab_01 |
simulate_lc(...) | toy LC 振盪器 state-space 模擬 | lab_02 |
excess_phase | 從波形萃取 excess phase | [P1] Eq.(1) |
extract_isf_by_injection(...) | 在不同相位注入小電荷、量相位跳變,反推 ISF | lab_04 |
ring_edge_times | 算 ring 各 edge 的時刻 | lab_03 |
accumulated_jitter_curve | 產生 vs 曲線 | [P2] Eq.(8) |
phase_to_time | 相位 → 時間(edge 位置) | spec Eq.(17) |
全部都是 toy / 概念模型(toy model,非 transistor-level)。它們重現的是公式的行為與 scaling,不是真實電晶體電路的精確數值。
6. Reproducibility( 固定 rng seed)
所有用到亂數的 lab(白噪、flicker、jitter 累積)都用 NumPy 的新式亂數產生器並固定 seed, 讓任何人重跑都得到逐位元相同的圖:
import numpy as np
rng = np.random.default_rng(seed=12345) # 固定種子 -> 完全可重現
i_n = white_noise(n=2**16, psd=1e-24, fs=fs, rng=rng) # 傳入同一個 rng
- 為什麼用
default_rng(seed)而不是舊的np.random.seed:新式Generator物件式 API 讓亂數狀態顯式傳遞(rng當參數丟進函式),避免全域狀態被別處偷改,是 reproducibility 的 最佳實務。 - 驗證手感:固定 seed 後,lab_08 的數值積分 jitter 會穩定落在解析值 fs、 mrad(canonical 例 C)附近, 與理論完全一致。
- 想看不同實現:改 seed(如
default_rng(1)、default_rng(2))可看 Monte-Carlo 抖動範圍; 但網站上釘住的圖一律用固定 seed。
7. 一行驗算示範(把公式變數字)
把前面的環境串起來,下面這段不需要任何 lab script,只靠 common/ 就能重現 canonical 例 A
( pC、 fC、、 GHz):
from simulations.common.isf_utils import impulse_to_phase_step
from simulations.common.noise_utils import phase_to_time_error
dphi = impulse_to_phase_step(delta_q=1e-15, gamma_value=0.5, qmax=1e-12)
dt = phase_to_time_error(dphi, f0=5e9)
print(dphi, "rad", dt * 1e15, "fs") # -> 0.0005 rad 15.92 fs
得到 rad、 fs,與 impulse_to_phase_shift(例 A)一致。
8. 📓 下載 Jupyter notebooks
七個主線 lab 有對應的 Jupyter notebook(互動式筆記本,可一格一格執行、改參數重跑) 可直接下載,離線把公式玩成數字與圖:
| Notebook(點擊下載 .ipynb) | 內容 | 對應頁面 |
|---|---|---|
| lab_01_sinusoidal_oscillator | limit cycle、phase(切向)vs amplitude(徑向)擾動、impulse 注入時機 | lab_01 |
| lab_05_fourier_isf | ISF 傅立葉係數 、Parseval 驗證、 與對稱性 | lab_05 |
| lab_06_white_noise_phase_noise | 白噪 phase noise 端到端模擬 vs 理論線 | lab_06 |
| lab_08_jitter_integration | 積分成 rms jitter(canonical 例 C) | lab_08 |
| lab_18_lorentzian | 相位 random walk 載波 Lorentzian 線形與 3-dB 線寬 | lorentzian_linewidth |
| lab_22_capstone_lc_end_to_end | 理想 LC 全鏈: 線寬 BER | capstone |
| lab_24_jitter_kernels | TIE/period/cycle-to-cycle 三種 jitter 權重核 + Monte-Carlo 驗證 | jitter_kernels |
怎麼跑:notebook 會 import simulations/common 的模組,所以要先
git clone https://github.com/gmcycle7/isf-teaching-site.git,並把下載的 .ipynb 放在
repo 目錄樹內任何位置執行(每本 notebook 的 setup cell 會自動往上層目錄尋找
simulations/common 並加入 sys.path)。相依套件同第 1 節的
pip install numpy scipy matplotlib,再加上 pip install jupyter 後用
jupyter lab 開啟即可。
誠實註記:這些 notebook 是
scripts/make_notebooks.py從對應的simulations/lab_*.py自動產生的快照(generated snapshot),不是手寫檔—— 權威版本永遠是 repo 裡的 lab script;lab 更新後執行python scripts/make_notebooks.py會重新產生全部 notebook。 與原 script 只有兩處刻意差異:savefig改成 notebook 內 inline 顯示 (不寫入static/figures/)、路徑設定由 setup cell 自動尋找 repo root (原 script 用__file__定位)。
重點回顧
- Python 3.12 +
numpy/scipy/matplotlib,CJK 用Heiti TC並關閉unicode_minus。 common/三模組(isf_utils、noise_utils、oscillator_models)放權威實作;各 lab 只擺參數。python scripts/run_all_sims.py一鍵重產 14 張圖到static/figures/。- 全部是 toy model;用固定
default_rng(seed)保證逐位元可重現。 - 七個主線 lab 有可下載的 Jupyter notebook(第 8 節),由
scripts/make_notebooks.py自動產生(generated snapshot)。
延伸閱讀
- 數值口算與驗算:numerical_feeling
- 數學工具箱:math_identities
- 詞彙表:glossary
- 公式索引:equation_index