대시보드
import streamlit as st
import numpy as np
import pandas as pd
import datetime
# Streamlit 대시보드 UI 설정
st.markdown("<h2 style='text-align: center;'>✨ Chill & NASA RUL 예측 서비스 ✨</h2>", unsafe_allow_html=True)
# 파일 업로드 기능
uploaded_file = st.file_uploader("📂 CSV 파일을 업로드하세요", type=["csv"])
if uploaded_file is not None:
# 데이터 로드
df = pd.read_csv(uploaded_file)
# 온도 및 컷오프 전압 선택
available_temps = df["ambient_temperature"].unique()
available_cutoffs = df["discharge_voltage"].unique()
col1, col2 = st.columns(2)
with col1:
selected_temp = st.selectbox("🌡️ 온도를 선택하세요 (°C)", sorted(available_temps))
with col2:
selected_cutoff = st.selectbox("🔋 컷오프 전압을 선택하세요 (V)", sorted(available_cutoffs))
# 선택된 조건에 맞는 데이터 필터링
filtered_df = df[(df["ambient_temperature"] == selected_temp) &
(df["discharge_voltage"] == selected_cutoff)]
if filtered_df.empty:
st.warning("⚠️ 선택한 조건에 해당하는 데이터가 없습니다. 다른 값을 선택해 주세요.")
else:
# Cycle을 인덱스로 설정
filtered_df.set_index("Cycle", inplace=True)
soh_series = filtered_df["SOH"].dropna()
# SOH 최대값 및 80% 임계값 계산
soh_max = soh_series.max()
soh_threshold = soh_max * 0.8
# SOH 80% 이하가 되는 첫 번째 싸이클 찾기 (EOL)
below_threshold_cycles = soh_series[soh_series.index > soh_series.idxmax()]
below_threshold_cycles = below_threshold_cycles[below_threshold_cycles <= soh_threshold]
EOL_cycle = None
if not below_threshold_cycles.empty:
EOL_cycle = int(below_threshold_cycles.index[0])
# 현재 싸이클을 데이터의 마지막 싸이클로 설정
current_cycle = int(soh_series.index[-1])
# 현재 싸이클과 RUL 계산
RUL = EOL_cycle - current_cycle if EOL_cycle is not None else None
# 🔹 현재 사이클 & 예상 RUL 표시
st.subheader("🔢 배터리 상태")
col3, col4 = st.columns(2)
with col3:
st.info(f"🔄 현재 사이클: **{current_cycle} 회**")
with col4:
if RUL is not None:
st.success(f"📌 예상 RUL: **{RUL} 회**")
else:
st.error("⚠️ RUL을 계산할 수 없습니다.")
if RUL is not None:
# 🔹 1사이클 사용 가능 시간 (초)
CYCLE_DURATION = 10496
# 🔹 사용자 입력 (하루 평균 사용 시간)
daily_usage = st.number_input("⏳ 하루 평균 사용 시간 (초)", min_value=1, value=36000, step=1)
# 🔹 남은 사용 가능 일수 계산
if daily_usage > 0:
remaining_days = (RUL * CYCLE_DURATION) / daily_usage
# 🔹 연간 교체 개수 계산
annual_replacements = 365 / remaining_days
# 🔹 연간 교체 비용 계산 (배터리 가격 5,000원)
BATTERY_PRICE = 5000
annual_cost = annual_replacements * BATTERY_PRICE
# 🔹 남은 사용 가능 일수 & 연간 교체 비용 나란히 출력
st.subheader("📅 배터리 사용 예측")
col5, col6 = st.columns(2)
with col5:
st.success(f"📅 남은 사용 가능 일수: **{remaining_days:.2f} 일**")
with col6:
st.warning(f"💵 예상 연간 교체 비용: **{annual_cost:,.0f} 원**")
# 🔹 예상 배터리 교체 날짜 계산 (오늘 날짜 기준)
expected_replacement_date = datetime.date.today() + datetime.timedelta(days=remaining_days)
# 🔹 FullCalendar 스타일 달력 추가 (예상 교체일 이벤트 추가)
st.subheader("📆 예상 배터리 교체일 (캘린더)")
calendar_html = f"""
<html>
<head>
<link href='https://cdn.jsdelivr.net/npm/fullcalendar@5.10.1/main.min.css' rel='stylesheet' />
<script src='https://cdn.jsdelivr.net/npm/fullcalendar@5.10.1/main.min.js'></script>
<script>
document.addEventListener('DOMContentLoaded', function() {{
var calendarEl = document.getElementById('calendar');
var calendar = new FullCalendar.Calendar(calendarEl, {{
initialView: 'dayGridMonth',
initialDate: '{expected_replacement_date.strftime('%Y-%m-%d')}',
events: [
{{
title: '🔋 예상 교체일',
start: '{expected_replacement_date.strftime('%Y-%m-%d')}',
color: '#FF5733'
}}
]
}});
calendar.render();
}});
</script>
</head>
<body>
<div id='calendar'></div>
</body>
</html>
"""
# 🔹 Streamlit에서 캘린더 표시
st.components.v1.html(calendar_html, height=600)
# 🔹 예상 교체일 출력
st.info(f"📌 예상 배터리 교체일: **{expected_replacement_date.strftime('%Y-%m-%d')}**")
else:
st.error("⚠️ 하루 평균 사용 시간은 0보다 커야 합니다!")'TIL' 카테고리의 다른 글
| TIL - 실무에 쓰는 머신러닝 기초 1-2 (0) | 2025.03.14 |
|---|---|
| TIL - 실무에 쓰는 머신러닝 기초 1-1 (0) | 2025.03.12 |
| TIL - 실전 프로젝트 (0) | 2025.03.06 |
| TIL - 실전 프로젝트 (0) | 2025.03.05 |
| TIL - 실전 프로젝트 (0) | 2025.03.04 |