Spaces:
Sleeping
Sleeping
import numpy as np | |
import pandas as pd | |
import matplotlib.pyplot as plt | |
import seaborn as sns | |
import streamlit as st | |
from typing import Dict | |
# Constants | |
ONE_BR_UNITS = 23 | |
TWO_BR_UNITS = 45 | |
SOLAR_PANEL_RATING = 625 # W | |
BATTERY_CAPACITY = 200 # Ah | |
BATTERY_VOLTAGE = 12 # V | |
SYSTEM_LOSSES = 0.20 | |
FEED_IN_TARIFF = 12 | |
# Lighting specifications | |
LIGHTS_1BR = 5 | |
LIGHTS_2BR = 8 | |
LIGHT_POWER = 6 # Watts per light | |
def initialize_session_state(): | |
"""Initialize session state variables""" | |
defaults = { | |
'solar_panels': 100, | |
'batteries': 50, | |
'panel_price': 13000, | |
'battery_price': 39000, | |
'grid_price': 28.44 | |
} | |
for key, value in defaults.items(): | |
if key not in st.session_state: | |
st.session_state[key] = value | |
def calculate_lighting_consumption(occupancy_1br: float, occupancy_2br: float) -> float: | |
"""Calculate daily lighting consumption""" | |
return ( | |
(occupancy_1br * ONE_BR_UNITS * LIGHTS_1BR * LIGHT_POWER / 1000) + | |
(occupancy_2br * TWO_BR_UNITS * LIGHTS_2BR * LIGHT_POWER / 1000) | |
) * 24 # Daily kWh | |
def calculate_appliance_consumption(occupancy_1br: float, occupancy_2br: float) -> float: | |
"""Calculate daily appliance consumption""" | |
return ( | |
(occupancy_1br * ONE_BR_UNITS * (250 - (LIGHTS_1BR * LIGHT_POWER * 24 / 1000))) + | |
(occupancy_2br * TWO_BR_UNITS * (400 - (LIGHTS_2BR * LIGHT_POWER * 24 / 1000))) | |
) # Daily kWh | |
def total_consumption(occupancy_1br: float, occupancy_2br: float, common_area: float) -> float: | |
"""Calculate total monthly consumption""" | |
lighting = calculate_lighting_consumption(occupancy_1br, occupancy_2br) | |
appliances = calculate_appliance_consumption(occupancy_1br, occupancy_2br) | |
return (lighting + appliances + common_area) * 30 # Monthly kWh | |
def solar_production(panels: int) -> float: | |
"""Monthly solar production with losses""" | |
return panels * SOLAR_PANEL_RATING * 5 * 0.8 * 30 / 1000 # 5 sun hours | |
def battery_storage(batteries: int) -> float: | |
"""Usable battery capacity""" | |
return batteries * BATTERY_CAPACITY * BATTERY_VOLTAGE * 0.8 / 1000 | |
def financial_analysis(consumption: float, production: float, storage: float) -> Dict: | |
"""Detailed financial calculations""" | |
solar_used = min(production, consumption) | |
grid_purchased = max(consumption - solar_used - storage, 0) | |
return { | |
'solar_contribution': solar_used / consumption * 100, | |
'grid_dependency': grid_purchased / consumption * 100, | |
'monthly_savings': (consumption * st.session_state.grid_price) - | |
(grid_purchased * st.session_state.grid_price), | |
'payback_period': (st.session_state.solar_panels * st.session_state.panel_price + | |
st.session_state.batteries * st.session_state.battery_price) / | |
((consumption - grid_purchased) * st.session_state.grid_price * 12) | |
} | |
def create_consumption_breakdown(occupancy_1br: float, occupancy_2br: float, common_area: float): | |
"""Create detailed consumption breakdown""" | |
breakdown = { | |
'Lighting': calculate_lighting_consumption(occupancy_1br, occupancy_2br) * 30, | |
'Appliances': calculate_appliance_consumption(occupancy_1br, occupancy_2br) * 30, | |
'Common Areas': common_area * 30 | |
} | |
return pd.DataFrame.from_dict(breakdown, orient='index', columns=['kWh']) | |
# Streamlit Interface | |
def main(): | |
st.set_page_config("Solar Analysis Suite", "🌞", "wide") | |
initialize_session_state() | |
st.title("🌞 Advanced Solar Performance Analyzer") | |
with st.sidebar: | |
st.header("System Configuration") | |
st.number_input("Solar Panels", 1, 1000, key='solar_panels') | |
st.number_input("Batteries", 0, 500, key='batteries') | |
st.number_input("Panel Price (Ksh)", 1000, 50000, key='panel_price') | |
st.number_input("Battery Price (Ksh)", 5000, 100000, key='battery_price') | |
st.number_input("Grid Price (Ksh/kWh)", 10.0, 50.0, key='grid_price') | |
scenarios = { | |
"Low Occupancy": {"1br": 0.0, "2br": 1.0, "common": 5.904}, | |
"Medium Occupancy": {"1br": 0.25, "2br": 1.0, "common": 5.904}, | |
"High Occupancy": {"1br": 0.5, "2br": 1.0, "common": 5.904} | |
} | |
analysis_data = [] | |
for name, params in scenarios.items(): | |
consumption = total_consumption( | |
params["1br"], params["2br"], params["common"] | |
) | |
production = solar_production(st.session_state.solar_panels) | |
storage = battery_storage(st.session_state.batteries) | |
financials = financial_analysis(consumption, production, storage) | |
analysis_data.append({ | |
"Scenario": name, | |
"Consumption": consumption, | |
"Production": production, | |
**financials | |
}) | |
df = pd.DataFrame(analysis_data) | |
# Energy Flow Analysis | |
st.header("Energy Flow Composition") | |
fig, ax = plt.subplots(figsize=(10, 6)) | |
sns.barplot(df.melt(id_vars=['Scenario'], | |
value_vars=['solar_contribution', 'grid_dependency'], | |
x='Scenario', y='value', hue='variable', ax=ax) | |
ax.set_ylabel("Percentage (%)") | |
ax.set_title("Energy Contribution Breakdown") | |
st.pyplot(fig) | |
with st.expander("🔍 Energy Flow Interpretation"): | |
st.markdown(""" | |
**Understanding the Chart:** | |
- **Solar Contribution**: Percentage of total energy needs met by solar production | |
- **Grid Dependency**: Remaining energy required from grid | |
- Ideal scenario shows high solar contribution with minimal grid dependency | |
""") | |
# Financial Analysis | |
st.header("Financial Performance Metrics") | |
# Metric 1: Monthly Savings | |
fig1, ax1 = plt.subplots(figsize=(10, 4)) | |
sns.barplot(data=df, x='Scenario', y='monthly_savings', ax=ax1) | |
ax1.set_title("Monthly Cost Savings") | |
ax1.set_ylabel("Ksh") | |
st.pyplot(fig1) | |
with st.expander("💵 Savings Analysis"): | |
st.markdown(f""" | |
**Key Observations:** | |
- Savings calculated as: `(Total Consumption × Grid Price) - (Grid Purchased × Grid Price)` | |
- Current Grid Price: Ksh {st.session_state.grid_price}/kWh | |
- Maximum potential savings limited by solar production capacity | |
""") | |
st.table(df[['Scenario', 'Consumption', 'Production', 'monthly_savings']]) | |
# Metric 2: Payback Period | |
fig2, ax2 = plt.subplots(figsize=(10, 4)) | |
sns.barplot(data=df, x='Scenario', y='payback_period', ax=ax2) | |
ax2.set_title("System Payback Period") | |
ax2.set_ylabel("Years") | |
st.pyplot(fig2) | |
with st.expander("⏳ Payback Explanation"): | |
st.markdown(f""" | |
**Calculation Methodology:** | |
- Total Investment: (Panels × {st.session_state.panel_price:,}Ksh) + (Batteries × {st.session_state.battery_price:,}Ksh) | |
- Annual Savings: Monthly Savings × 12 | |
- Payback Period = Total Investment / Annual Savings | |
""") | |
st.table(df[['Scenario', 'payback_period']]) | |
# Consumption Breakdown | |
st.header("Detailed Consumption Analysis") | |
scenario_select = st.selectbox("Select Scenario", list(scenarios.keys())) | |
selected_params = scenarios[scenario_select] | |
breakdown_df = create_consumption_breakdown( | |
selected_params["1br"], | |
selected_params["2br"], | |
selected_params["common"] | |
) | |
col1, col2 = st.columns(2) | |
with col1: | |
st.subheader("Energy Composition") | |
fig3, ax3 = plt.subplots() | |
breakdown_df.plot.pie(y='kWh', ax=ax3, autopct='%1.1f%%') | |
st.pyplot(fig3) | |
with col2: | |
st.subheader("Component Breakdown") | |
st.table(breakdown_df) | |
analysis_text = f""" | |
**Key Insights for {scenario_select}:** | |
- Lighting contributes {breakdown_df.loc['Lighting', 'kWh']/breakdown_df.sum().values[0]*100:.1f}% of total consumption | |
- Common areas account for {breakdown_df.loc['Common Areas', 'kWh']:.0f}kWh monthly | |
- 2BR units dominate appliance usage at {selected_params['2br']*100}% occupancy | |
""" | |
st.markdown(analysis_text) | |
if __name__ == "__main__": | |
main() | |