File size: 7,635 Bytes
80df50a
 
 
 
d390991
fd63fae
80df50a
fd63fae
 
80df50a
 
 
 
fd63fae
 
 
70d7494
fd63fae
 
70d7494
fd63fae
 
 
80df50a
 
 
fd63fae
 
d390991
fd63fae
80df50a
 
 
 
 
 
d390991
80df50a
 
 
 
 
70d7494
 
80df50a
fd63fae
80df50a
 
d390991
 
 
 
80df50a
d390991
80df50a
d390991
80df50a
 
d390991
70d7494
d390991
 
 
70d7494
80df50a
 
d390991
 
80df50a
 
 
 
 
70d7494
fd63fae
80df50a
 
d390991
80df50a
d390991
80df50a
d390991
80df50a
d390991
 
 
fd63fae
d390991
 
 
fd63fae
d390991
 
 
 
70d7494
d390991
 
 
 
80df50a
d390991
 
 
 
 
 
 
 
 
80df50a
 
 
d390991
80df50a
d390991
80df50a
 
d390991
 
 
80df50a
 
 
 
 
d390991
 
 
 
 
80df50a
d390991
80df50a
 
d390991
80df50a
 
 
d390991
80df50a
d390991
80df50a
70d7494
80df50a
 
 
 
 
 
 
d390991
 
 
 
 
 
 
80df50a
 
 
 
 
 
 
 
fd63fae
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
import gradio as gr
import numpy as np
import matplotlib.pyplot as plt

# --- 核心計算與繪圖函數 (已加入臨界距離) ---
def plot_travel_times(v1, v2, h, x_max):
    """
    根據輸入的地層參數,計算並繪製直達波、反射波與折射波的走時曲線。
    圖表內的標籤為英文。
    """
    # 物理條件檢查:折射必須 V2 > V1
    if v2 <= v1:
        fig, ax = plt.subplots(figsize=(10, 6))
        # 即使沒有折射,我們仍然可以顯示直達波和反射波
        x = np.linspace(0, x_max, 500)
        t_direct = x / v1
        t_reflected = np.sqrt(x**2 + (2 * h)**2) / v1
        
        ax.plot(x, t_direct, 'b--', label='Direct Wave')
        ax.plot(x, t_reflected, 'm-.', label='Reflected Wave')
        
        ax.text(0.5, 0.5, 'V2 <= V1: Critical refraction does not occur.\nOnly Direct and Reflected waves are shown.',
                ha='center', va='center', fontsize=12, color='orange')
        ax.set_xlabel("Distance (m)")
        ax.set_ylabel("Travel Time (s)")
        ax.grid(True)
        ax.legend()
        ax.set_title("Travel-Time Curve (No Refraction)")
        results_md = "### 參數錯誤\n請確保第二層速度 (V2) 大於第一層速度 (V1) 才能產生臨界折射現象。"
        return fig, results_md

    # 1. 計算關鍵物理量
    theta_c_rad = np.arcsin(v1 / v2)
    theta_c_deg = np.rad2deg(theta_c_rad)
    ti = (2 * h * np.cos(theta_c_rad)) / v1
    xc = 2 * h * np.sqrt((v2 + v1) / (v2 - v1))
    xcrit = 2 * h * np.tan(theta_c_rad) # <<< 新增:臨界距離計算

    # 2. 準備繪圖數據
    x = np.linspace(0, x_max, 500)
    t_direct = x / v1
    t_refracted = (x / v2) + ti
    t_reflected = np.sqrt(x**2 + (2 * h)**2) / v1
    t_first_arrival = np.minimum(t_direct, t_refracted)
    
    # 3. 使用 Matplotlib 繪圖
    fig, ax = plt.subplots(figsize=(10, 6))
    
    ax.plot(x, t_direct, 'b--', label=f'Direct Wave (Slope 1/{v1:.0f})')
    ax.plot(x, t_refracted, 'g--', label=f'Refracted Wave (Slope 1/{v2:.0f})')
    ax.plot(x, t_reflected, 'm-.', label='Reflected Wave')
    ax.plot(x, t_first_arrival, 'r-', linewidth=3, label='First Arrival')
    
    # 標示交越距離
    if xc < x_max:
        ax.axvline(x=xc, color='k', linestyle=':', label=f'Crossover Distance = {xc:.1f} m')
        ax.plot(xc, xc/v1, 'ko') 

    # <<< 新增:標示臨界距離 >>>
    if xcrit < x_max:
        tcrit = (xcrit / v2) + ti # 計算臨界點的時間
        ax.axvline(x=xcrit, color='c', linestyle=':', label=f'Critical Distance = {xcrit:.1f} m')
        ax.plot(xcrit, tcrit, 'co', markersize=8) # 在臨界點加上青色圓點

    ax.plot(0, ti, 'mo', markersize=8, label=f'Intercept Time = {ti*1000:.1f} ms')

    ax.set_title("Interactive Seismic T-X Plot (Reflection + Refraction)", fontsize=16)
    ax.set_xlabel("Distance (m)", fontsize=12)
    ax.set_ylabel("Travel Time (s)", fontsize=12)
    
    ax.legend()
    ax.grid(True)
    ax.set_xlim(0, x_max)
    max_time = np.max([t_direct[-1], t_refracted[-1], t_reflected[-1]])
    ax.set_ylim(0, max_time * 1.1)
    plt.tight_layout()

    # 4. 準備輸出的說明文字
    results_md = f"""
    ### 🔬 分析結果

    根據您設定的參數,我們計算出以下關鍵物理量:

    - **直達波 (Direct Wave)**:
      - 公式: `t = x / V1`
      - *震波直接沿著地表傳遞,走時圖為一條過原點的直線。*

    - **反射波 (Reflected Wave)**:
      - 公式: `t = sqrt(x² + (2h)²) / V1`
      - *震波向下傳至界面後反射回地表。走時圖為一條雙曲線。*

    - **折射波 (Refracted Wave)**:
      - **臨界角 (Critical Angle, θc)**:
        - 公式: `θc = arcsin(V1 / V2)`
        - 計算: `arcsin({v1:.0f} / {v2:.0f})` = **{theta_c_deg:.2f}°**

      - **臨界距離 (Critical Distance, Xcrit)**:
        - 公式: `Xcrit = 2 * h * tan(θc)`
        - 計算: `2 * {h:.0f} * tan({theta_c_deg:.2f}°) ` = **{xcrit:.1f} m**
        - *這是能夠在地表接收到第一道臨界折射波的「最短水平距離」。*

      - **截時 (Intercept Time, tᵢ)**:
        - 公式: `tᵢ = (2 * h * cos(θc)) / V1`
        - 計算: `(2 * {h:.0f} * cos({theta_c_deg:.2f}°)) / {v1:.0f}` = **{ti*1000:.1f} ms**
        - *折射波走時線在時間軸上的截距,隱含了第一層的厚度資訊。*

    - **交越距離 (Crossover Distance, Xc)**:
      - 公式: `Xc = 2 * h * sqrt((V2 + V1) / (V2 - V1))`
      - 計算: `2 * {h:.0f} * sqrt(({v2:.0f} + {v1:.0f}) / ({v2:.0f} - {v1:.0f}))` = **{xc:.1f} m**
      - *在此距離上,直達波和折射波同時抵達。超過此距離後,折射波會先到。*
    """
    return fig, results_md

