한전 기본요금은 순간 전력이 아니라 15분 평균 전력의 최댓값으로 매겨집니다. 순간적으로 목표를 넘어도 15분 평균이 목표 아래면 요금에는 영향이 없고, 반대로 순간값이 목표 아래여도 앞에서 많이 썼다면 평균은 넘을 수 있습니다. 지금 jems 피크제어는 1초마다 순간값 ÷ 적용전력으로 단계를 정하기 때문에, 구간 안에서 시간이 얼마나 지났고 얼마나 썼는지를 보지 못합니다. 확인
구간 평균은 사실 "구간 동안 쓴 전력량"과 같은 말입니다. 목표가 1,000kW면 15분 동안 쓸 수 있는 전력량은 1,000kW × 0.25h = 250kWh로 정해집니다. 이 250kWh를 15분짜리 예산으로 보고, 지금까지 얼마를 썼고 남은 시간에 얼마를 쓸 수 있는지 계산하는 것이 이 문서의 출발점입니다.
이 문서 전체에서 같은 예시를 씁니다. 목표 1,000kW, 구간 6분이 지난 시점에 110kWh를 썼고(앞 6분 평균 1,100kW), 최근 몇 분은 1,080kW로 쓰고 있다고 가정합니다.
예시에서는 147kW를 남은 9분 동안 줄이면 정확히 250kWh로 끝납니다. 제어 여력이 200kW라면 막을 수 있는 구간이고, 여력이 100kW뿐이라면 최선을 다해도 넘는 구간입니다. 이 구분이 생긴다는 것만으로도 운영자에게 보여줄 정보가 달라집니다.
원문 아이디어 문서가 헷갈렸던 이유는 성격이 다른 세 가지가 한 목록에 섞여 있었기 때문입니다. 계산 부품, 그 부품을 쓰는 기존 기능의 수정, 그리고 허용량과 별개인 신규 주제입니다. 아래처럼 나누면 "새 기능인지 기존 기능 수정인지"가 항목마다 분명해집니다.
| 입력 | 현재 위치 | 상태 |
|---|---|---|
| 목표 kW | setup_contract('cost_applykw') — getNowPeakLevel이 이미 읽음 | 확인 |
| 구간 누적 평균 | datareproc.py avrgPeak15minKwProc 메모리 누적, avrg_kw_peak_15min_data DB | 확인 |
| 경과·남은 시간 | get_current_block_info() — 정각 기준 15분 고정 구간 | 확인 |
| 현재 총전력 | dataserver.py totalkw (모드 1이면 main 계측값) | 확인 |
| 설비별 전력 | 같은 루프의 units_data | 확인 |
| P_예측 | 없음. 최근 1~3분 평균으로 시작 | 미구현 |
| 설비별 감축 가능량 | powercontrol_value는 있으나 실제 감축 kW는 PLC 내부에서 결정 | 미확인 |
피크제어 판단(getNowPeakLevel)과 15분 누적(avrgPeak15minKwProc)은 같은 dataserver 프로세스, 같은 1초 루프 안에 있습니다. 그래서 누적기를 확장해 계산까지 하게 하면 DB를 거치지 않고 바로 쓸 수 있습니다. 다른 프로세스(aiControlProc, webserver)는 서버 간 직접 통신이 없고 공유 DB 테이블로만 주고받으므로, 계산 결과를 공유 테이블 한 행에 매초 덮어써 두면 됩니다. 확인 새 테이블을 만들지 기존 테이블에 컬럼을 추가할지는 정해야 합니다.
① P_예측 창은 구간 경계에서 끊지 않습니다. 구간 누적은 정각마다 0으로 돌아가지만, 최근 1~3분 평균은 이전 구간의 데이터를 그대로 이어서 써야 합니다. 그래야 구간 시작 직후에도 P_end가 극단적으로 튀지 않습니다. 구조조사 문서 24장 부근에 "구간 전환 직후 표본이 적어 평균이 튀어 오판했다"는 기록이 있는데, 같은 실수를 피하는 방법입니다.
② 누적량은 시간 기준으로 계산합니다. 지금 15분 평균은 샘플 수로 나눈 샘플 평균입니다. 확인 누적kWh = 구간 평균 × 경과 초 ÷ 3600으로 계산하면, 통신이 끊겨 샘플이 몇 개 빠져도 빠진 시간을 평균값으로 채운 효과가 납니다. 샘플을 단순히 더하면 빠진 만큼 덜 쓴 것으로 계산되어 제어가 덜 걸리는 쪽으로 틀립니다.
③ 기존 누적기를 고치지 않고 별도 누적기를 둡니다. 지금 누적기는 재시작하면 0에서 시작하고 그 구간의 DB 행을 부분 평균으로 덮어씁니다. 확인 기존 화면과 테이블은 그대로 두고, 층 1은 자기 누적기를 따로 두어 재시작 시 복구(안 되면 빠진 시간을 목표치로 쓴 것으로 보수적으로 채움)와 시간 가중을 처리합니다.
④ 한전 계량 구간과의 정렬은 출시 전에 맞춥니다. 구간은 서버 시각으로 정하고 데모 서버는 NTP 동기화 상태입니다. 확인 한전 구간과 맞춰 본 적은 아직 없으므로, 맞추기 전까지는 목표에 ×0.97 같은 여유를 둡니다. 가정: 철민 판단
⑥ main 통신이 끊긴 초의 처리를 정합니다. 지금은 통신이 끊기면 총전력이 0으로 들어갑니다. 확인 층 1의 누적에 0이 섞이면 E_r이 실제보다 커지므로, 새 모듈에서는 그 초를 어떻게 다룰지(직전 값 유지, 무효 표시 등)를 따로 정해야 합니다.
⑤ 목표 kW는 하드코딩하지 않습니다. 지금은 cost_applykw 하나지만, 나중에 2단 목표선(하드·소프트)으로 늘릴 수 있도록 계산 모듈은 목표를 입력값으로 받게 만듭니다.
층 1의 값이 실제로 쓰이는 곳은 피크제어(룰), 전원(운전)스케줄러 AI, 피크제어 AI, 화면 네 곳입니다. 부하적응·공정제어와 절전스케줄러는 연결하지 않습니다. 이 장의 중심은 피크제어입니다. 먼저 지금 코드가 어떻게 동작하는지 정리하고, 시뮬레이션 검증 결과를 본 다음, 그 결과에 맞춰 1단계를 다시 정의합니다.
피크제어가 지키려는 것은 15분 평균(요금)이고, 순간 kW 상한은 그걸 지키기 위해 고른 방법입니다. 가정: 철민 판단 코드 대조로 확인한 동작은 아래와 같습니다. 확인
| 항목 | 동작 |
|---|---|
| 레벨 판정 | 1초마다 순간kW ÷ cost_applykw × 100을 auto_control_param의 [위기;경계;주의] 값과 비교(≥). 히스테리시스·유지시간 없음 |
| 걸고 푸는 순서 | 간격(runIntervalSec)마다 한 행씩. 해제를 먼저 처리하고, 해제는 순번 오름차순(레벨 무관). 제어 중인 설비가 0대일 때 첫 ON은 대기 없이 즉시 |
| 레벨 행 | 누적: 현재 레벨 이하의 행이 모두 ON 대상. 설비는 활성 행 중 가장 높은 레벨 행의 값을 씀 |
| PLC로 가는 값 | 피크·평시 제한(정상가동률)은 같은 D1010(가동률 × 10), 부하적응은 D1020(Hz). PLC는 가동률을 전력 비율로 보고 60Hz 기준 Hz = 60 × 가동률1/3로 걸며, 부하적응 Hz와 함께 있으면 낮은 쪽을 쓰고 최종 Hz를 D1020에 다시 씀 확인(11/6, 사내 PLC 시뮬레이터 기준). 서버는 쓰기 성공만 확인하고 D1020을 반영 확인에 쓰지 않음 |
| 정책 우선순위 | 한 설비에 여러 정책을 동시에 등록할 수 있고, 매초 기동 유예 > 절전 > 피크 > 부하적응 > 평시 제한 순서로 그 순간 하나만 적용 확인 (11/6 정정: 이전 판의 "한 설비에 정책 하나가 설계 의도"는 틀린 전제) |
| 간격 설정 | 데모 61초, 개발서버 20초. 설정 행 자동 생성 기본값 3600초는 현장마다 바꾸는 임의값 가정: 철민 판단 |
레벨 행이 누적이라는 점은 예시로 보면 분명해집니다. 경계에 A·B·C, 위험에 B·C를 등록했다면, 위험으로 올라가도 A는 풀리지 않고 경계 값으로 계속 제어되며, B·C는 위험 값으로 바뀝니다. 2차 시뮬레이션에서는 이 누적 방식이 "레벨마다 조합을 교체하는" 방식보다 감축량이 커서 더 안전하게 나왔습니다.
확인할 수 없는 가정이 남아 있어서, 그 가정들을 바꿔 가며 결론이 버티는지 봤습니다. 바꾼 조건은 가동률 해석(Hz 비율 / 전력 비율), 설비 구성(팬 위주 / 정토크 위주), 반영 지연(10 / 30초), 간격(20 / 61초), 기저 부하(낮음 58~70% / 높음 62~74%)로 모두 32개 조합이고, 조합마다 무작위 15분 구간 600개를 돌렸습니다. 판정이 경계에 걸린 칸은 600개를 더 돌려 1200구간 합산으로 판정했습니다.
가동률은 전력 비율로 확인됐습니다(5-1 PLC로 가는 값). 팬류는 가동률만큼, 정토크 설비는 가동률1/3만큼만 줄어(80%를 걸면 약 93%) 위 두 갈래 어느 쪽과도 다릅니다. 이 시뮬레이션의 원래 코드가 남아 있지 않아, 이 절의 설명대로 모델을 새로 만들어 세 가지 해석을 같은 조건(설비 6대 280kW, 레벨 행 누적, 지연·간격·기저 각 두 가지, 1200구간)으로 다시 돌렸습니다 가정.
| 해석 · 설비 구성 | 최대 제한 시 여력 | 현재 방식 초과(1200구간, 중앙값) | P_end+ − 현재 초과 | P_end+ 불필요 제어 감소 |
|---|---|---|---|---|
| Hz 비율 · 팬 위주 | 181kW | 80 | −6 ~ +1 | 20~30% |
| 전력 비율 · 팬 위주 | 98kW | 120 | −6 ~ +2 | 22~34% |
| 확인된 동작 · 팬 위주 | 85kW | 123 | −4 ~ +4 | 22~35% |
| 확인된 동작 · 정토크 위주 | 53kW | 145 | −1 ~ +6 | 27~36% |
① 방식 비교 결론은 그대로입니다. 어느 해석에서도 P_end+는 초과가 현재 방식과 비슷하고(8칸 중 7~8칸이 +4건/1200 이내) 불필요 제어를 20~36% 줄였습니다. 1단계를 P_end+로 정한 근거는 바뀌지 않습니다.
② 바뀌는 것은 여력입니다. "Hz 비율" 갈래는 팬류 감축을 두 배 넘게 크게 봤고(181 대 85kW), 정토크 위주 현장은 같은 레벨 행으로 막을 수 있는 양이 "전력 비율" 갈래의 절반 수준(53 대 98kW)입니다. 그만큼 초과 구간이 늘어납니다(현재 방식 중앙값 120 → 145건). 방식으로 고칠 문제가 아니라, 정토크 설비의 가동률을 더 낮게 잡거나 팬류를 레벨 행 앞쪽에 두는 설정 문제이고, 감축표(6장)가 그 근거가 됩니다.
③ 새 모델은 늦게 들어오는 큰 부하를 원래 모델보다 많이 넣어서 절대 건수가 크고, S-a(여력 안 초과 ≤ 2건)는 이 모델로는 다시 확인되지 않습니다. 아래 표의 수치는 원래 v3 결과입니다. 그중 "Hz 비율" 갈래 칸은 여력을 크게 본 결과이고, 현실에 가장 가까운 것은 "전력 비율 · 팬 위주" 칸입니다.
| 문장 | 판정 기준 | 결과 |
|---|---|---|
| S-a 현재 방식도 대부분 막는다 | 여력 안 초과 ≤ 2건(600구간) | 낮은 기저 16칸 전부 성립. 높은 기저·정토크 위주·간격 61초·지연 30초 한 칸만 깨짐(1200구간 중 5건). 정토크 감축을 실제보다 크게 본 결과. 11/6 재실행에서 정토크 위주 현장은 여력이 절반 수준이라 초과가 늘어남(5-2 위 상자) |
| S-b P_end는 안전성 비슷, 불필요 제어 크게 감소 | 초과 +2건 이내, 불필요 제어 30% 이상 감소 | 불필요 제어 감소는 모든 칸에서 37~58%. 초과 조건이 9칸에서 깨짐(+5 ~ +21건/1200) |
| S-c P_end+는 현재 방식보다 나쁘지 않다 | 초과 +2건 이내, 불필요 제어 ≤ 현재 | 31/32칸 성립. 깨진 한 칸은 초과가 10건 적은데 불필요 제어가 2% 많았음 |
여력이 충분한 구성에서는 15분 피크를 대부분 막습니다. 여력 안에서 넘는 구간은 1200구간 중 최대 2건이었습니다(v3 결과. 11/6 재실행 모델로는 이 수치를 다시 확인하지 못함). 대가는 원래 넘지 않을 구간에서도 순간값만 보고 누르는 것입니다.
생산은 가장 덜 누르지만, 여력이 바닥나거나 간격이 길면 앞에서 넘친 양을 뒤에서 갚지 못해 초과가 늘 수 있습니다. 단독으로는 쓰지 않습니다.
초과는 모든 조건에서 현재 방식보다 적거나 같고(11/6 재실행에서는 현재 방식과 비슷, 1200구간에 −6~+6건), 불필요 제어도 대체로 줄어듭니다(−2 ~ 35%). 절감 폭은 P_end 단독의 절반 정도입니다. 안전을 먼저 지키면서 덜 누르는 쪽으로 옮겨 가는 방식이라, 1단계는 이 형태로 정의합니다.
그림 4의 차이가 어디서 나오는지 보여 주는 단순 사례입니다. 1차 단순 모델(설비 30kW씩 감축)로 그렸으므로 숫자보다는 모양을 보면 됩니다.
v2까지는 1단계를 "getNowPeakLevel의 분자만 P_end로 바꾼다"로 정의했습니다. 검증 결과 이것만으로는 안전성이 보장되지 않아서, 해제 규칙을 1단계에 포함합니다.
P_end + 복귀kW × 남은 시간 ÷ 0.25h + 20kW가 그 레벨 임계보다 낮을 때만 풉니다. 새 파라미터는 해제 여유(20kW) 하나입니다.해제 규칙이 필요한 이유는 아래 순환 때문입니다. 지금 코드에도 걸고 푸는 기준이 같은 임계선이라 같은 구조가 있습니다. 제어 간격이 잦은 변속을 막는 완충 역할을 하지만, 해제 쪽 여유는 따로 고려하지 않은 것으로 보입니다. 가정: 철민 판단
구간 말미 속도 규칙(후보, 미검증). 남은 시간이 남은 후보 수 × runIntervalSec보다 짧으면 간격을 건너뛰고 한 번에 거는 규칙입니다. 간격이 긴 현장(61초)일수록 효과가 있을 것으로 보이지만, 3차 시뮬레이션에서는 따로 돌려 보지 않았습니다. 가정
1단계는 레벨과 해제만 바꾸고 "몇 대를 걸지"는 그대로입니다. 2단계는 ΔP를 채우는 만큼 한 번에 겁니다. 기존 순번대로 예상 감축량을 더해 가다가 ΔP × 1.2에 닿으면 멈춥니다.
설비별 예상 감축량은 가동률과 설비 유형으로 계산합니다. 가동률은 전력 비율이라(11/6 확인) 팬·펌프·블로어는 전력이 가동률만큼 줄고(72%면 약 72%), 공기압축기 같은 정토크 부하는 가동률1/3만큼만 줄어듭니다(72%면 약 90%). 걸고 나서 실제로 몇 kW가 줄었는지는 제어 결과 로그가 쌓이면 실측값으로 바꿉니다.
지금 여유값은 임계값 − 구간 평균, 즉 kW의 차이입니다. 그런데 설비를 켜면 그 부하가 이번 구간의 남은 시간 내내 얹힙니다. 같은 100kW 설비라도 3분에 켜면 이번 구간에 20kWh가 더해지고, 13분에 켜면 3.3kWh만 더해집니다.
기동 허용 조건은 E_r − P_예측 × 남은 시간 ≥ 돌입kW × 지속초 ÷ 3600 + 신규부하kW × 남은 시간으로 바꿉니다. 신규부하kW는 설비 정격 대신 그 설비가 가동 중일 때 kW의 중앙값을 씁니다. 설계문서 23-4의 종료 예상 계산이 코드에 없으므로 이 식으로 채웁니다.
피크제어 AI는 LLM 입력에 P_allow와 P_end를 추가하고, 1단계 이후 바뀐 레벨 기준과 입력이 어긋나지 않게 맞춥니다. 판단은 Python 계산이 하고 LLM은 설명을 맡는 방향이 교수님 권고와도 맞습니다.
운영 주의. 정상가동률은 피크 등록 설비 전체에 공통으로 적용되는 값이고, 피크와 같은 D1010을 씁니다. 그래서 정상가동률이 피크 행 값보다 낮은 상태에서 피크가 걸리면 그 설비의 가동률이 오히려 올라갑니다(예: 65 → 74). 수동으로 그렇게 입력하는 것은 설정으로 피할 수 있습니다. 하지만 피크제어 AI는 예측 레벨이 경계 이상이면 정상가동률 자리에 주의 행 값보다 낮은 값을 쓸 수 있는 구조라, AI를 켠 현장에서는 설정만으로 막을 수 없습니다. 화면과 서버에 둘을 비교하는 검증은 없습니다. 현재 데모·개발 DB 값에는 이런 설비가 없습니다. 확인 이번 범위에서는 수정하지 않고 주의사항으로 둡니다.
층 1이 생기면 운영자에게 "지금 몇 %"가 아니라 "이번 구간이 어떻게 끝날지"를 보여줄 수 있습니다. 수치는 2장의 예시와 같습니다.
아래 주제는 허용량 문서에서 분리해 따로 일정을 잡습니다. 다만 표의 "연결" 열처럼 일부는 층 1·2와 맞물리므로 순서를 정할 때 참고해야 합니다.
| 주제 | 무엇인가 | 층 1·2와의 연결 |
|---|---|---|
| 제어 결과 로그 | 제어마다 설비, 제한율, 직전 kW, 30·60초 후 kW, Hz 기록 | 2단계의 선행 조건. 복귀 kW, C, 예상 감축량을 실측으로 바꿈 |
| M&V 절감 실적 | "제어가 없었다면"과 실제의 차이를 구간마다 기록 | 층 1과 제어 결과 로그 둘 다 필요. 회피 피크 ≈ Σ(감축kW × 제어시간) ÷ 0.25h |
| 피크 위험 시간표 | 요일 × 96구간 통계로 위험 시간대 표시 | 독립. 초반 스파이크(그림 6) 같은 기동 피크 판별에 활용 가능 |
| 공회전·누설 리포트 | 무부하 운전, 주말 압축기 가동으로 낭비 kWh 추정 | 독립. 평상시 절전 쪽 |
| 요금 시간대 이동 | 저장 여유 있는 부하를 경부하로 | 독립. yym_elecCostPolicy.md 의존 |
| 중재 계층 | 설비마다 명령 하나만 나가도록 우선순위 정리 | 독립. 5-3의 임시 규칙이 첫걸음 |
| 예측 AI | 남은 구간의 비제어 부하 예측 | P_예측을 대체. 초반 스파이크의 근본 해결 |
| 2단 목표선 | 요금적용전력(하드)과 낮추고 싶은 목표(소프트) 분리 | 층 1의 목표 정의를 바꿈. 한전 약관 원문 확인 후 |
응답 시간. 걸고 나서 kW가 안정되기까지 몇 초인지는 지금 확인할 방법이 없어 두 갈래(10 / 30초)로 두고 결론을 점검했습니다(5-2). 제어 결과 로그가 쌓이면 실제 값으로 대신할 수 있습니다. 가동률 해석은 11/6에 전력 비율로 확인됐고, 그 전제로 다시 돌린 결과는 5-2의 상자에 있습니다.
층 1을 만든 뒤 바로 제어를 바꾸지 않고, 실제 제어는 기존 방식으로 하면서 P_end+ 기준 레벨을 기록만 합니다. 2주 정도 쌓은 뒤 두 방식을 비교하면 1단계가 실제로 나은지 숫자로 판단할 수 있습니다. 과거 총전력은 1분 단위로만 남아 있어 초 단위 재생은 할 수 없습니다. 확인
1~3차 코드 대조와 시뮬레이션, 질문지 답변을 성격별로 나눴습니다. 위로 갈수록 단단하고, 아래로 갈수록 조건이 붙습니다.
| 구분 | 내용 |
|---|---|
| 확정 코드 사실 | 순간값 레벨 판정(히스테리시스 없음). 해제 우선·순번 오름차순 해제·첫 ON 즉시·간격 게이트. 레벨 행 누적과 설비별 최고 레벨 값. 피크·평시 제한 D1010 공용, 부하적응 D1020. 가동률은 전력 비율(PLC가 60 × 가동률1/3Hz로 환산, 11/6 확인). 쓰기 결과 미검증(D1020으로 확인 가능). main 통신 실패 시 totalkw=0. 재시작 시 15분 누적 소실과 DB 행 덮어쓰기. 15분 평균은 샘플 평균. 설계문서 23-4의 종료 예상 계산 미구현. 정상가동률은 공통 값이고 피크 행 값과의 비교 검증 없음 |
| 철민 판단 전제 | 피크제어의 목표는 15분 평균이고 순간값은 방법이다. 간격은 잦은 변속 방지용이고 해제 여유는 고려되지 않았다. 한 설비에 여러 정책을 동시에 등록해도 되고, 그 순간 우선순위에 따라 한 정책만 쓴다(동시 등록은 설정 실수가 아님, 11/6 정정·코드 확인). 적용전력은 운영자가 입력하고 임계가 안전 여유 역할을 한다. 기본 간격 3600초는 현장마다 바꾼다. 한전 15분 구간 정렬은 출시 전에 맞춘다 |
| 두 갈래로 남는 가정 | 반영 지연(10 / 30초), 설비 구성(팬 / 정토크 위주), 간격(20 / 61초), 기저 부하(낮음 / 높음). 결론은 이 조합 전체에서 점검했다. 가동률 해석은 11/6에 전력 비율로 확인되어 더 이상 갈래가 아님. 그 전제로 재실행한 결과 방식 비교 결론은 같고, 정토크 위주 현장은 여력이 절반 수준(5-2) |
| 결론 | ① 여력이 충분한 구성에서는 현재 방식도 15분 피크를 대부분 막는다. 막을 수 있는 양은 설비 유형에 따라 크게 다르다(가동률은 전력 비율, 정토크 설비는 덜 줄어듦). ② P_end 단독은 생산을 가장 덜 누르지만 여력이 부족하거나 간격이 길면 초과가 늘 수 있어 단독으로 쓰지 않는다. ③ P_end+(해제 시 종료 예상 확인 + 여유)는 초과가 현재 방식과 같은 수준이고 불필요 제어도 줄인다. 1단계는 이 형태로 한다 |
층 1만 끝나도 "지금 구간이 어떻게 가고 있는지"가 숫자로 보입니다. 그림자 모드로 2주 정도 기록하면 1단계를 켜기 전에 실제 데이터로 현재 방식과 P_end+를 비교할 수 있습니다. 교수님과의 다음 미팅에는 그림 6(초반 스파이크)을 들고 가서 "P_예측을 AI로 바꾸면 기동 피크를 구분할 수 있겠느냐"고 묻는 것이 가장 구체적인 역질문입니다.
지금 피크제어는 순간값으로 15분 평균을 간접적으로 지키고 있고, 여력이 충분하면 대부분 막습니다(정토크 위주 현장은 막을 수 있는 양이 절반 수준). 허용량 계산은 같은 목표를 직접 보게 해서, 안전은 그대로 두거나 높이면서 덜 누르게 하는 보강입니다.