Spaces:
Sleeping
Sleeping
File size: 6,210 Bytes
65e9345 4d6fe89 d34efc0 4d6fe89 d34efc0 6709c71 d34efc0 6709c71 d34efc0 6709c71 d34efc0 4d6fe89 d34efc0 4d6fe89 d34efc0 4d6fe89 d34efc0 ee7277b d34efc0 ee7277b 4d6fe89 d34efc0 4d6fe89 d34efc0 4d6fe89 d34efc0 4d6fe89 d34efc0 4d6fe89 d34efc0 4d6fe89 65e9345 d34efc0 4d6fe89 d34efc0 4d6fe89 d34efc0 |
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 |
import streamlit as st
from obspy import UTCDateTime
import pandas as pd
from datetime import datetime, timedelta
# 匯入我們自己寫的模組
import earthquake_fetcher
import earthquake_analyzer
import visualizer
# --- 頁面設定 ---
st.set_page_config(
page_title="即時地震監測儀表板",
page_icon="🌊",
layout="wide"
)
st.title("即時地震監測與定位儀表板")
st.markdown("""
本應用程式從 [IRIS](http://ds.iris.edu/ds/nodes/dmc/) FDSN 服務獲取台灣 (TW) 測站的即時地震波形資料,
自動偵測 P 波並使用 Geiger 方法定位震源。
""")
# --- 側邊欄控制項 (FR6) ---
with st.sidebar:
st.header("⚙️ 分析參數設定")
# --- START OF CHANGE ---
# FR1: 時間範圍設定 (使用固定的預設值,並增加提示)
st.subheader("時間範圍設定")
# 設定一個固定的、可說明的預設時間範圍,避免使用者誤解
default_start_datetime = datetime(2025, 7, 20, 7, 0, 0)
default_end_datetime = datetime(2025, 7, 20, 7, 15, 0)
col1, col2 = st.columns(2)
with col1:
start_date = st.date_input("起始日期", value=default_start_datetime.date())
start_time_input = st.time_input("起始時間", value=default_start_datetime.time())
with col2:
end_date = st.date_input("終止日期", value=default_end_datetime.date())
end_time_input = st.time_input("終止時間", value=default_end_datetime.time())
# 增加提示文字,確保使用者了解其靈活性
st.caption("提示:您可以自由調整上方的日期與時間,查詢任何時間範圍的資料。")
# --- END OF CHANGE ---
# FR2: STA/LTA 參數設定
st.subheader("P波撿拾 (STA/LTA) 參數")
sta_window = st.slider("STA 窗長 (秒)", min_value=0.1, max_value=5.0, value=1.0, step=0.1)
lta_window = st.slider("LTA 窗長 (秒)", min_value=5.0, max_value=60.0, value=10.0, step=1.0)
trigger_threshold = st.slider("觸發門檻值", min_value=1.5, max_value=10.0, value=3.0, step=0.5)
off_threshold = st.slider("關閉門檻值", min_value=0.1, max_value=2.0, value=1.5, step=0.1)
# 初始化 session state
if 'analysis_results' not in st.session_state:
st.session_state.analysis_results = None
# 執行按鈕
if st.button("獲取指定範圍地震資料並分析", type="primary"):
with st.spinner("正在執行分析...請稍候..."):
# 將日期和時間輸入組合成 datetime 物件
start_datetime_local = datetime.combine(start_date, start_time_input)
end_datetime_local = datetime.combine(end_date, end_time_input)
# 轉換為 obspy 的 UTCDateTime 物件
start_time = UTCDateTime(start_datetime_local)
end_time = UTCDateTime(end_datetime_local)
# 為了快取,將 UTCDateTime 物件轉為字串傳遞
stream, inventory = earthquake_fetcher.get_earthquake_data(
start_time_str=str(start_time),
end_time_str=str(end_time)
)
if stream and inventory:
# 2. P波自動撿拾 (FR2)
p_picks = earthquake_analyzer.pick_p_waves(stream, sta_window, lta_window, trigger_threshold, off_threshold)
# 4. 震源定位 (FR4)
location_result = None
if len(p_picks) >= 4:
st.write(f"找到 {len(p_picks)} 個 P 波觸發,開始定位...")
location_result = earthquake_analyzer.locate_hypocenter(p_picks, inventory)
else:
st.write(f"P 波觸發測站數 ({len(p_picks)}) 不足 4 個,無法進行定位。")
# 將所有結果存儲到 session state
st.session_state.analysis_results = {
"stream": stream,
"inventory": inventory,
"p_picks": p_picks,
"location_result": location_result
}
else:
st.session_state.analysis_results = None # 清除舊結果
st.success("分析完成!")
# --- 主畫面結果展示 ---
if st.session_state.analysis_results:
results = st.session_state.analysis_results
p_picks = results["p_picks"]
location_result = results["location_result"]
inventory = results["inventory"]
st.header("📊 分析結果")
# 3. 波形視覺化 (FR3)
if p_picks:
st.subheader("測站波形與 P 波初達")
waveform_fig = visualizer.plot_waveforms_with_picks(p_picks)
st.plotly_chart(waveform_fig, use_container_width=True)
else:
st.info("在所有獲取的波形中,均未成功觸發 P 波。請嘗試調整 STA/LTA 參數或擴大時間範圍。")
# 5. 定位結果視覺化 (FR5)
st.subheader("震源定位結果")
if len(p_picks) < 4:
st.warning("P 波撿拾測站不足(少於4個),無法進行定位。")
elif not location_result:
st.error("定位計算失敗,可能是測站分佈不佳或資料品質問題。")
else:
col1, col2 = st.columns([2, 1]) # 地圖佔2/3,文字佔1/3
with col1:
st.pydeck_chart(visualizer.plot_event_map(inventory, p_picks, location_result))
with col2:
st.markdown("#### **定位資訊**")
origin_utc = UTCDateTime(location_result['origin_time'])
st.metric(label="發震時刻 (UTC)", value=origin_utc.strftime("%Y-%m-%d %H:%M:%S"))
st.metric(label="震央位置", value=f"{location_result['latitude']:.3f}°N, {location_result['longitude']:.3f}°E")
st.metric(label="深度", value=f"{location_result['depth_km']:.1f} km")
st.metric(label="使用測站數", value=len(p_picks))
st.markdown("---")
st.markdown("#### **參與定位測站**")
station_list = [p['station'] for p in p_picks]
st.text(", ".join(station_list))
else:
st.info("請在左側設定時間範圍與參數,然後點擊按鈕以開始分析。") |