refactor: remove emojis from titles and buttons for a cleaner UI
All checks were successful
Build & Deploy Shannon / 🏗️ Build & Deploy Shannon (push) Successful in 1m3s

This commit is contained in:
Poidevin, Antoine (ITOP CM) - AF
2026-02-20 10:50:04 +01:00
parent 6a4ccc3376
commit ac6c0e1bdf
9 changed files with 112 additions and 113 deletions

16
app.py
View File

@@ -17,7 +17,7 @@ import streamlit as st
st.set_page_config(
page_title="Shannon's Equation for Dummies",
page_icon="📡",
page_icon="antenna_bars",
layout="wide",
initial_sidebar_state="expanded",
)
@@ -104,7 +104,7 @@ st.markdown("""
# ──────────────────────────────────────────────────────────────────────────────
with st.sidebar:
st.markdown("## 📡 Shannon for Dummies")
st.markdown("## Shannon for Dummies")
st.caption("Educational Application — AP Feb 2021")
st.divider()
@@ -112,12 +112,12 @@ with st.sidebar:
"Navigation",
options=["animation", "orbits", "sat_types", "theory", "real_world", "contributions"],
format_func=lambda x: {
"animation": "📡 Satellite Link Animation",
"orbits": "🌍 GEO / MEO / LEO Orbits",
"sat_types": "🛰️ Satellite Missions & Types",
"theory": "🧮 Theoretical Exploration",
"real_world": "🛰️ Real World Link Budget",
"contributions": "💬 Community Contributions",
"animation": "Satellite Link Animation",
"orbits": "GEO / MEO / LEO Orbits",
"sat_types": "Satellite Missions & Types",
"theory": "Theoretical Exploration",
"real_world": "Real World Link Budget",
"contributions": "Community Contributions",
}[x],
label_visibility="collapsed",
)

View File

@@ -101,7 +101,7 @@ THEORY_HELP = {
"- Try multiple values in all the fields one by one\n"
"- Explore the graphs and try to understand the underlying physics\n"
"- The units are as explicit as possible to facilitate the exploration\n"
"- Click on the icons to get information about each parameter"
"- Click on the info icons to get information about each parameter"
),
}
@@ -134,7 +134,7 @@ REAL_WORLD_HELP = {
"The position of the ground station affects link availability due to weather statistics "
"(tropical regions have very heavy rains attenuating signals at high frequencies). "
"It also impacts the elevation angle and overall path length.\n\n"
"🔗 [Find coordinates](https://www.gps-coordinates.net)"
"[Find coordinates](https://www.gps-coordinates.net)"
),
"availability": (
"**Link Availability [%]**\n\n"

View File

@@ -11,17 +11,17 @@ from core.database import write_contribution, search_contributions, delete_contr
def render():
"""Render the Contributions page."""
st.markdown("# 💬 Community Contributions")
st.markdown("# Community Contributions")
st.markdown(
"Share your observations about Shannon's theorem, satellite communications, "
"or suggest improvements. Contributions are stored locally and shared with all users."
)
tab_read, tab_write = st.tabs(["📖 Read Contributions", "✍️ Write Contribution"])
tab_read, tab_write = st.tabs(["Read Contributions", "Write Contribution"])
# ── Read Contributions ──
with tab_read:
st.markdown("### 🔍 Search Contributions")
st.markdown("### Search Contributions")
db_choice = st.radio(
"Database",
@@ -39,7 +39,7 @@ def render():
kw_filter = st.text_input("Filter by Keywords", key="filter_kw")
content_filter = st.text_input("Filter by Content", key="filter_content")
if st.button("🔍 Search", type="primary", key="btn_search"):
if st.button("Search", type="primary", key="btn_search"):
results = search_contributions(
db_name,
name_filter=name_filter,
@@ -60,10 +60,10 @@ def render():
):
st.markdown(contrib["text"])
if contrib["keywords"]:
st.caption(f"🏷️ Keywords: {contrib['keywords']}")
st.caption(f"Keywords: {contrib['keywords']}")
# Delete functionality
with st.popover("🗑️ Delete"):
with st.popover("Delete"):
st.warning("This action cannot be undone.")
del_password = st.text_input(
"Enter contribution password",
@@ -72,7 +72,7 @@ def render():
)
if st.button("Confirm Delete", key=f"del_btn_{contrib['num']}"):
if delete_contribution(db_name, contrib["num"], del_password):
st.success(f"Contribution #{contrib['num']} deleted.")
st.success(f"Contribution #{contrib['num']} deleted.")
# Refresh results
st.session_state["contrib_results"] = search_contributions(
db_name,
@@ -83,13 +83,13 @@ def render():
)
st.rerun()
else:
st.error("Incorrect password or contribution not found.")
st.error("Incorrect password or contribution not found.")
elif "contrib_results" in st.session_state:
st.info("No contributions found matching your filters.")
# ── Write Contribution ──
with tab_write:
st.markdown("### ✍️ New Contribution")
st.markdown("### New Contribution")
db_choice_w = st.radio(
"Database",
@@ -109,17 +109,16 @@ def render():
type="password",
)
submitted = st.form_submit_button("📤 Submit", type="primary")
submitted = st.form_submit_button("Submit", type="primary")
if submitted:
if not name or not title or not text:
st.error("Please fill in all required fields (marked with *).")
st.error("Please fill in all required fields (marked with *).")
else:
new_id = write_contribution(db_name_w, name, title, keywords, text, password)
st.success(f"Thank you! Your contribution has been stored with ID #{new_id}.")
st.balloons()
st.success(f"Thank you. Your contribution has been stored with ID #{new_id}.")
with st.expander("Help"):
with st.expander("Help"):
st.markdown(
"Write your contribution as a free text. Contributions should be:\n\n"
"- Candid observations about the technical subject\n"

View File

@@ -66,7 +66,7 @@ _ORBITS_HTML = """
<canvas id="c"></canvas>
<div id="info">
<h3>🛰️ Orbit Comparison</h3>
<h3>Orbit Comparison</h3>
<div id="infoContent">
<p style="color:#94a3b8; text-align:center;">
Hover over a satellite to see its details.
@@ -226,8 +226,8 @@ function showInfo(o) {
<div class="stat"><span class="label">FSPL</span><span class="value">${o.fsplDb}</span></div>
<div class="stat"><span class="label">Coverage</span><span class="value">${o.coverage}</span></div>
<hr>
<div class="stat"><span class="label">Pros</span><span class="value" style="text-align:right; max-width:160px">${o.pros}</span></div>
<div class="stat"><span class="label">⚠️ Cons</span><span class="value" style="text-align:right; max-width:160px">${o.cons}</span></div>
<div class="stat"><span class="label">Pros</span><span class="value" style="text-align:right; max-width:160px">${o.pros}</span></div>
<div class="stat"><span class="label">Cons</span><span class="value" style="text-align:right; max-width:160px">${o.cons}</span></div>
<hr>
<div class="stat"><span class="label">Examples</span><span class="value" style="color:#4FC3F7">${o.examples}</span></div>
`;
@@ -489,7 +489,7 @@ draw();
def render():
"""Render the GEO/MEO/LEO orbit comparison animation."""
st.markdown("## 🌍 Satellite Orbits — GEO vs MEO vs LEO")
st.markdown("## Satellite Orbits — GEO vs MEO vs LEO")
st.markdown(
"Compare the three main satellite orbit types. "
"Hover over satellites or legend items to explore their characteristics."
@@ -500,50 +500,50 @@ def render():
# ── Educational content below ──
st.divider()
st.markdown("### 📊 Orbit Comparison at a Glance")
st.markdown("### Orbit Comparison at a Glance")
col1, col2, col3 = st.columns(3)
with col1:
st.markdown("""
#### 🟢 LEO — Low Earth Orbit
#### LEO — Low Earth Orbit
**160 2 000 km**
- Latency: **4 20 ms** (RTT)
- 📉 FSPL: ~155 dB (Ku-band)
- 🔄 Period: ~90 120 min
- 📡 Small footprint → **large constellations** needed (hundreds to thousands)
- 🤝 Requires **handover** between satellites
- 🛰️ *Starlink (550 km), OneWeb (1 200 km), Iridium (780 km)*
- Latency: **4 20 ms** (RTT)
- FSPL: ~155 dB (Ku-band)
- Period: ~90 120 min
- Small footprint → **large constellations** needed (hundreds to thousands)
- Requires **handover** between satellites
- *Starlink (550 km), OneWeb (1 200 km), Iridium (780 km)*
""")
with col2:
st.markdown("""
#### 🟡 MEO — Medium Earth Orbit
#### MEO — Medium Earth Orbit
**2 000 35 786 km**
- Latency: **40 80 ms** (RTT)
- 📉 FSPL: ~186 dB (Ku-band)
- 🔄 Period: ~2 12 h
- 📡 Medium footprint → **medium constellations** (20 50 sats)
- 🌍 Good balance between coverage and latency
- 🛰️ *GPS (20 200 km), Galileo, O3b/SES (8 000 km)*
- Latency: **40 80 ms** (RTT)
- FSPL: ~186 dB (Ku-band)
- Period: ~2 12 h
- Medium footprint → **medium constellations** (20 50 sats)
- Good balance between coverage and latency
- *GPS (20 200 km), Galileo, O3b/SES (8 000 km)*
""")
with col3:
st.markdown("""
#### 🔴 GEO — Geostationary Orbit
#### GEO — Geostationary Orbit
**35 786 km (fixed)**
- Latency: **240 280 ms** (RTT)
- 📉 FSPL: ~205 dB (Ku-band)
- 🔄 Period: 23 h 56 min (= 1 sidereal day)
- 📡 Huge footprint → **3 sats = global** coverage
- 📌 **Fixed position** in the sky — no tracking needed
- 🛰️ *Intelsat, SES, Eutelsat, ViaSat*
- Latency: **240 280 ms** (RTT)
- FSPL: ~205 dB (Ku-band)
- Period: 23 h 56 min (= 1 sidereal day)
- Huge footprint → **3 sats = global** coverage
- **Fixed position** in the sky — no tracking needed
- *Intelsat, SES, Eutelsat, ViaSat*
""")
with st.expander("🔬 Key Trade-offs in Detail"):
with st.expander("Key Trade-offs in Detail"):
st.markdown(r"""
| Parameter | LEO | MEO | GEO |
|:---|:---:|:---:|:---:|
@@ -569,7 +569,7 @@ for the same bandwidth and transmit power. LEO compensates with lower FSPL
but requires more satellites and complex handover.
""")
with st.expander("🛰️ Notable Constellations"):
with st.expander("Notable Constellations"):
st.markdown("""
| Constellation | Orbit | Altitude | # Satellites | Use Case |
|:---|:---:|:---:|:---:|:---|

View File

@@ -159,21 +159,21 @@ def render():
with col_img:
st.image("Satellite.png", width=200)
with col_title:
st.markdown("# 🛰️ Shannon & Friends in the Real World")
st.markdown("# Shannon & Friends in the Real World")
st.markdown("From theory to satellite communication link budget.")
wiki_cols = st.columns(4)
wiki_cols[0].link_button("📖 Harry Nyquist", "https://en.wikipedia.org/wiki/Harry_Nyquist")
wiki_cols[1].link_button("📖 Richard Hamming", "https://en.wikipedia.org/wiki/Richard_Hamming")
wiki_cols[2].link_button("📖 Andrew Viterbi", "https://en.wikipedia.org/wiki/Andrew_Viterbi")
wiki_cols[3].link_button("📖 Claude Berrou", "https://en.wikipedia.org/wiki/Claude_Berrou")
wiki_cols[0].link_button("Harry Nyquist", "https://en.wikipedia.org/wiki/Harry_Nyquist")
wiki_cols[1].link_button("Richard Hamming", "https://en.wikipedia.org/wiki/Richard_Hamming")
wiki_cols[2].link_button("Andrew Viterbi", "https://en.wikipedia.org/wiki/Andrew_Viterbi")
wiki_cols[3].link_button("Claude Berrou", "https://en.wikipedia.org/wiki/Claude_Berrou")
st.divider()
# ══════════════════════════════════════════════════════════════════════════
# SECTION 1: Satellite Link
# ══════════════════════════════════════════════════════════════════════════
st.markdown("## 📡 Satellite Link")
st.markdown("## Satellite Link")
col1, col2, col3 = st.columns(3)
with col1:
@@ -213,7 +213,7 @@ def render():
try:
sat_cir_list = [float(v.strip()) for v in sat_cir_input.split(",")]
except ValueError:
st.error("Invalid C/I values.")
st.error("Invalid C/I values.")
return
# Compute satellite link
@@ -224,11 +224,11 @@ def render():
sat_alt, sat_lat, sat_lon, gs_lat, gs_lon, availability,
)
except Exception as e:
st.error(f"Satellite link computation error: {e}")
st.error(f"Satellite link computation error: {e}")
return
# Display satellite link results
st.markdown("#### 📊 Satellite Link Results")
st.markdown("#### Satellite Link Results")
r1, r2, r3 = st.columns(3)
r1.metric("Output Power", fmt_power(sat["sig_power"]), help=REAL_WORLD_HELP["output_power"])
r2.metric("Antenna Gain", fmt_gain(sat["sat_gain_linear"]), help=REAL_WORLD_HELP["sat_gain"])
@@ -245,14 +245,14 @@ def render():
st.metric("Power Flux Density", fmt_pfd(sat["pfd_linear"]), help=REAL_WORLD_HELP["pfd"])
if sat["elevation"] <= 0:
st.warning("⚠️ Satellite is below the horizon (negative elevation). Results may not be meaningful.")
st.warning("Satellite is below the horizon (negative elevation). Results may not be meaningful.")
st.divider()
# ══════════════════════════════════════════════════════════════════════════
# SECTION 2: Radio Front End
# ══════════════════════════════════════════════════════════════════════════
st.markdown("## 📻 Radio Front End")
st.markdown("## Radio Front End")
col_r1, col_r2 = st.columns(2)
with col_r1:
@@ -268,10 +268,10 @@ def render():
cpe_ant_d, cpe_t_clear,
)
except Exception as e:
st.error(f"Receiver computation error: {e}")
st.error(f"Receiver computation error: {e}")
return
st.markdown("#### 📊 Receiver Results")
st.markdown("#### Receiver Results")
rx1, rx2 = st.columns(2)
rx1.metric("Antenna Area · G/T", f"{rcv['cpe_ae']:.2f} m² · {rcv['cpe_g_t']:.1f} dB/K",
help=REAL_WORLD_HELP["cpe_gain"])
@@ -290,7 +290,7 @@ def render():
# ══════════════════════════════════════════════════════════════════════════
# SECTION 3: Baseband Unit
# ══════════════════════════════════════════════════════════════════════════
st.markdown("## 💻 Baseband Unit")
st.markdown("## Baseband Unit")
col_b1, col_b2, col_b3 = st.columns(3)
with col_b1:
@@ -310,7 +310,7 @@ def render():
try:
cnr_imp_list = [float(v.strip()) for v in cir_input.split(",")]
except ValueError:
st.error("Invalid C/I values.")
st.error("Invalid C/I values.")
return
try:
@@ -319,10 +319,10 @@ def render():
sat["sat_cir"], bandwidth, rolloff, overheads, cnr_imp_list, penalties,
)
except Exception as e:
st.error(f"Baseband computation error: {e}")
st.error(f"Baseband computation error: {e}")
return
st.markdown("#### 📊 Baseband Results")
st.markdown("#### Baseband Results")
b1, b2, b3 = st.columns(3)
b1.metric("SNR in Available BW", f"{bb['cnr_bw']:.1f} dB in {bandwidth:.1f} MHz",
@@ -336,7 +336,7 @@ def render():
b4, b5 = st.columns(2)
with b4:
st.markdown("##### 🎯 Theoretical")
st.markdown("##### Theoretical")
st.metric(
"Theoretical BR",
f"{fmt_br(bb['br_nyq'])} · {bb['br_nyq_norm']:.0%}",
@@ -344,7 +344,7 @@ def render():
)
st.caption(f"Spectral Eff: {bb['spe_nyq']:.2f} bps/Hz · {bb['bits_per_symbol']:.2f} b/Symbol")
with b5:
st.markdown("##### 🏭 Practical")
st.markdown("##### Practical")
st.metric(
"Physical Layer BR",
f"{fmt_br(bb['br_rcv'])} · {bb['br_rcv_norm']:.0%}",
@@ -360,12 +360,12 @@ def render():
st.divider()
# ── Graphs ──
st.markdown("### 📈 Interactive Graphs")
st.markdown("### Interactive Graphs")
tab_bw, tab_pow, tab_map = st.tabs([
"📶 BW Sensitivity",
"Power Sensitivity",
"🗺️ BR Factor Map",
"BW Sensitivity",
"Power Sensitivity",
"BR Factor Map",
])
cnr_imp = combine_cnr(*cnr_imp_list)

View File

@@ -78,7 +78,7 @@ body{background:transparent;overflow:hidden;font-family:'Segoe UI',system-ui,san
<canvas id="c"></canvas>
<div id="tabs"></div>
<div id="info"><h3>🛰️ Satellite Missions</h3><p style="color:#64748b;text-align:center;padding:12px 0">Select a mission type above<br>to explore its animation.</p></div>
<div id="info"><h3>Satellite Missions</h3><p style="color:#64748b;text-align:center;padding:12px 0">Select a mission type above<br>to explore its animation.</p></div>
<div id="sceneLabel"><span>Mission Control</span> — choose a category</div>
<script>
@@ -86,37 +86,37 @@ body{background:transparent;overflow:hidden;font-family:'Segoe UI',system-ui,san
// DATA
// ═══════════════════════════════════════════════════════════════
const cats=[
{id:'nav',icon:'🧭',name:'Navigation',color:'#34d399',rgb:'52,211,153',
{id:'nav',icon:'NAV',name:'Navigation',color:'#34d399',rgb:'52,211,153',
orbit:'MEO',alt:'20 200 km',band:'L-band (1.21.6 GHz)',power:'~50 W/signal',
precision:'< 1 m (dual-freq)',lifetime:'1215 yrs',
examples:['GPS (USA)','Galileo (EU)','GLONASS (RU)','BeiDou (CN)'],
fact:'Each GPS satellite carries 4 atomic clocks accurate to ~1 ns. Relativity corrections of 38 μs/day are applied.',
sceneHint:'Triangulation — 3 satellites fix your position'},
{id:'com',icon:'📡',name:'Communication',color:'#4FC3F7',rgb:'79,195,247',
{id:'com',icon:'COM',name:'Communication',color:'#4FC3F7',rgb:'79,195,247',
orbit:'GEO + LEO',alt:'55036 000 km',band:'C / Ku / Ka-band',power:'220 kW',
precision:'100+ Gbps (HTS)',lifetime:'1520 yrs',
examples:['Starlink','Intelsat','SES','OneWeb'],
fact:'A modern HTS can deliver 500+ Gbps — equivalent to 100 000 HD streams simultaneously.',
sceneHint:'Data flowing between ground stations'},
{id:'eo',icon:'📸',name:'Earth Observation',color:'#a78bfa',rgb:'167,139,250',
{id:'eo',icon:'EO',name:'Earth Observation',color:'#a78bfa',rgb:'167,139,250',
orbit:'LEO (SSO)',alt:'500800 km',band:'X-band (downlink)',power:'SAR + optical',
precision:'0.330 m resolution',lifetime:'57 yrs',
examples:['Sentinel','Landsat','Planet Doves','Pléiades'],
fact:'Planet Labs\' 200+ Doves image the entire land surface every single day at 3 m resolution.',
sceneHint:'Satellite scanning the terrain below'},
{id:'wx',icon:'🌦️',name:'Weather',color:'#fbbf24',rgb:'251,191,36',
{id:'wx',icon:'WX',name:'Weather',color:'#fbbf24',rgb:'251,191,36',
orbit:'GEO + LEO',alt:'80036 000 km',band:'L / S / Ka-band',power:'Imager + Sounder',
precision:'Full disk every 10 min',lifetime:'1015 yrs',
examples:['Meteosat','GOES','Himawari','FengYun'],
fact:'GOES-16 produces 3.6 TB of weather imagery per day across 16 spectral bands.',
sceneHint:'Atmospheric monitoring & cloud tracking'},
{id:'sci',icon:'🔭',name:'Science',color:'#f472b6',rgb:'244,114,182',
{id:'sci',icon:'SCI',name:'Science',color:'#f472b6',rgb:'244,114,182',
orbit:'Various (L2, LEO, HEO)',alt:'540 km 1.5M km',band:'S / X / Ka-band',power:'Telescope + Spectrometer',
precision:'28 Mbps (JWST)',lifetime:'520+ yrs',
examples:['JWST','Hubble','Gaia','SOHO','Chandra'],
fact:'JWST\'s 6.5 m gold mirror operates at 233 °C to see infrared light from the first galaxies, 13.5 billion years ago.',
sceneHint:'Deep-space telescope view'},
{id:'def',icon:'🛡️',name:'Defense',color:'#fb923c',rgb:'251,146,60',
{id:'def',icon:'DEF',name:'Defense',color:'#fb923c',rgb:'251,146,60',
orbit:'LEO / GEO / HEO',alt:'Variable',band:'UHF / SHF / EHF',power:'Anti-jam, encrypted',
precision:'SIGINT + IMINT',lifetime:'715 yrs',
examples:['SBIRS','WGS','Syracuse (FR)','Skynet (UK)'],
@@ -155,7 +155,7 @@ cats.forEach(c=>{
});
function resetInfo(){
document.getElementById('info').innerHTML='<h3>🛰️ Satellite Missions</h3><p style="color:#64748b;text-align:center;padding:12px 0">Select a mission type above<br>to explore its animation.</p>';
document.getElementById('info').innerHTML='<h3>Satellite Missions</h3><p style="color:#64748b;text-align:center;padding:12px 0">Select a mission type above<br>to explore its animation.</p>';
}
function showInfo(c){
document.getElementById('info').innerHTML=
@@ -170,7 +170,7 @@ function showInfo(c){
'<div style="color:#64748b;font-size:10.5px;margin-bottom:4px">Notable systems:</div>'+
'<div>'+c.examples.map(function(e){return '<span class="tag">'+e+'</span>'}).join('')+'</div>'+
'<hr class="sep">'+
'<div class="fact"><b>💡 Did you know?</b><p>'+c.fact+'</p></div>';
'<div class="fact"><b>Key fact:</b><p>'+c.fact+'</p></div>';
}
function updateLabel(){
var el=document.getElementById('sceneLabel');
@@ -791,7 +791,7 @@ frame();
def render():
"""Render the satellite missions / types dashboard page."""
st.markdown("## 🛰️ Satellite Missions — Types & Applications")
st.markdown("## Satellite Missions — Types & Applications")
st.markdown(
"Explore **six categories** of satellite missions through unique animated scenes. "
"Click a tab to switch between navigation, communication, observation, weather, "
@@ -803,23 +803,23 @@ def render():
# ── Educational content below ──
st.divider()
st.markdown("### 📋 Mission Comparison")
st.markdown("### Mission Comparison")
st.markdown("""
| Category | Orbit | Altitude | Key Band | Examples |
|:---|:---:|:---:|:---:|:---|
| 🧭 **Navigation** | MEO | 20 200 km | L-band | GPS, Galileo, GLONASS, BeiDou |
| 📡 **Communication** | GEO / LEO | 550 36 000 km | C / Ku / Ka | Starlink, Intelsat, SES |
| 📸 **Earth Observation** | LEO (SSO) | 500 800 km | X-band | Sentinel, Landsat, Planet |
| 🌦️ **Weather** | GEO / LEO | 800 36 000 km | L / Ka | Meteosat, GOES, Himawari |
| 🔭 **Science** | Various | Variable | S / X / Ka | JWST, Hubble, Gaia |
| 🛡️ **Defense** | LEO / GEO / HEO | Variable | UHF / EHF | SBIRS, WGS, Syracuse |
| **Navigation** | MEO | 20 200 km | L-band | GPS, Galileo, GLONASS, BeiDou |
| **Communication** | GEO / LEO | 550 36 000 km | C / Ku / Ka | Starlink, Intelsat, SES |
| **Earth Observation** | LEO (SSO) | 500 800 km | X-band | Sentinel, Landsat, Planet |
| **Weather** | GEO / LEO | 800 36 000 km | L / Ka | Meteosat, GOES, Himawari |
| **Science** | Various | Variable | S / X / Ka | JWST, Hubble, Gaia |
| **Defense** | LEO / GEO / HEO | Variable | UHF / EHF | SBIRS, WGS, Syracuse |
""")
col1, col2 = st.columns(2)
with col1:
with st.expander("🧭 Navigation Satellites"):
with st.expander("Navigation Satellites"):
st.markdown("""
**How GNSS works:**
@@ -842,7 +842,7 @@ With 4+ satellites the receiver solves for $(x, y, z, \\Delta t)$ —
- **BeiDou** (China) — 35+ sats
""")
with st.expander("📡 Communication Satellites"):
with st.expander("Communication Satellites"):
st.markdown("""
**Evolution:**
@@ -860,7 +860,7 @@ LEO at 550 km, but compensates with larger antennas, higher power
and advanced modulation (DVB-S2X, 256-APSK).
""")
with st.expander("🌦️ Weather Satellites"):
with st.expander("Weather Satellites"):
st.markdown("""
**Two approaches:**
@@ -873,7 +873,7 @@ and advanced modulation (DVB-S2X, 256-APSK).
""")
with col2:
with st.expander("📸 Earth Observation Satellites"):
with st.expander("Earth Observation Satellites"):
st.markdown("""
**Imaging technologies:**
@@ -889,7 +889,7 @@ and advanced modulation (DVB-S2X, 256-APSK).
consistent solar illumination for temporal comparison.
""")
with st.expander("🔭 Science & Exploration"):
with st.expander("Science & Exploration"):
st.markdown("""
| Mission | Location | Purpose |
|:---|:---:|:---|
@@ -902,7 +902,7 @@ consistent solar illumination for temporal comparison.
at ~160 **bits**/s with 23 W through NASA's 70 m DSN antennas.
""")
with st.expander("🛡️ Defense & Intelligence"):
with st.expander("Defense & Intelligence"):
st.markdown("""
**Categories:**

View File

@@ -146,17 +146,17 @@ def render():
with col_img:
st.image("Shannon.png", width=200)
with col_title:
st.markdown("# 📡 Shannon's Equation for Dummies")
st.markdown("# Shannon's Equation for Dummies")
st.markdown(
"Exploration of Claude Shannon's channel capacity theorem — "
"the fundamental limit of digital communications."
)
st.link_button("📖 Wiki: Claude Shannon", "https://en.wikipedia.org/wiki/Claude_Shannon")
st.link_button("Wiki: Claude Shannon", "https://en.wikipedia.org/wiki/Claude_Shannon")
st.divider()
# ── Input Parameters ──
st.markdown("### ⚙️ Input Parameters")
st.markdown("### Input Parameters")
col_in1, col_in2 = st.columns(2)
with col_in1:
@@ -177,15 +177,15 @@ def render():
cnr_values = [float(v.strip()) for v in cnr_input.split(",")]
cnr_nyq = combine_cnr(*cnr_values)
except (ValueError, ZeroDivisionError):
st.error("Invalid C/N values. Use comma-separated numbers (e.g., '12' or '12, 15').")
st.error("Invalid C/N values. Use comma-separated numbers (e.g., '12' or '12, 15').")
return
# ── Computed Results ──
cnr_linear, br_inf, c_n0, br_bw = shannon_points(bw_input, cnr_nyq)
br_unit = c_n0 # Spectral efficiency = 1
st.markdown("### 📊 Results")
st.info(THEORY_HELP["c_n0"], icon="") if st.checkbox("Show C/N₀ explanation", value=False) else None
st.markdown("### Results")
st.info(THEORY_HELP["c_n0"], icon=":material/info:") if st.checkbox("Show C/N₀ explanation", value=False) else None
m1, m2, m3, m4 = st.columns(4)
m1.metric("C/N₀", f"{c_n0:.1f} MHz", help=THEORY_HELP["c_n0"])
@@ -202,7 +202,7 @@ def render():
st.divider()
# ── Sensitivity Analysis ──
st.markdown("### 🔬 Sensitivity Analysis")
st.markdown("### Sensitivity Analysis")
col_s1, col_s2, col_s3 = st.columns(3)
with col_s1:
@@ -229,12 +229,12 @@ def render():
st.divider()
# ── Graphs ──
st.markdown("### 📈 Interactive Graphs")
st.markdown("### Interactive Graphs")
tab_bw, tab_pow, tab_map = st.tabs([
"📶 Bandwidth Sensitivity",
"Power Sensitivity",
"🗺️ BR Factor Map",
"Bandwidth Sensitivity",
"Power Sensitivity",
"BR Factor Map",
])
with tab_bw:
@@ -256,14 +256,14 @@ def render():
)
# ── Help Section ──
with st.expander("📘 Background Information"):
with st.expander("Background Information"):
help_topic = st.selectbox(
"Choose a topic:",
options=["shannon", "advanced", "help"],
format_func=lambda x: {
"shannon": "🧠 Shannon's Equation",
"advanced": "🔧 Advanced (AWGN Model)",
"help": "How to use this tool",
"shannon": "Shannon's Equation",
"advanced": "Advanced (AWGN Model)",
"help": "How to use this tool",
}[x],
)
st.markdown(THEORY_HELP[help_topic])