# --- Gradio 介面設定 (已更新標題與說明) ---
with gr.Blocks(theme=gr.themes.Soft()) as demo:
    gr.Markdown("# 地心震波奇幻之旅:互動震測走時曲線實驗室 🌍")
    gr.Markdown(
        """
        歡迎來到地球物理小教室!這個互動工具可以模擬一個簡單的雙層地層模型中的震波傳遞。
        您可以透過下方的滑桿來調整第一層速度 `V1`、第二層速度 `V2` 以及第一層的厚度 `h`。
        觀察右側的「走時-距離圖」如何即時變化,並從中學習**直達波 (Direct)**、**反射波 (Reflected)** 與**折射波 (Refracted)** 的核心原理!
        """
    )
    
    with gr.Row():
        with gr.Column(scale=1):
            gr.Markdown("### ⚙️ 調整地層參數")
            v1_slider = gr.Slider(label="V1: 第一層速度 (m/s)", minimum=300, maximum=3000, value=800, step=50)
            v2_slider = gr.Slider(label="V2: 第二層速度 (m/s)", minimum=500, maximum=6000, value=2500, step=50)
            h_slider = gr.Slider(label="h: 第一層厚度 (m)", minimum=5, maximum=100, value=20, step=1)
            xmax_slider = gr.Slider(label="最大觀測距離 (m)", minimum=100, maximum=500, value=250, step=10)
            
            submit_btn = gr.Button("產生圖表", variant="primary")
            
        with gr.Column(scale=2):
            gr.Markdown("### 📊 走時-距離圖 (T-X Plot)")
            plot_output = gr.Plot()
            
    with gr.Row():
        results_output = gr.Markdown("### 🔬 分析結果\n請調整參數並點擊按鈕以顯示計算結果。")

    # --- 事件監聽 ---
    submit_btn.click(
        fn=plot_travel_times,
        inputs=[v1_slider, v2_slider, h_slider, xmax_slider],
        outputs=[plot_output, results_output]
    )
    
    gr.Markdown(
        """
        ---
        ### 學習重點
        1.  **觀察斜率**: 直達波的斜率是 `1/V1`,折射波的斜率是 `1/V2`。
        2.  **觀察截時 (Intercept Time)**: 增加厚度 `h`,觀察折射波在 Y 軸上的截距如何變大。
        3.  **觀察交越距離 (Crossover Distance)**: 增加 `h` 或減小 `V2` 與 `V1` 的速度差,觀察交叉點如何向右移動。
        4.  **觀察反射波**: 注意反射波(洋紅色點虛線)是一條雙曲線,其曲率與 `h` 和 `V1` 有關。
        5.  **尋找臨界點**: 觀察**臨界距離**(青色虛線)的位置。這是折射波物理上「誕生」的地方。注意看,它正好落在反射波的曲線上!
        6.  **必要條件**: 將 `V2` 調整到比 `V1` 小,臨界折射現象會消失,只剩下直達波與反射波!
        
        <footer>
            <p style="text-align:center; color:grey;">地球物理小教室 &copy; 2025 - 由 Gemini 根據課程文件生成</p>
        </footer>
        """
    )

if __name__ == "__main__":
    demo.launch()