Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
|
@@ -2,22 +2,32 @@ import gradio as gr
|
|
| 2 |
import numpy as np
|
| 3 |
import matplotlib.pyplot as plt
|
| 4 |
|
| 5 |
-
# --- 核心計算與繪圖函數 ---
|
| 6 |
-
def
|
| 7 |
"""
|
| 8 |
-
|
| 9 |
-
|
| 10 |
"""
|
| 11 |
# 物理條件檢查:折射必須 V2 > V1
|
| 12 |
if v2 <= v1:
|
| 13 |
fig, ax = plt.subplots(figsize=(10, 6))
|
| 14 |
-
|
| 15 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 16 |
ax.set_xlabel("Distance (m)")
|
| 17 |
ax.set_ylabel("Travel Time (s)")
|
| 18 |
ax.grid(True)
|
| 19 |
-
ax.
|
| 20 |
-
|
|
|
|
|
|
|
| 21 |
|
| 22 |
# 1. 計算關鍵物理量
|
| 23 |
theta_c_rad = np.arcsin(v1 / v2)
|
|
@@ -29,14 +39,15 @@ def plot_seismic_refraction(v1, v2, h, x_max):
|
|
| 29 |
x = np.linspace(0, x_max, 500)
|
| 30 |
t_direct = x / v1
|
| 31 |
t_refracted = (x / v2) + ti
|
| 32 |
-
|
|
|
|
| 33 |
|
| 34 |
-
# 3. 使用 Matplotlib 繪圖
|
| 35 |
fig, ax = plt.subplots(figsize=(10, 6))
|
| 36 |
|
| 37 |
-
# --- 英文圖例標籤修改處 ---
|
| 38 |
ax.plot(x, t_direct, 'b--', label=f'Direct Wave (Slope 1/{v1:.0f})')
|
| 39 |
ax.plot(x, t_refracted, 'g--', label=f'Refracted Wave (Slope 1/{v2:.0f})')
|
|
|
|
| 40 |
ax.plot(x, t_first_arrival, 'r-', linewidth=3, label='First Arrival')
|
| 41 |
|
| 42 |
if xc < x_max:
|
|
@@ -45,49 +56,59 @@ def plot_seismic_refraction(v1, v2, h, x_max):
|
|
| 45 |
|
| 46 |
ax.plot(0, ti, 'mo', markersize=8, label=f'Intercept Time = {ti*1000:.1f} ms')
|
| 47 |
|
| 48 |
-
|
| 49 |
-
ax.set_title("Interactive Seismic Refraction T-X Plot", fontsize=16)
|
| 50 |
ax.set_xlabel("Distance (m)", fontsize=12)
|
| 51 |
ax.set_ylabel("Travel Time (s)", fontsize=12)
|
| 52 |
|
| 53 |
ax.legend()
|
| 54 |
ax.grid(True)
|
| 55 |
ax.set_xlim(0, x_max)
|
| 56 |
-
|
|
|
|
|
|
|
| 57 |
plt.tight_layout()
|
| 58 |
|
| 59 |
-
# 4. 準備輸出的說明文字
|
| 60 |
results_md = f"""
|
| 61 |
### 🔬 分析結果
|
| 62 |
|
| 63 |
根據您設定的參數,我們計算出以下關鍵物理量:
|
| 64 |
|
| 65 |
-
-
|
| 66 |
-
- 公式:
|
| 67 |
-
-
|
| 68 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 69 |
|
| 70 |
-
|
| 71 |
-
|
| 72 |
-
|
| 73 |
-
|
| 74 |
|
| 75 |
- **交越距離 (Crossover Distance, Xc)**:
|
| 76 |
- 公式: `Xc = 2 * h * sqrt((V2 + V1) / (V2 - V1))`
|
| 77 |
- 計算: `2 * {h:.0f} * sqrt(({v2:.0f} + {v1:.0f}) / ({v2:.0f} - {v1:.0f}))` = **{xc:.1f} m**
|
| 78 |
-
-
|
| 79 |
"""
|
| 80 |
|
| 81 |
return fig, results_md
|
| 82 |
|
| 83 |
-
# --- Gradio 介面設定 (
|
| 84 |
with gr.Blocks(theme=gr.themes.Soft()) as demo:
|
| 85 |
-
gr.Markdown("#
|
| 86 |
gr.Markdown(
|
| 87 |
"""
|
| 88 |
-
|
| 89 |
-
|
| 90 |
-
|
| 91 |
"""
|
| 92 |
)
|
| 93 |
|
|
@@ -110,7 +131,7 @@ with gr.Blocks(theme=gr.themes.Soft()) as demo:
|
|
| 110 |
|
| 111 |
# --- 事件監聽 ---
|
| 112 |
submit_btn.click(
|
| 113 |
-
fn=
|
| 114 |
inputs=[v1_slider, v2_slider, h_slider, xmax_slider],
|
| 115 |
outputs=[plot_output, results_output]
|
| 116 |
)
|
|
@@ -119,10 +140,11 @@ with gr.Blocks(theme=gr.themes.Soft()) as demo:
|
|
| 119 |
"""
|
| 120 |
---
|
| 121 |
### 學習重點
|
| 122 |
-
1. **觀察斜率**: 直達波的斜率是 `1/V1`,折射波的斜率是 `1/V2`。試著調整 `V1` 和 `V2`,看看線條的陡峭程度如何變化?
|
| 123 |
-
2. **觀察截時 (Intercept Time)**: 試著只增加厚度 `h
|
| 124 |
3. **觀察交越距離 (Crossover Distance)**: 試著增加 `h` 或減小 `V2` 與 `V1` 的速度差,看看交叉點如何向右移動?
|
| 125 |
-
4.
|
|
|
|
| 126 |
|
| 127 |
<footer>
|
| 128 |
<p style="text-align:center; color:grey;">地球物理小教室 © 2025 - 由 Gemini 根據課程文件生成</p>
|
|
@@ -131,4 +153,4 @@ with gr.Blocks(theme=gr.themes.Soft()) as demo:
|
|
| 131 |
)
|
| 132 |
|
| 133 |
if __name__ == "__main__":
|
| 134 |
-
demo.launch()
|
|
|
|
| 2 |
import numpy as np
|
| 3 |
import matplotlib.pyplot as plt
|
| 4 |
|
| 5 |
+
# --- 核心計算與繪圖函數 (已加入反射波) ---
|
| 6 |
+
def plot_travel_times(v1, v2, h, x_max):
|
| 7 |
"""
|
| 8 |
+
根據輸入的地層參數,計算並繪製直達波、反射波與折射波的走時曲線。
|
| 9 |
+
圖表內的標籤為英文。
|
| 10 |
"""
|
| 11 |
# 物理條件檢查:折射必須 V2 > V1
|
| 12 |
if v2 <= v1:
|
| 13 |
fig, ax = plt.subplots(figsize=(10, 6))
|
| 14 |
+
# 即使沒有折射,我們仍然可以顯示直達波和反射波
|
| 15 |
+
x = np.linspace(0, x_max, 500)
|
| 16 |
+
t_direct = x / v1
|
| 17 |
+
t_reflected = np.sqrt(x**2 + (2 * h)**2) / v1 # 反射波計算
|
| 18 |
+
|
| 19 |
+
ax.plot(x, t_direct, 'b--', label='Direct Wave')
|
| 20 |
+
ax.plot(x, t_reflected, 'm-.', label='Reflected Wave') # 反射波繪圖
|
| 21 |
+
|
| 22 |
+
ax.text(0.5, 0.5, 'V2 <= V1: Critical refraction does not occur.\nOnly Direct and Reflected waves are shown.',
|
| 23 |
+
ha='center', va='center', fontsize=12, color='orange')
|
| 24 |
ax.set_xlabel("Distance (m)")
|
| 25 |
ax.set_ylabel("Travel Time (s)")
|
| 26 |
ax.grid(True)
|
| 27 |
+
ax.legend()
|
| 28 |
+
ax.set_title("Travel-Time Curve (No Refraction)")
|
| 29 |
+
results_md = "### 參數錯誤\n請確保第二層速度 (V2) 大於第一層速度 (V1) 才能產生臨界折射現象。"
|
| 30 |
+
return fig, results_md
|
| 31 |
|
| 32 |
# 1. 計算關鍵物理量
|
| 33 |
theta_c_rad = np.arcsin(v1 / v2)
|
|
|
|
| 39 |
x = np.linspace(0, x_max, 500)
|
| 40 |
t_direct = x / v1
|
| 41 |
t_refracted = (x / v2) + ti
|
| 42 |
+
t_reflected = np.sqrt(x**2 + (2 * h)**2) / v1 # <<< 新增:反射波走時計算
|
| 43 |
+
t_first_arrival = np.minimum(t_direct, t_refracted) # 注意:反射波永遠不會是初達波
|
| 44 |
|
| 45 |
+
# 3. 使用 Matplotlib 繪圖
|
| 46 |
fig, ax = plt.subplots(figsize=(10, 6))
|
| 47 |
|
|
|
|
| 48 |
ax.plot(x, t_direct, 'b--', label=f'Direct Wave (Slope 1/{v1:.0f})')
|
| 49 |
ax.plot(x, t_refracted, 'g--', label=f'Refracted Wave (Slope 1/{v2:.0f})')
|
| 50 |
+
ax.plot(x, t_reflected, 'm-.', label='Reflected Wave') # <<< 新增:反射波繪圖指令
|
| 51 |
ax.plot(x, t_first_arrival, 'r-', linewidth=3, label='First Arrival')
|
| 52 |
|
| 53 |
if xc < x_max:
|
|
|
|
| 56 |
|
| 57 |
ax.plot(0, ti, 'mo', markersize=8, label=f'Intercept Time = {ti*1000:.1f} ms')
|
| 58 |
|
| 59 |
+
ax.set_title("Interactive Seismic T-X Plot (Reflection + Refraction)", fontsize=16)
|
|
|
|
| 60 |
ax.set_xlabel("Distance (m)", fontsize=12)
|
| 61 |
ax.set_ylabel("Travel Time (s)", fontsize=12)
|
| 62 |
|
| 63 |
ax.legend()
|
| 64 |
ax.grid(True)
|
| 65 |
ax.set_xlim(0, x_max)
|
| 66 |
+
# 優化 Y 軸範圍,確保所有曲線可見
|
| 67 |
+
max_time = np.max([t_direct, t_refracted, t_reflected])
|
| 68 |
+
ax.set_ylim(0, max_time * 1.1)
|
| 69 |
plt.tight_layout()
|
| 70 |
|
| 71 |
+
# 4. 準備輸出的說明文字
|
| 72 |
results_md = f"""
|
| 73 |
### 🔬 分析結果
|
| 74 |
|
| 75 |
根據您設定的參數,我們計算出以下關鍵物理量:
|
| 76 |
|
| 77 |
+
- **直達波 (Direct Wave)**:
|
| 78 |
+
- 公式: `t = x / V1`
|
| 79 |
+
- *震波直接沿著地表傳遞,走時圖為一條過原點的直線。*
|
| 80 |
+
|
| 81 |
+
- **反射波 (Reflected Wave)**:
|
| 82 |
+
- 公式: `t = sqrt(x² + (2h)²) / V1`
|
| 83 |
+
- *震波向下傳至界面後反射回地表。走時圖為一條雙曲線,它永遠不會是「初達波」。*
|
| 84 |
+
|
| 85 |
+
- **折射波 (Refracted Wave)**:
|
| 86 |
+
- **臨界角 (Critical Angle, θc)**:
|
| 87 |
+
- 公式: `θc = arcsin(V1 / V2)`
|
| 88 |
+
- 計算: `arcsin({v1:.0f} / {v2:.0f})` = **{theta_c_deg:.2f}°**
|
| 89 |
+
- *產生「抄捷徑」折射波的關鍵入射角度。*
|
| 90 |
|
| 91 |
+
- **截時 (Intercept Time, tᵢ)**:
|
| 92 |
+
- 公式: `tᵢ = (2 * h * cos(θc)) / V1`
|
| 93 |
+
- 計算: `(2 * {h:.0f} * cos({theta_c_deg:.2f}°)) / {v1:.0f}` = **{ti*1000:.1f} ms**
|
| 94 |
+
- *折射波走時線在時間軸上的截距,隱含了第一層的厚度資訊。*
|
| 95 |
|
| 96 |
- **交越距離 (Crossover Distance, Xc)**:
|
| 97 |
- 公式: `Xc = 2 * h * sqrt((V2 + V1) / (V2 - V1))`
|
| 98 |
- 計算: `2 * {h:.0f} * sqrt(({v2:.0f} + {v1:.0f}) / ({v2:.0f} - {v1:.0f}))` = **{xc:.1f} m**
|
| 99 |
+
- *在此距離上,直達波和折射波同時抵達。超過此距離後,折射波會先到。*
|
| 100 |
"""
|
| 101 |
|
| 102 |
return fig, results_md
|
| 103 |
|
| 104 |
+
# --- Gradio 介面設定 (已更新標題與說明) ---
|
| 105 |
with gr.Blocks(theme=gr.themes.Soft()) as demo:
|
| 106 |
+
gr.Markdown("# 地心震波奇幻之旅:互動震測走時曲線實驗室 🌍")
|
| 107 |
gr.Markdown(
|
| 108 |
"""
|
| 109 |
+
歡迎來到地球物理小教室!這個互動工具可以模擬一個簡單的雙層地層模型中的震波傳遞。
|
| 110 |
+
您可以透過下方的滑桿來調整第一層速度 `V1`、第二層速度 `V2` 以及第一層的厚度 `h`。
|
| 111 |
+
觀察右側的「走時-距離圖」如何即時變化,並從中學習**直達波 (Direct)**、**反射波 (Reflected)** 與**折射波 (Refracted)** 的核心原理!
|
| 112 |
"""
|
| 113 |
)
|
| 114 |
|
|
|
|
| 131 |
|
| 132 |
# --- 事件監聽 ---
|
| 133 |
submit_btn.click(
|
| 134 |
+
fn=plot_travel_times, # 更新函數名稱
|
| 135 |
inputs=[v1_slider, v2_slider, h_slider, xmax_slider],
|
| 136 |
outputs=[plot_output, results_output]
|
| 137 |
)
|
|
|
|
| 140 |
"""
|
| 141 |
---
|
| 142 |
### 學習重點
|
| 143 |
+
1. **觀察斜率**: 直達波的斜率是 `1/V1`,折射波的斜率是 `1/V2`。試著調整 `V1` 和 `V2`,看看線條的陡峭程度如何變化?
|
| 144 |
+
2. **觀察截時 (Intercept Time)**: 試著只增加厚度 `h`,看看折射波在 Y 軸上的截距有什麼變化?
|
| 145 |
3. **觀察交越距離 (Crossover Distance)**: 試著增加 `h` 或減小 `V2` 與 `V1` 的速度差,看看交叉點如何向右移動?
|
| 146 |
+
4. **觀察反射波**: 注意反射波(洋紅色點虛線)是一條優美的雙曲線。它的曲率與第一層的厚度 `h` 和速度 `V1` 有關。
|
| 147 |
+
5. **必要條件**: 試著將 `V2` 調整到比 `V1` 小,看看會發生什麼事?你會發現,臨界折射的現象消失了,只剩下直達波與反射波!
|
| 148 |
|
| 149 |
<footer>
|
| 150 |
<p style="text-align:center; color:grey;">地球物理小教室 © 2025 - 由 Gemini 根據課程文件生成</p>
|
|
|
|
| 153 |
)
|
| 154 |
|
| 155 |
if __name__ == "__main__":
|
| 156 |
+
demo.launch()
|