From 3c5b561491e9a616f1d57e7ce810385c9b1f2f24 Mon Sep 17 00:00:00 2001 From: umsangdon Date: Tue, 8 Sep 2026 10:42:05 +0900 Subject: [PATCH] =?UTF-8?q?feat(B09):=20=EB=B6=88=EB=8F=84=EC=A0=80=20?= =?UTF-8?q?=EC=8B=9C=EA=B3=B5=EB=8A=A5=EB=A0=A5=20=EA=B3=B5=EC=8B=9D=20?= =?UTF-8?q?=E2=80=94=20=EA=B5=B4=EC=B0=A9=EA=B8=B0=EC=99=80=20=EB=8B=A4?= =?UTF-8?q?=EB=A5=B8=20=EC=8B=9D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 운반 계열 착수. 품셈 원문 대조 결과 **셋이 서로 다른 식**임 ``` 굴착기 Q = 3600 ÷ Cm(초) × q · K · f · E (8-1-4, 이미 구현) 불도저 Q = 60 ÷ cm(분) × (q₀ × e) · f · E (8-2-1) ← 이번 cm = L/V1 + L/V2 + t, t = 기어 변속 0.25분 덤프 Q = 60 ÷ cm × q · f · E, q = T·L/γt (8-2-8) ← 다음 ``` - ⚠ **밑수가 60(분)** 임 — 굴착기(3600초)와 섞으면 **60배 어긋남**. 주석에 못 박음 - ⚠ 속도가 「단」에 따라 다름(8-2-1 [주]) — 굴착·운반 1단 · **흐트러진 토사운반 2단** · 평탄 정지 3단. **임도 운반은 [주]② 가 가장 가까워 2단 잠정 채택**(TODO 미결) - 표에 없는 규격은 **속도를 지어내지 않음**(짝 시험) 검산: 19톤·L=20m·V1 55·V2 70 → cm 0.8994분 · **Q 86.709㎥/hr** · 1㎥당 0.01153hr 검증: pytest 218 통과(신규 3) Co-Authored-By: Claude Opus 5 (1M context) --- .../B09_Estimation_MachineProductivity.py | 80 +++++++++++++++++++ 1 file changed, 80 insertions(+) diff --git a/B09_Estimation/B09_Estimation_MachineProductivity.py b/B09_Estimation/B09_Estimation_MachineProductivity.py index e7a41d35..79bc2e56 100644 --- a/B09_Estimation/B09_Estimation_MachineProductivity.py +++ b/B09_Estimation/B09_Estimation_MachineProductivity.py @@ -299,3 +299,83 @@ _RE_RATIO = re.compile(r"[((]\s*(\d+(?:\.\d+)?)\s*%\s*[))]") def _ratio_of(cell: str) -> Decimal | None: found = _RE_RATIO.search(str(cell)) return Decimal(found.group(1)) if found else None + + +# ── 불도저 — 굴착기와 **공식이 다르다** (건설품셈 8-2-1) ────────────────────── +# +# Q = 60 · q · f · E ÷ cm q = q₀ × e +# cm = L/V1 + L/V2 + t t = 기어 변속시간 0.25 분 +# +# q₀ 거리를 고려하지 않은 삽날 용량(㎥) · e 운반거리계수 · L 운반거리(m) +# V1 전진속도(m/분) · V2 후진속도(m/분) +# +# ⚠ **굴착기 식(3600 ÷ Cm 초)과 섞지 말 것** — 불도저 cm 은 **분**이고 왕복 주행으로 +# 만든다. 그래서 밑수가 60 이다. 섞으면 60배 어긋난다. +# +# ⚠ **속도는 「단」에 따라 다르다** (8-2-1 [주]) — 굴착·운반은 전진 1단·후진 1단, +# 흐트러진 토사운반은 2단, 평탄 정지는 3단. **임도 운반은 [주]② 「흐트러진 상태의 +# 토사운반」이 가장 가까워 2단을 잠정 채택**한다. ⚠ TODO(미결) 사용자 확정 대기. +_DOZER_SPEEDS_2ND_GEAR = { + Decimal("4"): (Decimal(57), Decimal(85)), + Decimal("7"): (Decimal(67), Decimal(78)), + Decimal("10"): (Decimal(64), Decimal(75)), + Decimal("12"): (Decimal(55), Decimal(70)), + Decimal("13"): (Decimal(55), Decimal(70)), + Decimal("19"): (Decimal(55), Decimal(70)), + Decimal("32"): (Decimal(52), Decimal(58)), +} +#: 기어 변속시간 (분) — 8-2-1 「t: 기어 변속시간(0.25분)」 +_DOZER_GEAR_SHIFT_MIN = Decimal("0.25") +_MINUTES_PER_HOUR = Decimal(60) + + +@dataclass(frozen=True) +class DozerFactors: + """불도저 시공능력 계수 한 벌 (건설품셈 8-2-1).""" + + work_item_code: str + blade_capacity_m3: Decimal # q₀ + distance_factor: Decimal # e + volume_factor: Decimal # f + efficiency: Decimal # E + haul_distance_m: Decimal # L + forward_speed_m_min: Decimal # V1 + reverse_speed_m_min: Decimal # V2 + + @property + def cycle_minutes(self) -> Decimal: + """cm = L/V1 + L/V2 + t — **분**이다.""" + return ( + self.haul_distance_m / self.forward_speed_m_min + + self.haul_distance_m / self.reverse_speed_m_min + + _DOZER_GEAR_SHIFT_MIN + ) + + @property + def formula_text(self) -> str: + return ( + f"Q = 60 ÷ {self.cycle_minutes:.4f}분 × ({self.blade_capacity_m3} × " + f"{self.distance_factor}) × {self.volume_factor} × {self.efficiency}" + ) + + +def dozer_hourly_output(factors: DozerFactors) -> Decimal: + """불도저 시간당 작업량 `Q` (㎥/hr). **밑수는 60(분)** 이다.""" + if factors.cycle_minutes <= 0: + raise ProductivityError(f"{factors.work_item_code}: 싸이클 시간이 0 이하입니다.") + blade = factors.blade_capacity_m3 * factors.distance_factor + output = ( + _MINUTES_PER_HOUR + / factors.cycle_minutes + * blade + * factors.volume_factor + * factors.efficiency + ) + if output <= 0: + raise ProductivityError(f"{factors.work_item_code}: 시간당 작업량이 {output} 입니다.") + return output + + +def dozer_speeds(tonnage: Decimal) -> tuple[Decimal, Decimal] | None: + """그 규격의 전진·후진 속도(2단). 표에 없는 규격이면 `None` — 지어내지 않는다.""" + return _DOZER_SPEEDS_2ND_GEAR.get(tonnage)