SDHU_AB.py 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620
  1. from typing import Union
  2. import numpy as np
  3. import pandas as pd
  4. import pymc as pm
  5. import pytensor.tensor as pt
  6. from .._base._base_device import BaseDevice
  7. from ...components import (
  8. coil_water,coil_steam,wheel2,wheel3,mixed
  9. )
  10. from ..utils.fit_utils import (
  11. observe,reorder_posterior
  12. )
  13. from ...tools.optimizer import optimizer
  14. from ...tools.data_cleaner import DataCleaner
  15. class SDHU_AB(BaseDevice):
  16. val_rw_adj_target = ('coil_2_ToutA','coil_2_DoutA')
  17. def __init__(
  18. self,
  19. DHU_type = 'A',
  20. exist_Fa_H = True,
  21. exist_Fa_H0 = False,
  22. wheel_1 = None,
  23. coolingcoil_2 = 'CoolingCoil2',
  24. heatingcoil_1 = 'SteamCoil',
  25. mixed_1 = 'Mixed',
  26. mixed_2 = 'Mixed',
  27. other_info = None
  28. ) -> None:
  29. super().__init__()
  30. self.DHU_type = DHU_type.replace('SDHU_','')
  31. if self.DHU_type == 'A':
  32. wheel_1 = wheel_1 if wheel_1 is not None else 'WheelS3V3'
  33. elif self.DHU_type == 'B':
  34. wheel_1 = wheel_1 if wheel_1 is not None else 'WheelS2V2'
  35. else:
  36. raise Exception('SDHU_type must be A or B')
  37. self.components_str = {
  38. 'wheel_1' : wheel_1,
  39. 'coil_2' : coolingcoil_2,
  40. 'heatingcoil_1': heatingcoil_1,
  41. 'mixed_1' : mixed_1,
  42. 'mixed_2' : mixed_2
  43. }
  44. self.exist_Fa_H = exist_Fa_H
  45. self.exist_Fa_H0 = exist_Fa_H0
  46. self.other_info = other_info if other_info is not None else {}
  47. self.record_load_info(
  48. components_str = self.components_str,
  49. DHU_type = self.DHU_type,
  50. exist_Fa_H = self.exist_Fa_H,
  51. exist_Fa_H0 = self.exist_Fa_H0,
  52. other_info = self.other_info
  53. )
  54. @property
  55. def components(self):
  56. comp_map = {
  57. 'WheelS2':wheel2,'WheelS3':wheel3,'CoolingCoil':coil_water,
  58. 'SteamCoil':coil_steam,'Mixed':mixed
  59. }
  60. output ={}
  61. for comp_name,comp_model in self.components_str.items():
  62. if comp_model == 'SteamCoilVal':
  63. output[comp_name] = coil_steam.SteamCoilVal(
  64. name = comp_name,
  65. Fs_rated = self.other_info[f'{comp_name}_Fs_rated']
  66. )
  67. continue
  68. for comp_map_k,comp_map_v in comp_map.items():
  69. if comp_model.startswith(comp_map_k):
  70. output[comp_name] = getattr(comp_map_v,comp_model)(name = comp_name)
  71. return output
  72. @property
  73. def model_input_data_columns(self):
  74. columns = {
  75. 'fan_1_Hz' : 'fan_1_Hz',
  76. 'fan_2_Hz' : 'fan_2_Hz',
  77. 'coil_2_TinW' : 'coil_2_TinW',
  78. 'coil_2_Val' : 'coil_2_Val',
  79. 'wheel_1_TinR': 'wheel_1_TinR',
  80. }
  81. if self.exist_Fa_H:
  82. columns['mixed_1_TinM'] = 'mixed_1_TinM'
  83. columns['mixed_1_HinM'] = 'mixed_1_HinM'
  84. if self.exist_Fa_H0:
  85. columns['coil_1_ToutA'] = 'mixed_0_ToutA'
  86. columns['coil_1_HoutA'] = 'mixed_0_HoutA'
  87. else:
  88. columns['coil_1_ToutA'] = 'coil_1_ToutA'
  89. columns['coil_1_HoutA'] = 'coil_1_HoutA'
  90. if self.DHU_type == 'A':
  91. columns['Fa_TinA'] = 'Fa_TinA'
  92. columns['Fa_HinA'] = 'Fa_HinA'
  93. elif self.DHU_type == 'B':
  94. columns['mixed_2_TinM'] = 'mixed_2_TinM'
  95. columns['mixed_2_HinM'] = 'mixed_2_HinM'
  96. return columns
  97. @property
  98. def model_observe_data_columns(self):
  99. columns = {
  100. 'mixed_1_ToutA': 'mixed_1_ToutA',
  101. 'mixed_1_DoutA': 'mixed_1_DoutA',
  102. 'coil_2_ToutA' : 'coil_2_ToutA',
  103. 'coil_2_DoutA' : 'coil_2_DoutA',
  104. }
  105. if self.DHU_type == 'A':
  106. columns['wheel_1_ToutC'] = 'wheel_1_ToutC' # A类除湿机前转轮是三分转轮
  107. exclude_obs = self.other_info.get('exclude_obs',[])
  108. for col in exclude_obs:
  109. if col in columns:
  110. del columns[col]
  111. return columns
  112. def model(self,*args,**kwargs):
  113. if self.DHU_type == 'A':
  114. return model_A(*args,**kwargs)
  115. elif self.DHU_type == 'B':
  116. return model_B(*args,**kwargs)
  117. else:
  118. raise ValueError('DHU_type must be A or B')
  119. def fit(
  120. self,
  121. input_data : pd.DataFrame,
  122. observed_data: pd.DataFrame,
  123. plot_TVP : bool = True,
  124. ):
  125. if len(input_data) < 30:
  126. raise Exception('数据量过少')
  127. with pm.Model() as self.MODEL_PYMC:
  128. param_prior = {name:comp.prior() for name,comp in self.components.items()}
  129. if self.DHU_type == 'A':
  130. param_prior['F_air'] = AirFlow_SDHU_A.prior(exist_Fa_H = self.exist_Fa_H)
  131. elif self.DHU_type == 'B':
  132. param_prior['F_air'] = AirFlow_SDHU_B.prior(exist_Fa_H = self.exist_Fa_H)
  133. else:
  134. raise NotImplementedError
  135. res = self.model(
  136. **{k:input_data.loc[:,v].values for k,v in self.model_input_data_columns.items()},
  137. engine = 'pymc',
  138. components = self.components,
  139. param = param_prior
  140. )
  141. for std_name,name in self.model_observe_data_columns.items():
  142. if name not in observed_data.columns:
  143. raise Exception(f'Missing column: {name}')
  144. observed_data = observed_data.rename(columns={name:std_name})
  145. std_name_equp,std_name_point = std_name.rsplit('_',1)
  146. sigma = 1
  147. observe(
  148. name = std_name,
  149. var = res[std_name_equp][std_name_point],
  150. observed = observed_data,
  151. sigma = sigma
  152. )
  153. self.param_posterior = pm.find_MAP(maxeval=50000,include_transformed=False)
  154. self.record_load_info(param_posterior = self.param_posterior)
  155. self.record_model(
  156. model_name = 'ATD',
  157. model = reorder_posterior(param_prior,self.param_posterior),
  158. train_data = {
  159. 'wheel_1_TinR': observed_data.loc[:,'wheel_1_TinR'].values,
  160. 'fan_2_Hz' : observed_data.loc[:,'fan_2_Hz'].values,
  161. 'coil_2_DoutA': observed_data.loc[:,'coil_2_DoutA'].values,
  162. },
  163. train_metric = {'R2':1,'MAE':1,'MAPE':1}
  164. )
  165. self.TVP_data = self.get_TVP(self.param_posterior,observed_data)
  166. self.TVP_metric = self.get_metric(self.TVP_data)
  167. if plot_TVP:
  168. self.plot_TVP(self.TVP_data).show()
  169. return self
  170. @property
  171. def F_air_val_rw(self):
  172. return None
  173. def set_F_air_val_rw(self,value:float):
  174. return self
  175. def clean_data(
  176. self,
  177. data : pd.DataFrame,
  178. data_type : list=['input','observed'],
  179. print_process: bool = True,
  180. fill_zero : bool = False,
  181. save_log : Union[str,None] = None
  182. ) -> pd.DataFrame:
  183. data = data.replace(-9999,np.nan)
  184. clean_data = DataCleaner(data,print_process=print_process)
  185. filter_columns = []
  186. if 'input' in data_type:
  187. filter_columns += list(self.model_input_data_columns.values())
  188. clean_data = (
  189. clean_data
  190. .rm_rolling_fluct(window=60,fun='ptp',thre=0.1,include_cols=['State'])
  191. .rm_rule('State != 1')
  192. .rm_rule('fan_1_Hz < 10').rm_rule('fan_2_Hz < 10')
  193. .rm_outrange(method='raw',upper=140,lower=20,include_cols=['wheel_1_TinR'])
  194. .rm_outrange(method='raw',upper=15,lower=-60,include_cols=['coil_2_DoutA'])
  195. )
  196. if 'observed' in data_type:
  197. filter_columns += list(self.model_observe_data_columns.values())
  198. clean_data = clean_data.get_data(
  199. fill = 0 if fill_zero else None,
  200. save_log = save_log
  201. )
  202. clean_data = clean_data.loc[:,filter_columns]
  203. return clean_data
  204. def optimize(
  205. self,
  206. cur_input_data: pd.DataFrame,
  207. wheel_1_TinR : tuple = (70,120),
  208. fan_2_Hz : tuple = (30,50),
  209. constrains : list = None,
  210. logging : bool = True,
  211. target : str = 'summary_Fs',
  212. target_min : bool = True
  213. ) -> list:
  214. constrains = [] if constrains is None else constrains
  215. cur_input_data = cur_input_data.iloc[[0],:]
  216. opt_var_boundary = {}
  217. if wheel_1_TinR is not None:
  218. opt_var_boundary['wheel_1_TinR'] = {'lb':min(wheel_1_TinR),'ub':max(wheel_1_TinR)}
  219. if fan_2_Hz is not None:
  220. opt_var_boundary['fan_2_Hz'] = {'lb':min(fan_2_Hz),'ub':max(fan_2_Hz)}
  221. opt_var_value = cur_input_data.loc[:,list(opt_var_boundary.keys())]
  222. oth_var_value = (
  223. cur_input_data
  224. .loc[:,list(set(self.model_input_data_columns.values()))]
  225. .drop(opt_var_value.columns,axis=1)
  226. )
  227. opt_res = optimizer(
  228. model = self,
  229. opt_var_boundary = opt_var_boundary,
  230. opt_var_value = opt_var_value,
  231. oth_var_value = oth_var_value,
  232. target = target,
  233. target_min = target_min,
  234. constrains = constrains,
  235. logging = logging,
  236. other_kwargs = {'NIND':2000,'MAXGEN':50}
  237. )
  238. return opt_res
  239. def plot_opt(
  240. self,
  241. cur_input_data: pd.DataFrame,
  242. target_min : str = 'summary_waste',
  243. coil_2_DoutA : tuple = None
  244. ):
  245. if coil_2_DoutA is None:
  246. coil_2_DoutA = (
  247. self.model_info['model_train_info_ATD']['coil_2_DoutA_min'],
  248. self.model_info['model_train_info_ATD']['coil_2_DoutA_max']
  249. )
  250. data_input = (
  251. pd.MultiIndex.from_product(
  252. [
  253. np.linspace(
  254. self.model_info['model_train_info_ATD']['wheel_1_TinR_min']-5,
  255. self.model_info['model_train_info_ATD']['wheel_1_TinR_max']+5,
  256. 1000
  257. ),
  258. np.linspace(
  259. self.model_info['model_train_info_ATD']['fan_2_Hz_min']-5,
  260. self.model_info['model_train_info_ATD']['fan_2_Hz_max']+5,
  261. 1000
  262. ),
  263. ],
  264. names=['wheel_1_TinR','fan_2_Hz']
  265. )
  266. .to_frame(index=False)
  267. )
  268. for col in cur_input_data.columns:
  269. if col in data_input.columns:
  270. continue
  271. data_input[col] = cur_input_data.loc[:,col].iat[0]
  272. data_output = self.predict_system(data_input)
  273. data = (
  274. data_output
  275. .assign(
  276. wheel_1_TinR = data_input.loc[:,'wheel_1_TinR'],
  277. fan_2_Hz = data_input.loc[:,'fan_2_Hz'],
  278. )
  279. .assign(coil_2_DoutA=lambda dt:dt.coil_2_DoutA.round(1))
  280. .loc[lambda dt:dt.coil_2_DoutA.between(*(min(coil_2_DoutA),max(coil_2_DoutA)))]
  281. .loc[lambda dt:dt.groupby('coil_2_DoutA')[target_min].idxmin()]
  282. .loc[lambda dt:dt.coil_2_DoutA.mod(0.5)==0]
  283. )
  284. import plotnine as gg
  285. plot = (
  286. data
  287. .pipe(gg.ggplot)
  288. + gg.aes(x='wheel_1_TinR',y='fan_2_Hz')
  289. + gg.geom_path(size=1)
  290. + gg.geom_point()
  291. + gg.geom_label(gg.aes(label='coil_2_DoutA'))
  292. + gg.geom_abline(slope=1,intercept=0,color='red',linetype='--')
  293. )
  294. return plot
  295. def plot_check(self,cur_input_data:pd.DataFrame) -> dict:
  296. pa1=self.curve(input_data=cur_input_data,x='wheel_1_TinR',y='wheel_1_DoutP')
  297. pa2=self.curve(input_data=cur_input_data,x='wheel_1_TinR',y='wheel_1_ToutP')
  298. pa3=self.curve(input_data=cur_input_data,x='wheel_1_TinR',y='wheel_1_EFF')
  299. pb1=self.curve(input_data=cur_input_data,x='fan_2_Hz',y='wheel_1_DoutP')
  300. pb2=self.curve(input_data=cur_input_data,x='fan_2_Hz',y='wheel_1_ToutP')
  301. pb3=self.curve(input_data=cur_input_data,x='fan_2_Hz',y='wheel_1_EFF')
  302. plot1 = (pa1|pa2|pa3)/(pb1|pb2|pb3)
  303. return {'plot1':plot1}
  304. def model_A(
  305. Fa_TinA, # 前表冷后温度
  306. Fa_HinA, # 前表冷后湿度
  307. coil_1_ToutA,
  308. coil_1_HoutA,
  309. fan_1_Hz, # 处理侧风机频率
  310. fan_2_Hz, # 再生侧风机频率
  311. coil_2_TinW, # 中表冷进水温度
  312. coil_2_Val, # 中表冷阀门开度
  313. wheel_1_TinR, # 前转轮再生侧温度
  314. engine : str,
  315. components: dict,
  316. param : dict,
  317. mixed_1_TinM = 0, # 回风温度(处理侧)
  318. mixed_1_HinM = 0, # 回风湿度(处理侧)
  319. ) -> dict:
  320. # 水的质量流量
  321. coil_2_FW = coil_2_Val / 100
  322. # 空气的质量流量
  323. air_flow = AirFlow_SDHU_A.model(fan_1_Hz=fan_1_Hz,fan_2_Hz=fan_2_Hz,param=param)
  324. # 前转轮
  325. wheel_1_res = components['wheel_1'].model(
  326. TinP = coil_1_ToutA,
  327. HinP = coil_1_HoutA,
  328. FP = air_flow['wheel_1_FaP'],
  329. TinR = wheel_1_TinR,
  330. HinR = 0,
  331. FR = air_flow['wheel_1_FaR'],
  332. TinC = Fa_TinA,
  333. HinC = Fa_HinA,
  334. FC = air_flow['wheel_1_FaC'],
  335. engine = engine,
  336. param = param['wheel_1']
  337. )
  338. # 处理侧混风(回风)
  339. mixed_1_res = components['mixed_1'].model(
  340. TinA = wheel_1_res['ToutP'],
  341. HinA = wheel_1_res['HoutP'],
  342. FA = air_flow['mixed_1_FaA'],
  343. TinM = mixed_1_TinM,
  344. HinM = mixed_1_HinM,
  345. FM = air_flow['mixed_1_FaM'],
  346. engine = engine
  347. )
  348. # 中表冷
  349. coil_2_res = components['coil_2'].model(
  350. TinA = mixed_1_res['ToutA'],
  351. HinA = mixed_1_res['HoutA'],
  352. FA = air_flow['coil_2_FaA'],
  353. TinW = coil_2_TinW,
  354. FW = coil_2_FW,
  355. engine = engine,
  356. param = param['coil_2']
  357. )
  358. # 后转轮湿度修正
  359. wheel_1_res_adj = components['wheel_1'].model(
  360. TinP = coil_1_ToutA,
  361. HinP = coil_1_HoutA,
  362. FP = air_flow['wheel_1_FaP'],
  363. TinR = wheel_1_TinR,
  364. HinR = wheel_1_res['HoutC'],
  365. FR = air_flow['wheel_1_FaR'],
  366. TinC = Fa_TinA,
  367. HinC = Fa_HinA,
  368. FC = air_flow['wheel_1_FaC'],
  369. engine = engine,
  370. param = param['wheel_1']
  371. )
  372. # 前再生加热盘管
  373. heatingcoil_1_res = components['heatingcoil_1'].model(
  374. TinA = wheel_1_res_adj['ToutC'],
  375. ToutA = wheel_1_TinR,
  376. FA = air_flow['heatingcoil_1_Fa'],
  377. param = param['heatingcoil_1'],
  378. engine = engine
  379. )
  380. waste = cal_Q_waste(
  381. wheel_1_res = wheel_1_res_adj,
  382. heatingcoil_1_res = heatingcoil_1_res,
  383. wheel_1_TinR = wheel_1_TinR,
  384. fan_2_Hz = fan_2_Hz
  385. )
  386. return {
  387. 'coil_2' : coil_2_res,
  388. 'wheel_1' : wheel_1_res_adj,
  389. 'mixed_1' : mixed_1_res,
  390. 'heatingcoil_1': heatingcoil_1_res,
  391. 'Fa' : air_flow,
  392. 'summary' : {
  393. 'Fs' : heatingcoil_1_res['Fs'],
  394. **waste,
  395. }
  396. }
  397. def model_B(
  398. mixed_2_TinM, # 再生侧入口温度
  399. mixed_2_HinM, # 再生侧入口湿度
  400. coil_1_ToutA,
  401. coil_1_HoutA,
  402. fan_1_Hz, # 处理侧风机频率
  403. fan_2_Hz, # 再生侧风机频率
  404. coil_2_TinW, # 中表冷进水温度
  405. coil_2_Val, # 中表冷阀门开度
  406. wheel_1_TinR, # 前转轮再生侧温度
  407. engine : str,
  408. components: dict,
  409. param : dict,
  410. mixed_1_TinM = 0, # 回风温度(处理侧)
  411. mixed_1_HinM = 0, # 回风湿度(处理侧)
  412. ) -> dict:
  413. # 水的质量流量
  414. coil_2_FW = coil_2_Val / 100
  415. # 空气的质量流量
  416. air_flow = AirFlow_SDHU_B.model(fan_1_Hz=fan_1_Hz,fan_2_Hz=fan_2_Hz,param=param)
  417. # 前转轮
  418. wheel_1_res = components['wheel_1'].model(
  419. TinP = coil_1_ToutA,
  420. HinP = coil_1_HoutA,
  421. FP = air_flow['wheel_1_FaP'],
  422. TinR = wheel_1_TinR,
  423. HinR = mixed_2_HinM,
  424. FR = air_flow['wheel_1_FaR'],
  425. engine = engine,
  426. param = param['wheel_1']
  427. )
  428. # 处理侧混风(回风)
  429. mixed_1_res = components['mixed_1'].model(
  430. TinA = wheel_1_res['ToutP'],
  431. HinA = wheel_1_res['HoutP'],
  432. FA = air_flow['mixed_1_FaA'],
  433. TinM = mixed_1_TinM,
  434. HinM = mixed_1_HinM,
  435. FM = air_flow['mixed_1_FaM'],
  436. engine = engine
  437. )
  438. # 中表冷
  439. coil_2_res = components['coil_2'].model(
  440. TinA = mixed_1_res['ToutA'],
  441. HinA = mixed_1_res['HoutA'],
  442. FA = air_flow['coil_2_FaA'],
  443. TinW = coil_2_TinW,
  444. FW = coil_2_FW,
  445. engine = engine,
  446. param = param['coil_2']
  447. )
  448. # 前再生加热盘管
  449. heatingcoil_1_res = components['heatingcoil_1'].model(
  450. TinA = mixed_2_TinM,
  451. ToutA = wheel_1_TinR,
  452. FA = air_flow['heatingcoil_1_Fa'],
  453. param = param['heatingcoil_1'],
  454. engine = engine
  455. )
  456. waste = cal_Q_waste(
  457. wheel_1_res = wheel_1_res,
  458. heatingcoil_1_res = heatingcoil_1_res,
  459. wheel_1_TinR = wheel_1_TinR,
  460. fan_2_Hz = fan_2_Hz
  461. )
  462. return {
  463. 'coil_2' : coil_2_res,
  464. 'wheel_1' : wheel_1_res,
  465. 'mixed_1' : mixed_1_res,
  466. 'heatingcoil_1': heatingcoil_1_res,
  467. 'Fa' : air_flow,
  468. 'summary' : {
  469. 'Fs' : heatingcoil_1_res['Fs'],
  470. **waste,
  471. }
  472. }
  473. class AirFlow_SDHU_A:
  474. @classmethod
  475. def model(cls,fan_1_Hz,fan_2_Hz,param):
  476. F_air_X2_base = 1 # 进入转轮处理侧的新风量
  477. F_air_H_base = param['F_air'].get('H_base',0)
  478. F_air_P_base = param['F_air']['P_base']
  479. Fa_H = F_air_H_base + (fan_1_Hz/50) * param['F_air'].get('HzP_H',0)
  480. Fa_X2 = F_air_X2_base + (fan_1_Hz/50) * param['F_air']['HzP_X2']
  481. Fa_S = Fa_H + Fa_X2
  482. Fa_P = F_air_P_base + (fan_2_Hz/50) * param['F_air']['HzR_P']
  483. return {
  484. 'wheel_1_FaP' : Fa_X2,
  485. 'wheel_1_FaC' : Fa_P,
  486. 'wheel_1_FaR' : Fa_P,
  487. 'coil_2_FaA' : Fa_S,
  488. 'mixed_1_FaM' : Fa_H,
  489. 'mixed_1_FaA' : Fa_X2,
  490. 'heatingcoil_1_Fa': Fa_P
  491. }
  492. @classmethod
  493. def prior(cls,exist_Fa_H):
  494. param = {}
  495. param['HzP_X2'] = pm.HalfNormal('F_air_HzP_X2',sigma=1,initval=0.5)
  496. param['HzR_P'] = pm.HalfNormal('F_air_HzR_P',sigma=1,initval=0.5)
  497. param['P_base'] = pm.TruncatedNormal('F_air_P_base',mu=1,sigma=0.2,lower=0,initval=1)
  498. if exist_Fa_H:
  499. param['H_base'] = pm.TruncatedNormal('F_air_H_base',mu=1,sigma=0.2,lower=0,initval=1)
  500. param['HzP_H'] = pm.HalfNormal('F_air_HzP_H',sigma=1,initval=0.5)
  501. return param
  502. class AirFlow_SDHU_B:
  503. @classmethod
  504. def model(cls,fan_1_Hz,fan_2_Hz,param):
  505. F_air_X2_base = 1
  506. F_air_H_base = param['F_air'].get('H_base',0)
  507. F_air_P_base = param['F_air']['P_base']
  508. Fa_H = F_air_H_base + (fan_1_Hz/50) * param['F_air'].get('HzP_H',0)
  509. Fa_X2 = F_air_X2_base + (fan_1_Hz/50) * param['F_air']['HzP_X2']
  510. Fa_S = Fa_H + Fa_X2
  511. Fa_P = F_air_P_base + (fan_2_Hz/50) * param['F_air']['HzR_P']
  512. return {
  513. 'wheel_1_FaP' : Fa_X2,
  514. 'wheel_1_FaR' : Fa_P,
  515. 'coil_2_FaA' : Fa_S,
  516. 'mixed_1_FaM' : Fa_H,
  517. 'mixed_1_FaA' : Fa_X2,
  518. 'heatingcoil_1_Fa': Fa_P
  519. }
  520. @classmethod
  521. def prior(cls,exist_Fa_H):
  522. param = {}
  523. param['HzP_X2'] = pm.HalfNormal('F_air_HzP_X2',sigma=1,initval=0.5)
  524. param['HzR_P'] = pm.HalfNormal('F_air_HzR_P',sigma=1,initval=0.5)
  525. param['P_base'] = pm.TruncatedNormal('F_air_P_base',mu=1,sigma=0.2,lower=0,initval=1)
  526. if exist_Fa_H:
  527. param['H_base'] = pm.TruncatedNormal('F_air_H_base',mu=1,sigma=0.2,lower=0,initval=1)
  528. param['HzP_H'] = pm.HalfNormal('F_air_HzP_H',sigma=1,initval=0.5)
  529. return param
  530. def cal_Q_waste(
  531. wheel_1_res,
  532. heatingcoil_1_res,
  533. wheel_1_TinR,
  534. fan_2_Hz
  535. ) -> dict:
  536. def waste_cond_func1(TinR):
  537. waste = 0.15 + 0.0001 * (TinR-70)**3
  538. return np.where(waste>0,waste,0)
  539. def waste_cond_func2(TinR):
  540. waste = 0.25 * (1 - np.exp(-0.04 * (TinR - 70)))
  541. return np.where(waste>0,waste,0)
  542. if isinstance(wheel_1_res['Qsen'],np.ndarray):
  543. WHERE = np.where
  544. else:
  545. WHERE = pm.math.switch
  546. heatingcoil_1_Q = heatingcoil_1_res['Q']
  547. heatingcoil_1_Q = WHERE(heatingcoil_1_Q>0,heatingcoil_1_Q,0)
  548. waste_Qsen1 = wheel_1_res['Qsen']
  549. waste_cond1 = heatingcoil_1_Q * waste_cond_func1(wheel_1_TinR)
  550. res = {
  551. 'waste_Qsen1': waste_Qsen1,
  552. 'waste_cond1': waste_cond1,
  553. }
  554. waste_out = heatingcoil_1_Q - wheel_1_res['Qsen'] - wheel_1_res['Qlat']
  555. waste_out = WHERE(waste_out>0,waste_out,0)
  556. waste = waste_Qsen1 + waste_cond1 + waste_out + fan_2_Hz/100
  557. res['waste_out'] = waste_out
  558. res['waste'] = waste
  559. return res