fixed_DQN_decide.py 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233
  1. import numpy as np
  2. from stable_baselines3 import DQN
  3. from fixed_DQN_env import UFSuperCycleEnv, UFParams
  4. from fixed_DQN_env import simulate_one_supercycle
  5. # 模型路径
  6. MODEL_PATH = "model/dqn_model.zip"
  7. # 加载模型(只加载一次,提高效率)
  8. model = DQN.load(MODEL_PATH)
  9. def run_uf_DQN_decide(uf_params, TMP0_value: float):
  10. """
  11. 单步决策函数(新版):
  12. 当前模型只输出进水时间 L_s,不输出反洗时间。
  13. """
  14. # 1. 初始化环境
  15. env = UFSuperCycleEnv(uf_params)
  16. # 2. 设置 TMP0
  17. env.current_params.TMP0 = TMP0_value
  18. # 3. 获取观察(归一化)
  19. obs = env._get_obs().reshape(1, -1)
  20. # 4. 模型预测动作
  21. action, _ = model.predict(obs, deterministic=True)
  22. # 5. 新模型动作只返回 L_s
  23. L_s = env._get_action_values(action[0]) # 单值
  24. # 6. 在环境中执行动作
  25. next_obs, reward, terminated, truncated, info = env.step(action[0])
  26. # 7. 返回结构化结果
  27. return {
  28. "action": int(action[0]),
  29. "L_s": float(L_s),
  30. "t_bw_s": None, # 保留字段但固定为 None
  31. "next_obs": next_obs,
  32. "reward": reward,
  33. "terminated": terminated,
  34. "truncated": truncated,
  35. "info": info
  36. }
  37. def generate_plc_instructions(current_L_s, model_prev_L_s, model_L_s):
  38. """
  39. 根据工厂当前值、模型上一轮决策值和模型当前轮决策值,生成PLC指令。
  40. 新增功能:
  41. 1. 处理None值情况:如果模型上一轮值为None,则使用工厂当前值;
  42. 如果工厂当前值也为None,则返回None并提示错误。
  43. """
  44. # 参数配置保持不变
  45. params = UFParams(
  46. L_min_s=3600.0, L_max_s=4800.0, L_step_s=60.0,
  47. )
  48. # 参数解包
  49. L_step_s = params.L_step_s
  50. L_min_s = params.L_min_s
  51. L_max_s = params.L_max_s
  52. adjustment_threshold = 1.0
  53. # 处理None值情况
  54. if model_prev_L_s is None:
  55. if current_L_s is None:
  56. print("错误: 过滤时长的工厂当前值和模型上一轮值均为None")
  57. return None, None
  58. else:
  59. # 使用工厂当前值作为基准
  60. effective_current_L = current_L_s
  61. source_L = "工厂当前值(模型上一轮值为None)"
  62. else:
  63. # 模型上一轮值不为None,继续检查工厂当前值
  64. if current_L_s is None:
  65. effective_current_L = model_prev_L_s
  66. source_L = "模型上一轮值(工厂当前值为None)"
  67. else:
  68. effective_current_L = model_prev_L_s
  69. source_L = "模型上一轮值"
  70. # 检测所有输入值是否在规定范围内(只对非None值进行检查)
  71. # 工厂当前值检查(警告)
  72. if current_L_s is not None and not (L_min_s <= current_L_s <= L_max_s):
  73. print(f"警告: 当前过滤时长 {current_L_s} 秒不在允许范围内 [{L_min_s}, {L_max_s}]")
  74. # 模型上一轮决策值检查(警告)
  75. if model_prev_L_s is not None and not (L_min_s <= model_prev_L_s <= L_max_s):
  76. print(f"警告: 模型上一轮过滤时长 {model_prev_L_s} 秒不在允许范围内 [{L_min_s}, {L_max_s}]")
  77. # 模型当前轮决策值检查(错误)
  78. if model_L_s is None:
  79. raise ValueError("错误: 决策模型建议的过滤时长不能为None")
  80. elif not (L_min_s <= model_L_s <= L_max_s):
  81. raise ValueError(f"错误: 决策模型建议的过滤时长 {model_L_s} 秒不在允许范围内 [{L_min_s}, {L_max_s}]")
  82. print(f"过滤时长基准: {source_L}, 值: {effective_current_L}")
  83. # 使用选定的基准值进行计算调整
  84. L_diff = model_L_s - effective_current_L
  85. L_adjustment = 0
  86. if abs(L_diff) >= adjustment_threshold * L_step_s:
  87. if L_diff >= 0:
  88. L_adjustment = L_step_s
  89. else:
  90. L_adjustment = -L_step_s
  91. next_L_s = effective_current_L + L_adjustment
  92. return next_L_s
  93. def calc_uf_cycle_metrics(p, TMP0, max_tmp_during_filtration, min_tmp_during_filtration, L_s: float, t_bw_s):
  94. """
  95. 计算 UF 超滤系统的核心性能指标
  96. 参数:
  97. p (UFParams): UF 系统参数
  98. L_s (float): 单次过滤时间(秒)
  99. t_bw_s (float): 单次反洗时间(秒)
  100. 返回:
  101. dict: {
  102. "k_bw_per_ceb": 小周期次数,
  103. "ton_water_energy_kWh_per_m3": 吨水电耗,
  104. "recovery": 回收率,
  105. "net_delivery_rate_m3ph": 净供水率 (m³/h),
  106. "daily_prod_time_h": 日均产水时间 (小时/天)
  107. "max_permeability": 全周期最高渗透率(lmh/bar)
  108. }
  109. """
  110. # 将跨膜压差写入参数
  111. p.TMP0 = TMP0
  112. # 模拟该参数下的超级周期
  113. info, next_params = simulate_one_supercycle(p, L_s, t_bw_s)
  114. # 获得模型模拟周期信息
  115. k_bw_per_ceb = info["k_bw_per_ceb"]
  116. ton_water_energy_kWh_per_m3 = info["ton_water_energy_kWh_per_m3"]
  117. recovery = info["recovery"]
  118. daily_prod_time_h = info["daily_prod_time_h"]
  119. # 获得模型模拟周期内最高跨膜压差/最低跨膜压差
  120. if max_tmp_during_filtration is None:
  121. max_tmp_during_filtration = info["max_TMP_during_filtration"]
  122. if min_tmp_during_filtration is None:
  123. min_tmp_during_filtration = info["min_TMP_during_filtration"]
  124. # 计算最高渗透率
  125. max_permeability = 100 * p.q_UF / (128*40) / min_tmp_during_filtration
  126. return {
  127. "k_bw_per_ceb": k_bw_per_ceb,
  128. "ton_water_energy_kWh_per_m3": ton_water_energy_kWh_per_m3,
  129. "recovery": recovery,
  130. "daily_prod_time_h": daily_prod_time_h,
  131. "max_permeability": max_permeability
  132. }
  133. # ==============================
  134. # 示例调用
  135. # ==============================
  136. if __name__ == "__main__":
  137. # -------------------------
  138. # 1. 初始化参数
  139. # -------------------------
  140. uf_params = UFParams()
  141. TMP0 = 0.01 # 原始跨膜压差
  142. # -------------------------
  143. # 2. 调用模型做一次决策(只输出 L_s)
  144. # -------------------------
  145. model_decide_result = run_uf_DQN_decide(uf_params, TMP0)
  146. model_L_s = model_decide_result["L_s"] # 只输出 L_s
  147. print(f"模型决策进水时长 L_s = {model_L_s}")
  148. # -------------------------
  149. # 3. 工厂当前值 + 模型上一轮值(示例值)
  150. # -------------------------
  151. current_L_s = 3800
  152. model_prev_L_s = 4040
  153. # -------------------------
  154. # 4. 生成 PLC 指令(新版仅 L_s)
  155. # -------------------------
  156. plc_L_s = generate_plc_instructions(current_L_s,model_prev_L_s,model_L_s)
  157. print(f"PLC 指令 L_s = {plc_L_s}")
  158. # -------------------------
  159. # 5. 反洗时长由工厂参数决定/固定值
  160. # (新模型不输出 t_bw_s)
  161. # -------------------------
  162. plc_t_bw_s = uf_params.fixed_t_bw_s
  163. # -------------------------
  164. # 6. 工厂 TMP 最大/最小(可为空 None)
  165. # -------------------------
  166. max_tmp_during_filtration = 0.050176
  167. min_tmp_during_filtration = 0.012496
  168. # -------------------------
  169. # 7. 计算周期指标(模型动作实际效果)
  170. # -------------------------
  171. execution_result = calc_uf_cycle_metrics(
  172. p=uf_params,
  173. TMP0=TMP0,
  174. max_tmp_during_filtration=max_tmp_during_filtration,
  175. min_tmp_during_filtration=min_tmp_during_filtration,
  176. L_s=plc_L_s,
  177. t_bw_s=plc_t_bw_s # 仍需要反洗时长参数
  178. )
  179. # -------------------------
  180. # 8. 打印结果
  181. # -------------------------
  182. print("\n===== 单步决策结果 =====")
  183. print(f"模型动作编号: {model_decide_result['action']}")
  184. print(f"模型选择的 L_s: {model_L_s} 秒")
  185. print(f"PLC 下发 L_s: {plc_L_s} 秒")
  186. print(f"PLC 下发反洗时长(固定) t_bw_s: {plc_t_bw_s} 秒")
  187. print(f"周期对应的反洗次数: {execution_result['k_bw_per_ceb']}")
  188. print(f"吨水电耗: {execution_result['ton_water_energy_kWh_per_m3']}")
  189. print(f"回收率: {execution_result['recovery']}")
  190. print(f"日均产水时间: {execution_result['daily_prod_time_h']}")
  191. print(f"最高渗透率: {execution_result['max_permeability']}")