calc_tools.py 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657
  1. # -*- coding: utf-8 -*-
  2. """
  3. 煤矿配风计划 - 需风量计算工具模块
  4. 基于《煤矿安全规程》2025 版和 AQ 1056-2008《煤矿通风能力核定标准》,
  5. 实现各用风地点类型的需风量计算工具。
  6. 每个工具函数返回结构化 JSON,包含:
  7. - formula: 计算公式(文字描述)
  8. - expression: 计算表达式(含数值代入)
  9. - steps: 计算步骤列表
  10. - result: 计算结果
  11. - unit: 单位
  12. 工具列表:
  13. - 采煤工作面: calc_face_by_gas / calc_face_by_workers / calc_face_by_wind_speed / calc_face_air_volume_max
  14. - 掘进工作面: calc_tunnel_by_gas / calc_tunnel_by_explosives / calc_tunnel_by_workers / calc_tunnel_by_wind_speed / calc_tunnel_by_vehicle / calc_tunnel_air_volume_max
  15. - 硐室: calc_chamber_by_equipment / calc_chamber_by_wind_speed
  16. - 其他巷道: calc_other_by_wind_speed
  17. - 辅助: calc_effective_area / calc_total_air_volume
  18. - 反算: calc_gas_emission_from_wind(从测风报表风量×浓度反算涌出量)
  19. """
  20. import json
  21. # ============================================================
  22. # 辅助工具
  23. # ============================================================
  24. def calc_effective_area(max_control_distance: float,
  25. min_control_distance: float,
  26. avg_mining_height: float) -> str:
  27. """计算工作面有效断面积。
  28. 公式: S = (L_max + L_min) / 2 × H
  29. 其中 L_max 为最大控顶距,L_min 为最小控顶距,H 为平均采高。
  30. Args:
  31. max_control_distance: 最大控顶距,单位 m
  32. min_control_distance: 最小控顶距,单位 m
  33. avg_mining_height: 平均采高,单位 m
  34. Returns:
  35. JSON格式的计算过程与结果
  36. """
  37. avg_distance = (max_control_distance + min_control_distance) / 2
  38. area = avg_distance * avg_mining_height
  39. return json.dumps({
  40. "formula": "S = (L_max + L_min) / 2 × H",
  41. "expression": f"S = ({max_control_distance} + {min_control_distance}) / 2 × {avg_mining_height}",
  42. "steps": [
  43. f"平均控顶距 = ({max_control_distance} + {min_control_distance}) / 2 = {avg_distance:.2f} m",
  44. f"有效断面积 = {avg_distance:.2f} × {avg_mining_height} = {area:.2f} m²",
  45. ],
  46. "result": round(area, 2),
  47. "unit": "m²",
  48. }, ensure_ascii=False)
  49. # ============================================================
  50. # 采煤工作面需风量计算
  51. # ============================================================
  52. def calc_face_by_gas(q_gas: float, k_gas: float = 1.5) -> str:
  53. """按瓦斯涌出量计算采煤工作面需风量。
  54. 公式: Q = 100 × q_gas × K_gas
  55. 依据: 按瓦斯涌出量计算,K_gas 为瓦斯涌出不均衡系数(1.2~1.6)
  56. Args:
  57. q_gas: 平均绝对瓦斯涌出量,单位 m³/min
  58. k_gas: 瓦斯涌出不均衡系数,默认 1.5
  59. Returns:
  60. JSON格式的计算过程与结果
  61. """
  62. result = 100 * q_gas * k_gas
  63. return json.dumps({
  64. "formula": "Q_cf = 100 × q_gas × K_gas",
  65. "expression": f"Q_cf = 100 × {q_gas} × {k_gas}",
  66. "steps": [
  67. f"Q_cf = 100 × {q_gas} × {k_gas}",
  68. f"Q_cf = {100 * q_gas:.2f} × {k_gas}",
  69. f"Q_cf = {result:.2f} m³/min",
  70. ],
  71. "result": round(result, 2),
  72. "unit": "m³/min",
  73. }, ensure_ascii=False)
  74. def calc_face_by_workers(n: int) -> str:
  75. """按同时工作最多人数计算采煤工作面需风量。
  76. 公式: Q = 4 × N
  77. 依据: 每人供风量不小于 4 m³/min
  78. Args:
  79. n: 同时工作最多人数
  80. Returns:
  81. JSON格式的计算过程与结果
  82. """
  83. result = 4 * n
  84. return json.dumps({
  85. "formula": "Q_cf = 4 × N",
  86. "expression": f"Q_cf = 4 × {n}",
  87. "steps": [
  88. f"Q_cf = 4 × {n}",
  89. f"Q_cf = {result:.2f} m³/min",
  90. ],
  91. "result": round(result, 2),
  92. "unit": "m³/min",
  93. }, ensure_ascii=False)
  94. def calc_face_by_wind_speed(v: float, s: float) -> str:
  95. """按风速验算采煤工作面需风量。
  96. 公式: Q = 60 × S × v
  97. 验算条件: 0.25 ≤ v ≤ 4.0 m/s(采煤工作面最低/最高风速)
  98. Args:
  99. v: 设计风速,单位 m/s
  100. s: 有效断面积,单位 m²(可使用 calc_effective_area 计算)
  101. Returns:
  102. JSON格式的计算过程与结果
  103. """
  104. result = 60 * s * v
  105. return json.dumps({
  106. "formula": "Q_cf = 60 × S × v",
  107. "expression": f"Q_cf = 60 × {s} × {v}",
  108. "steps": [
  109. f"Q_cf = 60 × {s} × {v}",
  110. f"Q_cf = {60 * s:.2f} × {v}",
  111. f"Q_cf = {result:.2f} m³/min",
  112. ],
  113. "result": round(result, 2),
  114. "unit": "m³/min",
  115. "wind_speed_check": {
  116. "v_min": 0.25,
  117. "v_max": 4.0,
  118. "passed": 0.25 <= v <= 4.0,
  119. },
  120. }, ensure_ascii=False)
  121. def calc_face_air_volume_max(q_gas: float = 0,
  122. q_co2: float = 0,
  123. k_gas: float = 1.5,
  124. n_workers: int = 0,
  125. v_wind: float = 0,
  126. s_area: float = 0) -> str:
  127. """采煤工作面需风量综合计算 —— 取各方法最大值。
  128. 按瓦斯、二氧化碳、人数、风速分别计算,取最大值作为最终需风量。
  129. 同时验算风速是否在 0.25~4.0 m/s 范围内。
  130. Args:
  131. q_gas: 平均绝对瓦斯涌出量,m³/min
  132. q_co2: 平均绝对二氧化碳涌出量,m³/min
  133. k_gas: 瓦斯涌出不均衡系数,默认 1.5
  134. n_workers: 同时工作最多人数
  135. v_wind: 设计风速,m/s
  136. s_area: 有效断面积,m²
  137. Returns:
  138. JSON格式的综合计算过程与结果
  139. """
  140. results = {}
  141. if q_gas > 0:
  142. results["按瓦斯涌出量"] = 100 * q_gas * k_gas
  143. if q_co2 > 0:
  144. # 二氧化碳涌出量:按 67 × q_co2 × K
  145. results["按二氧化碳涌出量"] = 67 * q_co2 * k_gas
  146. if n_workers > 0:
  147. results["按人数"] = 4 * n_workers
  148. if v_wind > 0 and s_area > 0:
  149. q_wind = 60 * s_area * v_wind
  150. results["按风速"] = q_wind
  151. v_check = 0.25 <= v_wind <= 4.0
  152. else:
  153. q_wind = 0
  154. v_check = None
  155. if not results:
  156. return json.dumps({
  157. "error": "请至少提供一种计算参数(q_gas、q_co2、n_workers、v_wind + s_area)",
  158. }, ensure_ascii=False)
  159. max_method = max(results, key=results.get)
  160. max_value = results[max_method]
  161. steps = []
  162. for method, val in results.items():
  163. steps.append(f"{method}: {val:.2f} m³/min")
  164. steps.append(f"取最大值: {max_method} = {max_value:.2f} m³/min")
  165. return json.dumps({
  166. "formula": "Q_cf = max(Q_gas, Q_co2, Q_workers, Q_wind)",
  167. "methods": {k: round(v, 2) for k, v in results.items()},
  168. "steps": steps,
  169. "result": round(max_value, 2),
  170. "max_method": max_method,
  171. "unit": "m³/min",
  172. "wind_speed_check": {
  173. "v_min": 0.25,
  174. "v_max": 4.0,
  175. "passed": v_check,
  176. } if v_check is not None else None,
  177. }, ensure_ascii=False)
  178. # ============================================================
  179. # 掘进工作面需风量计算
  180. # ============================================================
  181. def calc_tunnel_by_gas(q_gas: float, k_gas: float = 1.8) -> str:
  182. """按瓦斯涌出量计算掘进工作面需风量。
  183. 公式: Q = 100 × q_gas × K_gas
  184. 掘进工作面瓦斯不均衡系数通常取 1.8~2.0
  185. Args:
  186. q_gas: 平均绝对瓦斯涌出量,单位 m³/min
  187. k_gas: 瓦斯涌出不均衡系数,默认 1.8
  188. Returns:
  189. JSON格式的计算过程与结果
  190. """
  191. result = 100 * q_gas * k_gas
  192. return json.dumps({
  193. "formula": "Q_hf = 100 × q_gas × K_gas",
  194. "expression": f"Q_hf = 100 × {q_gas} × {k_gas}",
  195. "steps": [
  196. f"Q_hf = 100 × {q_gas} × {k_gas}",
  197. f"Q_hf = {100 * q_gas:.2f} × {k_gas}",
  198. f"Q_hf = {result:.2f} m³/min",
  199. ],
  200. "result": round(result, 2),
  201. "unit": "m³/min",
  202. }, ensure_ascii=False)
  203. def calc_tunnel_by_explosives(a: float) -> str:
  204. """按炸药量计算掘进工作面需风量。
  205. 公式: Q = 25 × A
  206. 其中 A 为一次爆破最大炸药用量,kg
  207. Args:
  208. a: 一次爆破最大炸药用量,单位 kg
  209. Returns:
  210. JSON格式的计算过程与结果
  211. """
  212. result = 25 * a
  213. return json.dumps({
  214. "formula": "Q_hf = 25 × A",
  215. "expression": f"Q_hf = 25 × {a}",
  216. "steps": [
  217. f"Q_hf = 25 × {a}",
  218. f"Q_hf = {result:.2f} m³/min",
  219. ],
  220. "result": round(result, 2),
  221. "unit": "m³/min",
  222. }, ensure_ascii=False)
  223. def calc_tunnel_by_workers(n: int) -> str:
  224. """按同时工作最多人数计算掘进工作面需风量。
  225. 公式: Q = 4 × N
  226. Args:
  227. n: 同时工作最多人数
  228. Returns:
  229. JSON格式的计算过程与结果
  230. """
  231. result = 4 * n
  232. return json.dumps({
  233. "formula": "Q_hf = 4 × N",
  234. "expression": f"Q_hf = 4 × {n}",
  235. "steps": [
  236. f"Q_hf = 4 × {n}",
  237. f"Q_hf = {result:.2f} m³/min",
  238. ],
  239. "result": round(result, 2),
  240. "unit": "m³/min",
  241. }, ensure_ascii=False)
  242. def calc_tunnel_by_wind_speed(v: float, s: float) -> str:
  243. """按风速验算掘进工作面需风量。
  244. 公式: Q = 60 × S × v
  245. 验算条件: 0.25 ≤ v ≤ 4.0 m/s(掘进工作面最低/最高风速)
  246. 注意:岩巷最低风速为 0.15 m/s
  247. Args:
  248. v: 设计风速,单位 m/s
  249. s: 有效断面积,单位 m²
  250. Returns:
  251. JSON格式的计算过程与结果
  252. """
  253. result = 60 * s * v
  254. return json.dumps({
  255. "formula": "Q_hf = 60 × S × v",
  256. "expression": f"Q_hf = 60 × {s} × {v}",
  257. "steps": [
  258. f"Q_hf = 60 × {s} × {v}",
  259. f"Q_hf = {60 * s:.2f} × {v}",
  260. f"Q_hf = {result:.2f} m³/min",
  261. ],
  262. "result": round(result, 2),
  263. "unit": "m³/min",
  264. "wind_speed_check": {
  265. "v_min": 0.25,
  266. "v_max": 4.0,
  267. "note": "岩巷最低风速为 0.15 m/s",
  268. "passed": 0.25 <= v <= 4.0,
  269. },
  270. }, ensure_ascii=False)
  271. def calc_tunnel_by_vehicle(total_power: float,
  272. k_vehicle: float = 0.8,
  273. vehicle_count: int = 1) -> str:
  274. """按防爆柴油机车(胶轮车)功率计算掘进工作面需风量。
  275. 公式: Q = 4 × ΣP × K
  276. 依据: 《煤矿安全规程》—— 使用防爆柴油机车(无轨胶轮车)的掘进工作面,
  277. 需风量按同时运行车辆总功率计算,每 kW 供风量不小于 4 m³/min。
  278. K 为车辆同时运行系数。
  279. Args:
  280. total_power: 防爆柴油机车总功率(同时运行),单位 kW
  281. k_vehicle: 车辆同时运行系数,默认 0.8(0.5~1.0)
  282. vehicle_count: 同时运行车辆数,默认 1
  283. Returns:
  284. JSON格式的计算过程与结果
  285. """
  286. result = 4 * total_power * k_vehicle
  287. return json.dumps({
  288. "formula": "Q_hf = 4 × ΣP × K",
  289. "expression": f"Q_hf = 4 × {total_power} × {k_vehicle}",
  290. "steps": [
  291. f"车辆总功率 ΣP = {total_power} kW",
  292. f"同时运行系数 K = {k_vehicle}({vehicle_count} 辆车)",
  293. f"Q_hf = 4 × {total_power} × {k_vehicle}",
  294. f"Q_hf = {4 * total_power:.2f} × {k_vehicle}",
  295. f"Q_hf = {result:.2f} m³/min",
  296. ],
  297. "result": round(result, 2),
  298. "unit": "m³/min",
  299. "params": {
  300. "total_power_kw": total_power,
  301. "k_vehicle": k_vehicle,
  302. "vehicle_count": vehicle_count,
  303. },
  304. "note": "每 kW 柴油机功率供风量 ≥ 4 m³/min(《煤矿安全规程》)",
  305. }, ensure_ascii=False)
  306. def calc_tunnel_air_volume_max(q_gas: float = 0,
  307. q_co2: float = 0,
  308. k_gas: float = 1.8,
  309. a_explosives: float = 0,
  310. n_workers: int = 0,
  311. v_wind: float = 0,
  312. s_area: float = 0,
  313. p_vehicle: float = 0,
  314. k_vehicle: float = 0.8) -> str:
  315. """掘进工作面需风量综合计算 —— 取各方法最大值。
  316. 按瓦斯、二氧化碳、炸药量、人数、风速、胶轮车分别计算,取最大值。
  317. 同时验算风速是否在 0.25~4.0 m/s 范围内。
  318. Args:
  319. q_gas: 平均绝对瓦斯涌出量,m³/min
  320. q_co2: 平均绝对二氧化碳涌出量,m³/min
  321. k_gas: 瓦斯涌出不均衡系数,默认 1.8
  322. a_explosives: 一次爆破最大炸药用量,kg
  323. n_workers: 同时工作最多人数
  324. v_wind: 设计风速,m/s
  325. s_area: 有效断面积,m²
  326. p_vehicle: 防爆柴油机车(胶轮车)总功率,kW
  327. k_vehicle: 车辆同时运行系数,默认 0.8
  328. Returns:
  329. JSON格式的综合计算过程与结果
  330. """
  331. results = {}
  332. if q_gas > 0:
  333. results["按瓦斯涌出量"] = 100 * q_gas * k_gas
  334. if q_co2 > 0:
  335. results["按二氧化碳涌出量"] = 67 * q_co2 * k_gas
  336. if a_explosives > 0:
  337. results["按炸药量"] = 25 * a_explosives
  338. if n_workers > 0:
  339. results["按人数"] = 4 * n_workers
  340. if v_wind > 0 and s_area > 0:
  341. results["按风速"] = 60 * s_area * v_wind
  342. v_check = 0.25 <= v_wind <= 4.0
  343. else:
  344. v_check = None
  345. if p_vehicle > 0:
  346. results["按胶轮车"] = 4 * p_vehicle * k_vehicle
  347. if not results:
  348. return json.dumps({
  349. "error": "请至少提供一种计算参数",
  350. }, ensure_ascii=False)
  351. max_method = max(results, key=results.get)
  352. max_value = results[max_method]
  353. steps = []
  354. for method, val in results.items():
  355. steps.append(f"{method}: {val:.2f} m³/min")
  356. steps.append(f"取最大值: {max_method} = {max_value:.2f} m³/min")
  357. return json.dumps({
  358. "formula": "Q_hf = max(Q_gas, Q_co2, Q_explosives, Q_workers, Q_wind, Q_vehicle)",
  359. "methods": {k: round(v, 2) for k, v in results.items()},
  360. "steps": steps,
  361. "result": round(max_value, 2),
  362. "max_method": max_method,
  363. "unit": "m³/min",
  364. "wind_speed_check": {
  365. "v_min": 0.25,
  366. "v_max": 4.0,
  367. "passed": v_check,
  368. } if v_check is not None else None,
  369. }, ensure_ascii=False)
  370. # ============================================================
  371. # 硐室需风量计算
  372. # ============================================================
  373. def calc_chamber_by_equipment(total_power: float,
  374. efficiency: float = 0.85,
  375. temp_rise: float = 10.0) -> str:
  376. """按机电设备发热量计算硐室需风量。
  377. 公式: Q = 3600 × θ × ΣN / (ρ × C_p × Δt)
  378. 简化: Q ≈ 0.1 × ΣN (常规硐室估算)
  379. 或精确: Q = ΣN × (1 - η) / (C_p × ρ × Δt) × 60
  380. 此处使用机电设备功率简化计算。
  381. Args:
  382. total_power: 硐室内机电设备总功率,kW
  383. efficiency: 设备平均效率,默认 0.85
  384. temp_rise: 允许温升,℃,默认 10
  385. Returns:
  386. JSON格式的计算过程与结果
  387. """
  388. # 发热量: θ = (1 - η) × ΣN
  389. heat = (1 - efficiency) * total_power # kW 发热量
  390. # Q = 3600 × θ / (ρ × C_p × Δt) → 空气密度 1.2 kg/m³, 比热 1.005 kJ/(kg·℃)
  391. result = 3600 * heat / (1.2 * 1.005 * temp_rise)
  392. return json.dumps({
  393. "formula": "Q = 3600 × (1 - η) × ΣN / (ρ × C_p × Δt)",
  394. "expression": f"Q = 3600 × (1 - {efficiency}) × {total_power} / (1.2 × 1.005 × {temp_rise})",
  395. "steps": [
  396. f"发热量 θ = (1 - {efficiency}) × {total_power} = {heat:.2f} kW",
  397. f"Q = 3600 × {heat:.2f} / (1.2 × 1.005 × {temp_rise})",
  398. f"Q = {3600 * heat:.2f} / {1.2 * 1.005 * temp_rise:.2f}",
  399. f"Q = {result:.2f} m³/min",
  400. ],
  401. "result": round(result, 2),
  402. "unit": "m³/min",
  403. }, ensure_ascii=False)
  404. def calc_chamber_by_wind_speed(v: float, s: float) -> str:
  405. """按风速验算硐室需风量。
  406. 依据: 机电硐室最低风速 0.15 m/s,最高 6.0 m/s(无瓦斯涌出)
  407. Args:
  408. v: 设计风速,m/s
  409. s: 有效断面积,m²
  410. Returns:
  411. JSON格式的计算过程与结果
  412. """
  413. result = 60 * s * v
  414. return json.dumps({
  415. "formula": "Q = 60 × S × v",
  416. "expression": f"Q = 60 × {s} × {v}",
  417. "steps": [
  418. f"Q = 60 × {s} × {v}",
  419. f"Q = {60 * s:.2f} × {v}",
  420. f"Q = {result:.2f} m³/min",
  421. ],
  422. "result": round(result, 2),
  423. "unit": "m³/min",
  424. "wind_speed_check": {
  425. "v_min": 0.15,
  426. "v_max": 6.0,
  427. "passed": 0.15 <= v <= 6.0,
  428. },
  429. }, ensure_ascii=False)
  430. # ============================================================
  431. # 其他巷道需风量计算
  432. # ============================================================
  433. def calc_other_by_wind_speed(v: float, s: float, tunnel_type: str = "other") -> str:
  434. """按风速计算其他巷道需风量。
  435. 公式: Q = 60 × S × v
  436. 风速限值因巷道类型不同:
  437. - 主要进回风巷: v ≤ 8 m/s
  438. - 其他通风人行巷道: v ≥ 0.15 m/s
  439. - 运输机巷、采区进回风巷: 0.25 ≤ v ≤ 6 m/s
  440. Args:
  441. v: 设计风速,m/s
  442. s: 有效断面积,m²
  443. tunnel_type: 巷道类型 (main_in: 主要进风, main_out: 主要回风, mining: 采区, other: 其他)
  444. Returns:
  445. JSON格式的计算过程与结果
  446. """
  447. result = 60 * s * v
  448. # 各类型风速限值
  449. limits = {
  450. "main_in": {"v_min": None, "v_max": 8.0, "desc": "主要进风巷"},
  451. "main_out": {"v_min": None, "v_max": 8.0, "desc": "主要回风巷"},
  452. "mining": {"v_min": 0.25, "v_max": 6.0, "desc": "采区进回风巷"},
  453. "other": {"v_min": 0.15, "v_max": None, "desc": "其他通风人行巷道"},
  454. }
  455. limit = limits.get(tunnel_type, limits["other"])
  456. return json.dumps({
  457. "formula": "Q = 60 × S × v",
  458. "expression": f"Q = 60 × {s} × {v}",
  459. "steps": [
  460. f"Q = 60 × {s} × {v}",
  461. f"Q = {60 * s:.2f} × {v}",
  462. f"Q = {result:.2f} m³/min",
  463. ],
  464. "result": round(result, 2),
  465. "unit": "m³/min",
  466. "tunnel_type": limit["desc"],
  467. "wind_speed_limits": {
  468. "v_min": limit["v_min"],
  469. "v_max": limit["v_max"],
  470. },
  471. }, ensure_ascii=False)
  472. # ============================================================
  473. # 瓦斯/CO2 涌出量反算(从测风报表数据推算)
  474. # ============================================================
  475. def calc_gas_emission_from_wind(wind_volume: float,
  476. concentration: float,
  477. gas_type: str = "CH4") -> str:
  478. """根据回风顺槽实测风量和浓度反算绝对瓦斯/CO2涌出量。
  479. 公式: q = Q × C / 100
  480. 其中 Q 为回风顺槽实测风量(m³/min),C 为瓦斯或CO2浓度(%)。
  481. 用于数据一致性审查:将测风报表中反算的涌出量与配风计划中的数值对比。
  482. Args:
  483. wind_volume: 回风顺槽实测风量,单位 m³/min
  484. concentration: 瓦斯或CO2浓度,单位 %(如 0.3 表示 0.3%)
  485. gas_type: 气体类型,"CH4"(瓦斯)或 "CO2"(二氧化碳)
  486. Returns:
  487. JSON格式的计算过程与结果
  488. """
  489. result = wind_volume * concentration / 100.0
  490. gas_label = "绝对瓦斯涌出量" if gas_type.upper() == "CH4" else "绝对二氧化碳涌出量"
  491. gas_symbol = "q_gas" if gas_type.upper() == "CH4" else "q_co2"
  492. return json.dumps({
  493. "formula": f"{gas_symbol} = Q × C / 100",
  494. "expression": f"{gas_symbol} = {wind_volume} × {concentration} / 100",
  495. "steps": [
  496. f"回风顺槽实测风量 Q = {wind_volume} m³/min",
  497. f"{'瓦斯' if gas_type.upper() == 'CH4' else 'CO₂'}浓度 C = {concentration}%",
  498. f"{gas_label} = {wind_volume} × {concentration} / 100",
  499. f"{gas_label} = {wind_volume * concentration:.2f} / 100",
  500. f"{gas_label} = {result:.4f} m³/min",
  501. ],
  502. "result": round(result, 4),
  503. "unit": "m³/min",
  504. "gas_type": gas_type.upper(),
  505. "gas_label": gas_label,
  506. "source": "测风报表反算",
  507. }, ensure_ascii=False)
  508. # ============================================================
  509. # 汇总工具
  510. # ============================================================
  511. def calc_total_air_volume(air_volumes: list[dict]) -> str:
  512. """汇总各用风地点需风量,计算矿井总需风量。
  513. 将各用风地点的需风量求和,得到矿井总需风量。
  514. Args:
  515. air_volumes: 各用风地点需风量列表,格式 [{name: str, q: float}, ...]
  516. Returns:
  517. JSON格式的汇总结果
  518. """
  519. if not air_volumes:
  520. return json.dumps({"error": "请提供各用风地点需风量数据"}, ensure_ascii=False)
  521. total = sum(item.get("q", 0) for item in air_volumes)
  522. details = [f"{item.get('name', '未知')}: {item.get('q', 0):.2f} m³/min" for item in air_volumes]
  523. return json.dumps({
  524. "formula": "Q_total = ΣQ_i",
  525. "steps": details + [f"总需风量 = {total:.2f} m³/min"],
  526. "result": round(total, 2),
  527. "location_count": len(air_volumes),
  528. "unit": "m³/min",
  529. }, ensure_ascii=False)