수소 충전 인프라의 '충전 사각지대' 해소와 운영 적자 최소화를 위해, AI가 실시간으로 "어떤 시점에, 어느 장소로 이동형 충전기를 보낼 것인가"를 결정하는 예측(Prediction) · 자원배분(Allocation) · 동적라우팅(Routing) 3-Layer AI 시스템입니다.
H2-Flex AX가 해결해야 하는 4가지 구조적 문제와 핵심 철학
수소차 보급과 충전 인프라는 닭-계란(Chicken-and-Egg) 딜레마입니다. 인프라 없이 차량 보급이 없고, 차량 없이 인프라 투자도 없습니다. H2-Flex AX는 정부가 선제적으로 충전소를 구축하되, AI가 적자를 최소화하는 최적 배치·운영 전략을 실시간으로 제안함으로써 한정된 재정으로 수소차 보급 확대를 유도하는 정책 실행 AI 도구입니다. 목표는 수익 극대화가 아닌 지속 가능한 적자 최소화 구조의 설계입니다.
고정식(sHRS) 기당 구축비 약 40억 원, 부지 확보·인허가 절차 복잡, 빠른 보급 불가. 2030년 기준 고정식 단독 운영 시 533개소 필요.
지역별·시기별 수요공급비(DSR) 편차 심각. 특정 지역은 충전 인프라가 전무한 '충전 사각지대' 존재. 현재 DSR 목표 34%±2% 유지가 핵심 과제.
높은 유지비·감가상각비로 대부분 충전소가 음(-)의 영업이익. 충전소당 연간 운영유지비 2억원, 감가상각 2억원(20년 분할). AI 운영 최적화 시급.
기후환경에너지부의 탄소중립 및 수소 경제 활성화 목표. 2030년까지 대규모 수소차 보급 예정. 탄력적 인프라 운영 모델 필요.
예측-배분-라우팅 3-Layer AI를 중심으로 한 Django 전체 구조
h2flex_ax/ ├── apps/ │ ├── location_optimizer/ # ① ALLOCATION — 입지 추천 │ │ └── services/ │ │ ├── ai_scorer_v2.py # XGBoost 108피처 (성장률 28개 포함) │ │ ├── growth_analyzer.py # 교통량·수익 증가율 분석 │ │ └── proactive_selector.py # 선제적 입지 선정 │ │ │ ├── demand_forecaster/ # ① PREDICTION — 수요 예측 │ │ └── services/ │ │ ├── ensemble_forecaster.py # Prophet + LSTM 앙상블 │ │ ├── realtime_queue.py # 실시간 대기 보정 레이어 │ │ └── event_demand_model.py # 이벤트 수요 오버레이 │ │ │ ├── mobile_router/ # ③ ROUTING — 이동형 배차 │ │ └── services/ │ │ ├── vrp_solver.py # OR-Tools CVRPTW │ │ ├── fault_replacer.py # ★ 고장·점검 즉시 대체 경로 │ │ └── event_dispatcher.py # 이벤트 임시 배차 │ │ │ ├── event_manager/ # 공사·행사 이벤트 관리 │ └── dsr_optimizer/ # ② ALLOCATION — DSR·구축비 최적화
Prediction · Allocation · Routing — 3개 AI 레이어의 알고리즘 및 구현 명세
기본 모델: Facebook Prophet + LSTM 앙상블
예측 범위: 1시간 ~ 7일 미래 충전 수요
정확도 목표: MAPE ≤ 15% (1일 예측)
업데이트: 매시간 자동 재예측
대기 보정: 30초 주기, 대기 3대↑ → 배차 트리거
이벤트 리드타임: 행사 48시간 전 선제 배차
공사 현장: 트럭 1대 = 15 kg/일 수요 산정
수소 소비 기준: 131.6 kg/대/년 (논문 파라미터)
# apps/demand_forecaster/services/ensemble_forecaster.py class H2FlexPredictionEngine: """ H2-Flex AX 수요 예측 엔진 — 3단계 파이프라인 1단계: Prophet+LSTM 기본 시계열 예측 2단계: 실시간 대기 큐 보정 (30초 갱신) 3단계: 이벤트 오버레이 (공사·행사 수요 가산) 파라미터: FCEV_KG_PER_UNIT = 131.6 (백동현 외 2025) """ FCEV_KG_PER_UNIT = 131.6 # 수소차 1대 연평균 소비량 (논문 기준) def predict(self, region_code: str, horizon_hours: int = 24) -> dict: # 1단계: 기본 앙상블 예측 base = self._ensemble_forecast(region_code, horizon_hours) # 2단계: 실시간 대기 보정 queue_adj = self.queue_adjuster.get_adjusted_demand( station_id=region_code, base_forecast_kg=base['demand_kg'] ) # 3단계: 이벤트 오버레이 (공사·행사) event_overlay = self.event_model.get_overlay(region_code, horizon_hours) total_demand = (queue_adj['adjusted_demand_kg'] + event_overlay['event_demand_kg']) return { 'total_demand_kg': total_demand, 'base_forecast_kg': base['demand_kg'], 'queue_demand_kg': queue_adj['queue_demand_kg'], 'event_demand_kg': event_overlay['event_demand_kg'], 'dispatch_needed': queue_adj['dispatch_needed'], 'dispatch_urgency': queue_adj['dispatch_urgency'], 'event_dispatch_lead': event_overlay['dispatch_lead_time_h'], }
# apps/dsr_optimizer/services/capex_minimizer.py (논문 직접 반영) class DSRCapexMinimizer: """ 논문 백동현 외(2025) 동적 확장판 핵심 파라미터 (SystemConfig DB에서 관리 → 재훈련 불필요): FCEV_KG_PER_UNIT = 131.6 # 수소차 1대 연평균 소비량 SHRS_ANNUAL_KG = 40 × 300 × 0.625 = 7,500 kg/년 MSHRS_ANNUAL_KG = 50 × 300 × 0.625 = 9,375 kg/년 DSR_TARGET = 0.34 (± 0.02) SHRS_CAPEX = 40억원 / 고정식 신설 MSHRS_CAPEX = 45억원 / 통합모델 신설 MRS_ADD_CAPEX = 7.5억원 / 기존 sHRS 전환 추가분 목표: 시나리오 A 기준 895억 절감 → 동적 최적화로 추가 절감 """ DSR_TARGET = 0.34 DSR_TOL = 0.02 SCENARIO_A = {'conversions': 50, 'new_builds': 30} # 논문 기준선 def optimize_annual(self, year: int, fcev_count: int, existing_sHRS: int, existing_msHRS: int) -> dict: from scipy.optimize import minimize annual_demand_kg = fcev_count * 131.6 result = minimize( lambda x: x[0] * 7.5 + x[1] * 45, # 구축비 최소화 x0=[30, 20], constraints={'type': 'ineq', 'fun': lambda x: ((existing_sHRS-x[0])*7500 + (existing_msHRS+x[0]+x[1])*9375) / annual_demand_kg - (self.DSR_TARGET - self.DSR_TOL)}, method='SLSQP', bounds=[(0, existing_sHRS), (0, 200)] ) opt_conv, opt_new = int(result.x[0]), int(result.x[1]) scenario_a_cost = self.SCENARIO_A['conversions']*7.5 + self.SCENARIO_A['new_builds']*45 return { 'year': year, 'optimal_conversions': opt_conv, # 기존 sHRS 전환 수 'optimal_new_builds': opt_new, # msHRS 신설 수 'total_capex_billion': float(result.fun), 'vs_scenario_a_saving': scenario_a_cost - float(result.fun), 'vs_stationary_saving': self._calc_stationary_cost(fcev_count) - float(result.fun), 'dsr_achieved_pct': self._calc_dsr(opt_conv, opt_new, existing_sHRS, existing_msHRS, annual_demand_kg) * 100, }
# apps/mobile_router/services/fault_replacer.py — ★NEW (v3 핵심) from apps.mobile_router.models import MobileUnit, DispatchPlan from apps.mobile_router.services.vrp_solver import MobileChargingVRPSolver from django.utils import timezone from datetime import timedelta class FaultReplacementRouter: """ 고정식 충전소 고장·점검 감지 → 이동형 즉시 대체 경로 생성 트리거: - OCPP WebSocket: 충전소 상태 'Faulted' / 'Unavailable' 수신 - 정기점검 스케줄: 24시간 전 사전 배차 계획 생성 SLA 목표: - 고장 감지 → 대체 배차 계획 생성: 5분 이내 - 이동형 충전소 현장 도착: 2시간 이내 - 서비스 공백 최소화 """ FAULT_RESPONSE_TARGET_MIN = 5 # 배차 계획 생성 SLA (분) ARRIVAL_TARGET_HOURS = 2 # 현장 도착 목표 (시간) MIN_HYDROGEN_LEVEL = 50 # 투입 가능 최소 수소 잔량 % def handle_fault_event(self, station_id: int, fault_type: str) -> dict: """ OCPP Faulted 이벤트 수신 시 즉시 호출 fault_type: 'FAULT' | 'SCHEDULED_MAINTENANCE' | 'EMERGENCY' """ faulted_station = self._get_station(station_id) affected_demand = self._estimate_lost_demand(faulted_station) # 최근접 가용 이동형 충전소 탐색 (수소 잔량 50% 이상) candidate_units = MobileUnit.objects.filter( status__in=['IDLE', 'DISPATCHED'], hydrogen_level__gte=self.MIN_HYDROGEN_LEVEL, ).annotate( dist= # PostGIS ST_Distance 기준 정렬 ).order_by('dist')[:3] if not candidate_units.exists(): self._escalate_alert(station_id, 'NO_MOBILE_UNIT_AVAILABLE') return {'status': 'ESCALATED', 'reason': 'no_available_unit'} best_unit = candidate_units.first() eta = timezone.now() + timedelta(hours=self.ARRIVAL_TARGET_HOURS) # OR-Tools로 대체 경로 즉시 생성 (30초 이내) route = MobileChargingVRPSolver().solve_single_unit( unit=best_unit, target=faulted_station.location, demand_kg=affected_demand, time_limit_sec=30 ) plan = DispatchPlan.objects.create( mobile_unit = best_unit, target_sites = [station_id], route_geom = route['geometry'], estimated_eta = eta, demand_served = affected_demand, dispatch_type = 'FAULT_REPLACEMENT', # ★ 대체 배차 구분 fault_ref_id = station_id, is_active = True ) best_unit.status = 'DISPATCHED' best_unit.save() return { 'status': 'DISPATCHED', 'unit_id': best_unit.unit_id, 'estimated_eta': eta.isoformat(), 'demand_covered_kg': affected_demand, 'route_distance_km': route['total_distance_km'], 'plan_id': plan.id, } def handle_scheduled_maintenance(self, station_id: int, maintenance_start: str) -> dict: """정기점검 24시간 전 사전 배차 계획 생성""" pass # 동일 로직, ETA만 정기점검 시작 시각으로 설정
| 데이터 | 소스 | 주기 | AI 레이어 활용 |
|---|---|---|---|
| EV/수소차 등록 | 공공데이터포털 (국토부) | 월 1회 | ① PREDICTION — 연도별 수요 기준값 (131.6 kg/대) |
| 교통량·증가율 | 도로공사 VDS, TOPIS | 5분 | ① PREDICTION + ② ALLOCATION 성장률 피처 |
| 충전 대기 ★ | 환경부 OCPP 2.0 | 30초 실시간 | ① PREDICTION 대기 보정 레이어 |
| 고장·점검 상태 ★ | OCPP WebSocket (Faulted/Unavailable) | 실시간 | ③ ROUTING 즉시 대체 경로 트리거 |
| 건설 공사 ★ | 국토부 건설허가 공공데이터 | 주 1회 | ① PREDICTION 이벤트 오버레이 + ③ ROUTING 임시 배차 |
| 지역 행사 ★ | 문체부 행사 DB, 지자체 API | 일 1회 | ① PREDICTION 이벤트 오버레이 + ③ ROUTING 임시 배차 |
| 충전소 수익 | 환경부 OCPP / ME-hub | 실시간 | ② ALLOCATION 수익 증가율 피처 |
| 수소 수급 | 가스공사 파이프라인 | 일 1회 | ② ALLOCATION DSR 공급 파라미터 |
| 전력 수급 | 한전 AMI API | 15분 | ② ALLOCATION 전기차 충전소 입지 적합성 |
# apps/mobile_router/models.py — v3 고장 대체 배차 추가 class DispatchPlan(models.Model): class DispatchType(models.TextChoices): REGULAR = 'REGULAR', '정기 VRP 배차' FAULT_REPLACE= 'FAULT_REPLACE','고장·점검 대체' # ★NEW EVENT_TEMP = 'EVENT_TEMP', '이벤트 임시 배차' mobile_unit = models.ForeignKey('MobileUnit', on_delete=models.CASCADE) # ★ 이동형은 반드시 고정식 거점과 연계 (논문: mHRS 단독 운영 배제) parent_station = models.ForeignKey('ChargingStation', on_delete=models.SET_NULL, null=True, related_name='mobile_plans') target_sites = JSONField(default=list) route_geom = models.LineStringField(srid=4326, null=True) estimated_eta = models.DateTimeField() demand_served = models.FloatField(default=0) dispatch_type = models.CharField(max_length=20, choices=DispatchType.choices, default=DispatchType.REGULAR) fault_ref_id = models.IntegerField(null=True) # 고장 대체 시 원 충전소 ID event_ref_id = models.IntegerField(null=True) # 이벤트 배차 시 이벤트 ID is_active = models.BooleanField(default=True) created_at = models.DateTimeField(auto_now_add=True) class StationFaultLog(models.Model): """충전소 고장·점검 이력 — 대체 배차 성능 측정에 활용""" station = models.ForeignKey('ChargingStation', on_delete=models.CASCADE) fault_type = models.CharField(max_length=30) # FAULT | MAINTENANCE | EMERGENCY detected_at = models.DateTimeField() dispatch_plan = models.OneToOneField(DispatchPlan, on_delete=models.SET_NULL, null=True, related_name='fault_response') plan_created_at = models.DateTimeField(null=True) # 배차 계획 생성 시각 unit_arrived_at = models.DateTimeField(null=True) # 실제 현장 도착 시각 @property def response_time_min(self) -> float: """감지 → 배차 계획 생성 소요 시간 (분) — SLA 5분 목표""" if self.plan_created_at: return (self.plan_created_at - self.detected_at).seconds / 60 return None @property def arrival_time_hours(self) -> float: """배차 계획 → 현장 도착 소요 시간 (시간) — SLA 2시간 목표""" if self.unit_arrived_at and self.plan_created_at: return (self.unit_arrived_at - self.plan_created_at).seconds / 3600 return None
백동현·박창협·전호병·김기세(2025), "이동식 수소충전소 통합 운영모델의 타당성 분석", 한국수소및신에너지학회논문집 36(6), pp.607-614
| 논문 핵심 수치 | H2-Flex AX 반영 | AI 레이어 |
|---|---|---|
| DSR 목표 34%±2% 5년 평균 35.8%, 최근 3년 34% | ALLOCATION 엔진의 핵심 제약 조건. 모든 입지·배차 의사결정의 기준 지표 | ② ALLOCATION |
| 시나리오 A: 895억 절감 50전환+30신설/년, 533→445개소 | 동적 최적화의 기준선(Baseline). H2-Flex AX는 이를 초과하는 추가 절감 추구 | ② ALLOCATION |
| mHRS 단독 운영 배제 | DispatchPlan.parent_station FK 필수화. VRP 솔버 귀환 거점 = 연계 sHRS 고정 | ③ ROUTING |
| 수소차 131.6 kg/대/년 | SystemConfig DB 관리. 재훈련 없이 정책 변경 시 즉시 수정 가능 | ① PREDICTION |
| 운영효율 62.5% (300시간) | sHRS 7,500 kg/년, msHRS 9,375 kg/년 공급능력 산출. ROUTING 연료 최소화 반영 | ③ ROUTING |
| 동적 모델 필요성 논문 토의 섹션의 자체 한계 지적 | Celery Beat 월별 자동 재훈련 파이프라인. 실시간 데이터로 매월 최적 구축 계획 재산출 | MLflow + Celery |
고정식 단독 대비 통합모델 운영 시 2026~2030년 구축 비용(CAPEX) 절감.
533개소 → 445개소로 88개소 감소. 절감된 예산으로 추가 미구축 지역 충전 인프라 투자 여력 확보.
msHRS 기준 연간 공급능력 최적화. 불필요한 인프라 과잉 투자 방지. 고장·점검 시 서비스 공백 2시간 내 복구. 이동형 운영 낭비율 -40%.
이동형 충전소의 유연한 배치로 미구축 지역·오지 수요 대응. 실시간 대기 정보 제공으로 충전 대기시간 -30% 단축. 수소차 보급 확대 가속화.
기후환경에너지부의 탄소중립 및 수소 경제 활성화 성과 관리 목표 직접 기여. DSR 34% 유지로 정부 수소차 보급 정책 실행력 강화. 정책 효과 데이터 기반 측정·보고 체계 구축.
| 메서드 | 엔드포인트 | 설명 | 레이어 |
|---|---|---|---|
| GET | /api/v1/locations/recommend/ | 선제적 입지 추천 (proactive_months 파라미터) | ② ALLOCATION |
| GET | /api/v1/locations/{id}/growth/ | 교통량·수익 증가율 추이 조회 | ② ALLOCATION |
| GET | /api/v1/demand/predict/ | 3-단계 수요 예측 (기본+대기+이벤트) | ① PREDICTION |
| GET | /api/v1/demand/queue/realtime/ | 충전소별 실시간 대기 현황 | ① PREDICTION |
| POST | /api/v1/mobile/dispatch/regular/ | 정기 VRP 배차 계획 생성 | ③ ROUTING |
| POST | /api/v1/mobile/dispatch/fault/ | 고장·점검 즉시 대체 경로 생성 ★ | ③ ROUTING |
| POST | /api/v1/mobile/dispatch/event/ | 이벤트 임시 배차 계획 생성 | ③ ROUTING |
| GET | /api/v1/dsr/current/ | 현재 수요공급비 실시간 계산 | ② ALLOCATION |
| GET | /api/v1/dsr/optimize/ | DSR 목표 달성 최적 구축 계획 | ② ALLOCATION |
| GET | /api/v1/events/upcoming/ | 48시간 내 예정 이벤트·공사 목록 | ① PREDICTION |
| WS | ws://host/ws/stations/faults/ | 충전소 고장 실시간 알림 스트림 ★ | ③ ROUTING |
| WS | ws://host/ws/mobile/location/ | 이동형 차량 실시간 위치 스트림 | ③ ROUTING |
| 리스크 | 유형 | 완화 전략 |
|---|---|---|
| OCPP 고장 이벤트 미수신 | 운영 | 충전소 운영사 직접 WebSocket 연동, 30분 무응답 시 장애 추정 자동 알림 |
| 고장 시 이동형 가용 차량 없음 | 운영 | 최소 가용 차량 수 임계치 설정, 미달 시 관리자 긴급 알림 + 인근 충전소 안내 |
| 이벤트 DB 데이터 불완전 | 데이터 | 문체부·지자체·SNS 크롤링 다중 소스 교차 검증 |
| 성장률 예측 오차 누적 | AI | 6개월+ 예측은 신뢰구간(CI) 함께 제공, 신뢰도 등급 표시 |
| DSR 목표 미충족 | 운영 | 월별 자동 재계산, 조기경보 → 긴급 추가 배차 또는 신설 계획 조기 실행 |
| 개인위치정보 처리 위반 | 법규 | 대기·위치 데이터 충전소 단위 집계만 수집, 개별 차량 추적 금지, PIIA 검토 |