open-fdd 0.1.8__py3-none-any.whl → 0.1.9__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- open_fdd/air_handling_unit/faults/__init__.py +30 -1487
- open_fdd/air_handling_unit/faults/fault_condition_eight.py +135 -0
- open_fdd/air_handling_unit/faults/fault_condition_eleven.py +108 -0
- open_fdd/air_handling_unit/faults/fault_condition_fifteen.py +189 -0
- open_fdd/air_handling_unit/faults/fault_condition_five.py +126 -0
- open_fdd/air_handling_unit/faults/fault_condition_four.py +128 -0
- open_fdd/air_handling_unit/faults/fault_condition_fourteen.py +177 -0
- open_fdd/air_handling_unit/faults/fault_condition_nine.py +140 -0
- open_fdd/air_handling_unit/faults/fault_condition_one.py +113 -0
- open_fdd/air_handling_unit/faults/fault_condition_seven.py +106 -0
- open_fdd/air_handling_unit/faults/fault_condition_six.py +228 -0
- open_fdd/air_handling_unit/faults/fault_condition_sixteen.py +196 -0
- open_fdd/air_handling_unit/faults/fault_condition_ten.py +119 -0
- open_fdd/air_handling_unit/faults/fault_condition_thirteen.py +139 -0
- open_fdd/air_handling_unit/faults/fault_condition_three.py +112 -0
- open_fdd/air_handling_unit/faults/fault_condition_twelve.py +164 -0
- open_fdd/air_handling_unit/faults/fault_condition_two.py +112 -0
- open_fdd/air_handling_unit/faults/helper_utils.py +29 -19
- open_fdd/air_handling_unit/reports/__init__.py +6 -4
- open_fdd/air_handling_unit/reports/fault_report.py +3 -2
- open_fdd/chiller_plant/faults/__init__.py +6 -2279
- open_fdd/chiller_plant/faults/fault_condition_one.py +113 -0
- open_fdd/chiller_plant/faults/fault_condition_two.py +100 -0
- open_fdd/tests/ahu/test_ahu_fc1.py +2 -2
- open_fdd/tests/ahu/test_ahu_fc10.py +1 -0
- open_fdd/tests/ahu/test_ahu_fc11.py +3 -4
- open_fdd/tests/ahu/test_ahu_fc12.py +3 -4
- open_fdd/tests/ahu/test_ahu_fc13.py +3 -4
- open_fdd/tests/ahu/test_ahu_fc14.py +3 -4
- open_fdd/tests/ahu/test_ahu_fc15.py +3 -4
- open_fdd/tests/ahu/test_ahu_fc16.py +4 -3
- open_fdd/tests/ahu/test_ahu_fc2.py +1 -0
- open_fdd/tests/ahu/test_ahu_fc3.py +1 -0
- open_fdd/tests/ahu/test_ahu_fc4.py +3 -1
- open_fdd/tests/ahu/test_ahu_fc5.py +1 -0
- open_fdd/tests/ahu/test_ahu_fc6.py +1 -0
- open_fdd/tests/ahu/test_ahu_fc7.py +1 -0
- open_fdd/tests/ahu/test_ahu_fc8.py +1 -0
- open_fdd/tests/ahu/test_ahu_fc9.py +1 -0
- open_fdd/tests/chiller/test_chiller_fc1.py +2 -2
- open_fdd/tests/chiller/test_chiller_fc2.py +2 -2
- {open_fdd-0.1.8.dist-info → open_fdd-0.1.9.dist-info}/METADATA +4 -3
- open_fdd-0.1.9.dist-info/RECORD +52 -0
- {open_fdd-0.1.8.dist-info → open_fdd-0.1.9.dist-info}/WHEEL +1 -1
- open_fdd/air_handling_unit/faults/fault_condition.py +0 -69
- open_fdd/air_handling_unit/faults/shared_utils.py +0 -90
- open_fdd-0.1.8.dist-info/RECORD +0 -36
- {open_fdd-0.1.8.dist-info → open_fdd-0.1.9.dist-info/licenses}/LICENSE +0 -0
- {open_fdd-0.1.8.dist-info → open_fdd-0.1.9.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,228 @@
|
|
1
|
+
import sys
|
2
|
+
|
3
|
+
import pandas as pd
|
4
|
+
|
5
|
+
from open_fdd.core.base_fault import BaseFaultCondition
|
6
|
+
from open_fdd.core.components import FaultInputColumn, InstanceAttribute
|
7
|
+
from open_fdd.core.exceptions import InvalidParameterError
|
8
|
+
from open_fdd.core.mixins import FaultConditionMixin
|
9
|
+
|
10
|
+
INPUT_COLS = [
|
11
|
+
FaultInputColumn(
|
12
|
+
name="supply_fan_air_volume_col",
|
13
|
+
constant_form="SUPPLY_FAN_AIR_VOLUME_COL",
|
14
|
+
description="Supply fan air volume",
|
15
|
+
unit="CFM",
|
16
|
+
required=True,
|
17
|
+
type=float,
|
18
|
+
),
|
19
|
+
FaultInputColumn(
|
20
|
+
name="mat_col",
|
21
|
+
constant_form="MAT_COL",
|
22
|
+
description="Mixed air temperature",
|
23
|
+
unit="°F",
|
24
|
+
required=True,
|
25
|
+
type=float,
|
26
|
+
),
|
27
|
+
FaultInputColumn(
|
28
|
+
name="oat_col",
|
29
|
+
constant_form="OAT_COL",
|
30
|
+
description="Outside air temperature",
|
31
|
+
unit="°F",
|
32
|
+
required=True,
|
33
|
+
type=float,
|
34
|
+
),
|
35
|
+
FaultInputColumn(
|
36
|
+
name="rat_col",
|
37
|
+
constant_form="RAT_COL",
|
38
|
+
description="Return air temperature",
|
39
|
+
unit="°F",
|
40
|
+
required=True,
|
41
|
+
type=float,
|
42
|
+
),
|
43
|
+
FaultInputColumn(
|
44
|
+
name="supply_vfd_speed_col",
|
45
|
+
constant_form="SUPPLY_VFD_SPEED_COL",
|
46
|
+
description="Supply fan VFD speed",
|
47
|
+
unit="%",
|
48
|
+
required=True,
|
49
|
+
type=float,
|
50
|
+
),
|
51
|
+
FaultInputColumn(
|
52
|
+
name="economizer_sig_col",
|
53
|
+
constant_form="ECONOMIZER_SIG_COL",
|
54
|
+
description="Economizer signal",
|
55
|
+
unit="%",
|
56
|
+
required=True,
|
57
|
+
type=float,
|
58
|
+
),
|
59
|
+
FaultInputColumn(
|
60
|
+
name="heating_sig_col",
|
61
|
+
constant_form="HEATING_SIG_COL",
|
62
|
+
description="Heating signal",
|
63
|
+
unit="%",
|
64
|
+
required=True,
|
65
|
+
type=float,
|
66
|
+
),
|
67
|
+
FaultInputColumn(
|
68
|
+
name="cooling_sig_col",
|
69
|
+
constant_form="COOLING_SIG_COL",
|
70
|
+
description="Cooling signal",
|
71
|
+
unit="%",
|
72
|
+
required=True,
|
73
|
+
type=float,
|
74
|
+
),
|
75
|
+
]
|
76
|
+
|
77
|
+
FAULT_PARAMS = [
|
78
|
+
InstanceAttribute(
|
79
|
+
name="airflow_err_thres",
|
80
|
+
constant_form="AIRFLOW_ERR_THRES",
|
81
|
+
description="Airflow error threshold",
|
82
|
+
unit="fraction",
|
83
|
+
type=float,
|
84
|
+
range=(0.0, 1.0),
|
85
|
+
),
|
86
|
+
InstanceAttribute(
|
87
|
+
name="ahu_min_oa_cfm_design",
|
88
|
+
constant_form="AHU_MIN_OA_CFM_DESIGN",
|
89
|
+
description="AHU minimum outdoor air CFM design",
|
90
|
+
unit="CFM",
|
91
|
+
type=float,
|
92
|
+
range=(0.0, 100000.0),
|
93
|
+
),
|
94
|
+
InstanceAttribute(
|
95
|
+
name="outdoor_degf_err_thres",
|
96
|
+
constant_form="OUTDOOR_DEGF_ERR_THRES",
|
97
|
+
description="Outdoor air temperature error threshold",
|
98
|
+
unit="°F",
|
99
|
+
type=float,
|
100
|
+
range=(0.0, 10.0),
|
101
|
+
),
|
102
|
+
InstanceAttribute(
|
103
|
+
name="return_degf_err_thres",
|
104
|
+
constant_form="RETURN_DEGF_ERR_THRES",
|
105
|
+
description="Return air temperature error threshold",
|
106
|
+
unit="°F",
|
107
|
+
type=float,
|
108
|
+
range=(0.0, 10.0),
|
109
|
+
),
|
110
|
+
InstanceAttribute(
|
111
|
+
name="oat_rat_delta_min",
|
112
|
+
constant_form="OAT_RAT_DELTA_MIN",
|
113
|
+
description="Minimum delta between outdoor and return air temperature",
|
114
|
+
unit="°F",
|
115
|
+
type=float,
|
116
|
+
range=(0.0, 20.0),
|
117
|
+
),
|
118
|
+
InstanceAttribute(
|
119
|
+
name="ahu_min_oa_dpr",
|
120
|
+
constant_form="AHU_MIN_OA_DPR",
|
121
|
+
description="Minimum outdoor air damper position",
|
122
|
+
unit="fraction",
|
123
|
+
type=float,
|
124
|
+
range=(0.0, 1.0),
|
125
|
+
),
|
126
|
+
]
|
127
|
+
|
128
|
+
|
129
|
+
class FaultConditionSix(BaseFaultCondition, FaultConditionMixin):
|
130
|
+
"""Class provides the definitions for Fault Condition 6.
|
131
|
+
|
132
|
+
This fault related to knowing the design air flow for
|
133
|
+
ventilation AHU_MIN_CFM_DESIGN which comes from the
|
134
|
+
design mech engineered records where then the fault
|
135
|
+
tries to calculate that based on totalized measured
|
136
|
+
AHU air flow and outside air fraction calc from
|
137
|
+
AHU temp sensors. The fault could flag issues where
|
138
|
+
flow stations are either not in calibration, temp
|
139
|
+
sensors used in the OA frac calc, or possibly the AHU
|
140
|
+
not bringing in design air flow when not operating in
|
141
|
+
economizer free cooling modes.
|
142
|
+
|
143
|
+
py -3.12 -m pytest open_fdd/tests/ahu/test_ahu_fc6.py -rP -s
|
144
|
+
"""
|
145
|
+
|
146
|
+
input_columns = INPUT_COLS
|
147
|
+
fault_params = FAULT_PARAMS
|
148
|
+
equation_string = (
|
149
|
+
"fc6_flag = 1 if |OA_frac_calc - OA_min| > airflow_err_thres "
|
150
|
+
"in non-economizer modes, considering htg and mech clg OS \n"
|
151
|
+
)
|
152
|
+
description_string = (
|
153
|
+
"Fault Condition 6: Issues detected with OA fraction calculation or AHU "
|
154
|
+
"not maintaining design air flow in non-economizer conditions \n"
|
155
|
+
)
|
156
|
+
error_string = "One or more required columns are missing or None \n"
|
157
|
+
|
158
|
+
@FaultConditionMixin._handle_errors
|
159
|
+
def apply(self, df: pd.DataFrame) -> pd.DataFrame:
|
160
|
+
"""Apply the fault condition to the DataFrame."""
|
161
|
+
# Apply common checks
|
162
|
+
self._apply_common_checks(df)
|
163
|
+
|
164
|
+
# Get column values using accessor methods
|
165
|
+
rat_col = self.get_input_column("rat_col")
|
166
|
+
oat_col = self.get_input_column("oat_col")
|
167
|
+
mat_col = self.get_input_column("mat_col")
|
168
|
+
supply_fan_air_volume_col = self.get_input_column("supply_fan_air_volume_col")
|
169
|
+
supply_vfd_speed_col = self.get_input_column("supply_vfd_speed_col")
|
170
|
+
economizer_sig_col = self.get_input_column("economizer_sig_col")
|
171
|
+
heating_sig_col = self.get_input_column("heating_sig_col")
|
172
|
+
cooling_sig_col = self.get_input_column("cooling_sig_col")
|
173
|
+
|
174
|
+
# Get parameter values using accessor methods
|
175
|
+
airflow_err_thres = self.get_param("airflow_err_thres")
|
176
|
+
ahu_min_oa_cfm_design = self.get_param("ahu_min_oa_cfm_design")
|
177
|
+
oat_rat_delta_min = self.get_param("oat_rat_delta_min")
|
178
|
+
ahu_min_oa_dpr = self.get_param("ahu_min_oa_dpr")
|
179
|
+
|
180
|
+
# Check for zeros in the columns that could lead to division by zero errors
|
181
|
+
cols_to_check = [rat_col, oat_col, supply_fan_air_volume_col]
|
182
|
+
if df[cols_to_check].eq(0).any().any():
|
183
|
+
print(f"Warning: Zero values found in columns: {cols_to_check}")
|
184
|
+
print("This may cause division by zero errors.")
|
185
|
+
sys.stdout.flush()
|
186
|
+
|
187
|
+
# Check analog outputs [data with units of %] are floats only
|
188
|
+
columns_to_check = [
|
189
|
+
supply_vfd_speed_col,
|
190
|
+
economizer_sig_col,
|
191
|
+
heating_sig_col,
|
192
|
+
cooling_sig_col,
|
193
|
+
]
|
194
|
+
self._apply_analog_checks(df, columns_to_check, check_greater_than_one=True)
|
195
|
+
|
196
|
+
# Calculate intermediate values
|
197
|
+
rat_minus_oat = abs(df[rat_col] - df[oat_col])
|
198
|
+
percent_oa_calc = (df[mat_col] - df[rat_col]) / (df[oat_col] - df[rat_col])
|
199
|
+
|
200
|
+
# Replace negative values in percent_oa_calc with zero using vectorized operation
|
201
|
+
percent_oa_calc = percent_oa_calc.clip(lower=0)
|
202
|
+
|
203
|
+
perc_OAmin = ahu_min_oa_cfm_design / df[supply_fan_air_volume_col]
|
204
|
+
percent_oa_calc_minus_perc_OAmin = abs(percent_oa_calc - perc_OAmin)
|
205
|
+
|
206
|
+
# Combined checks for OS 1 and OS 4 modes
|
207
|
+
os1_htg_mode_check = (
|
208
|
+
(rat_minus_oat >= oat_rat_delta_min)
|
209
|
+
& (percent_oa_calc_minus_perc_OAmin > airflow_err_thres)
|
210
|
+
& (df[heating_sig_col] > 0.0)
|
211
|
+
& (df[supply_vfd_speed_col] > 0.0)
|
212
|
+
)
|
213
|
+
|
214
|
+
os4_clg_mode_check = (
|
215
|
+
(rat_minus_oat >= oat_rat_delta_min)
|
216
|
+
& (percent_oa_calc_minus_perc_OAmin > airflow_err_thres)
|
217
|
+
& (df[heating_sig_col] == 0.0)
|
218
|
+
& (df[cooling_sig_col] > 0.0)
|
219
|
+
& (df[supply_vfd_speed_col] > 0.0)
|
220
|
+
& (df[economizer_sig_col] == ahu_min_oa_dpr)
|
221
|
+
)
|
222
|
+
|
223
|
+
combined_check = os1_htg_mode_check | os4_clg_mode_check
|
224
|
+
|
225
|
+
# Set fault flag
|
226
|
+
self._set_fault_flag(df, combined_check, "fc6_flag")
|
227
|
+
|
228
|
+
return df
|
@@ -0,0 +1,196 @@
|
|
1
|
+
import numpy as np
|
2
|
+
import pandas as pd
|
3
|
+
|
4
|
+
from open_fdd.core.base_fault import BaseFaultCondition
|
5
|
+
from open_fdd.core.components import FaultInputColumn, InstanceAttribute
|
6
|
+
from open_fdd.core.exceptions import InvalidParameterError
|
7
|
+
from open_fdd.core.mixins import FaultConditionMixin
|
8
|
+
|
9
|
+
INPUT_COLS = [
|
10
|
+
FaultInputColumn(
|
11
|
+
name="erv_oat_enter_col",
|
12
|
+
constant_form="ERV_OAT_ENTER_COL",
|
13
|
+
description="ERV outdoor air entering temperature",
|
14
|
+
unit="°F",
|
15
|
+
required=True,
|
16
|
+
type=float,
|
17
|
+
),
|
18
|
+
FaultInputColumn(
|
19
|
+
name="erv_oat_leaving_col",
|
20
|
+
constant_form="ERV_OAT_LEAVING_COL",
|
21
|
+
description="ERV outdoor air leaving temperature",
|
22
|
+
unit="°F",
|
23
|
+
required=True,
|
24
|
+
type=float,
|
25
|
+
),
|
26
|
+
FaultInputColumn(
|
27
|
+
name="erv_eat_enter_col",
|
28
|
+
constant_form="ERV_EAT_ENTER_COL",
|
29
|
+
description="ERV exhaust air entering temperature",
|
30
|
+
unit="°F",
|
31
|
+
required=True,
|
32
|
+
type=float,
|
33
|
+
),
|
34
|
+
FaultInputColumn(
|
35
|
+
name="erv_eat_leaving_col",
|
36
|
+
constant_form="ERV_EAT_LEAVING_COL",
|
37
|
+
description="ERV exhaust air leaving temperature",
|
38
|
+
unit="°F",
|
39
|
+
required=True,
|
40
|
+
type=float,
|
41
|
+
),
|
42
|
+
FaultInputColumn(
|
43
|
+
name="supply_vfd_speed_col",
|
44
|
+
constant_form="SUPPLY_VFD_SPEED_COL",
|
45
|
+
description="Supply fan VFD speed",
|
46
|
+
unit="%",
|
47
|
+
required=True,
|
48
|
+
type=float,
|
49
|
+
),
|
50
|
+
]
|
51
|
+
|
52
|
+
FAULT_PARAMS = [
|
53
|
+
InstanceAttribute(
|
54
|
+
name="erv_efficiency_min_heating",
|
55
|
+
constant_form="ERV_EFFICIENCY_MIN_HEATING",
|
56
|
+
description="Minimum expected ERV efficiency in heating mode",
|
57
|
+
unit="fraction",
|
58
|
+
type=float,
|
59
|
+
range=(0.0, 1.0),
|
60
|
+
),
|
61
|
+
InstanceAttribute(
|
62
|
+
name="erv_efficiency_max_heating",
|
63
|
+
constant_form="ERV_EFFICIENCY_MAX_HEATING",
|
64
|
+
description="Maximum expected ERV efficiency in heating mode",
|
65
|
+
unit="fraction",
|
66
|
+
type=float,
|
67
|
+
range=(0.0, 1.0),
|
68
|
+
),
|
69
|
+
InstanceAttribute(
|
70
|
+
name="erv_efficiency_min_cooling",
|
71
|
+
constant_form="ERV_EFFICIENCY_MIN_COOLING",
|
72
|
+
description="Minimum expected ERV efficiency in cooling mode",
|
73
|
+
unit="fraction",
|
74
|
+
type=float,
|
75
|
+
range=(0.0, 1.0),
|
76
|
+
),
|
77
|
+
InstanceAttribute(
|
78
|
+
name="erv_efficiency_max_cooling",
|
79
|
+
constant_form="ERV_EFFICIENCY_MAX_COOLING",
|
80
|
+
description="Maximum expected ERV efficiency in cooling mode",
|
81
|
+
unit="fraction",
|
82
|
+
type=float,
|
83
|
+
range=(0.0, 1.0),
|
84
|
+
),
|
85
|
+
InstanceAttribute(
|
86
|
+
name="oat_low_threshold",
|
87
|
+
constant_form="OAT_LOW_THRESHOLD",
|
88
|
+
description="OAT threshold for heating mode",
|
89
|
+
unit="°F",
|
90
|
+
type=float,
|
91
|
+
),
|
92
|
+
InstanceAttribute(
|
93
|
+
name="oat_high_threshold",
|
94
|
+
constant_form="OAT_HIGH_THRESHOLD",
|
95
|
+
description="OAT threshold for cooling mode",
|
96
|
+
unit="°F",
|
97
|
+
type=float,
|
98
|
+
),
|
99
|
+
InstanceAttribute(
|
100
|
+
name="oat_rat_delta_min",
|
101
|
+
constant_form="OAT_RAT_DELTA_MIN",
|
102
|
+
description="Minimum required delta between OAT and RAT",
|
103
|
+
unit="°F",
|
104
|
+
type=float,
|
105
|
+
),
|
106
|
+
]
|
107
|
+
|
108
|
+
|
109
|
+
class FaultConditionSixteen(BaseFaultCondition, FaultConditionMixin):
|
110
|
+
"""Class provides the definitions for Fault Condition 16.
|
111
|
+
ERV effectiveness should be within specified thresholds based on OAT.
|
112
|
+
This fault checks if the ERV (Energy Recovery Ventilator) is operating
|
113
|
+
within expected efficiency ranges in both heating and cooling modes.
|
114
|
+
|
115
|
+
py -3.12 -m pytest open_fdd/tests/ahu/test_ahu_fc16.py -rP -s
|
116
|
+
"""
|
117
|
+
|
118
|
+
input_columns = INPUT_COLS
|
119
|
+
fault_params = FAULT_PARAMS
|
120
|
+
equation_string = (
|
121
|
+
"fc16_flag = 1 if ERV effectiveness is outside expected range "
|
122
|
+
"(heating: εmin_htg ≤ ε ≤ εmax_htg, cooling: εmin_clg ≤ ε ≤ εmax_clg) "
|
123
|
+
"for N consecutive values else 0 \n"
|
124
|
+
)
|
125
|
+
description_string = (
|
126
|
+
"Fault Condition 16: ERV effectiveness should be within specified "
|
127
|
+
"thresholds based on OAT \n"
|
128
|
+
)
|
129
|
+
error_string = "One or more required columns are missing or None \n"
|
130
|
+
|
131
|
+
@FaultConditionMixin._handle_errors
|
132
|
+
def apply(self, df: pd.DataFrame) -> pd.DataFrame:
|
133
|
+
"""Apply the fault condition to the DataFrame."""
|
134
|
+
# Apply common checks
|
135
|
+
self._apply_common_checks(df)
|
136
|
+
|
137
|
+
# Get column values using accessor methods
|
138
|
+
supply_vfd_speed_col = self.get_input_column("supply_vfd_speed_col")
|
139
|
+
erv_oat_enter_col = self.get_input_column("erv_oat_enter_col")
|
140
|
+
erv_oat_leaving_col = self.get_input_column("erv_oat_leaving_col")
|
141
|
+
erv_eat_enter_col = self.get_input_column("erv_eat_enter_col")
|
142
|
+
|
143
|
+
# Get parameter values using accessor methods
|
144
|
+
erv_efficiency_min_heating = self.get_param("erv_efficiency_min_heating")
|
145
|
+
erv_efficiency_max_heating = self.get_param("erv_efficiency_max_heating")
|
146
|
+
erv_efficiency_min_cooling = self.get_param("erv_efficiency_min_cooling")
|
147
|
+
erv_efficiency_max_cooling = self.get_param("erv_efficiency_max_cooling")
|
148
|
+
oat_low_threshold = self.get_param("oat_low_threshold")
|
149
|
+
oat_high_threshold = self.get_param("oat_high_threshold")
|
150
|
+
oat_rat_delta_min = self.get_param("oat_rat_delta_min")
|
151
|
+
|
152
|
+
# Check analog outputs [data with units of %] are floats only
|
153
|
+
columns_to_check = [supply_vfd_speed_col]
|
154
|
+
self._apply_analog_checks(df, columns_to_check, check_greater_than_one=True)
|
155
|
+
|
156
|
+
# Calculate temperature differences
|
157
|
+
oat_rat_delta = abs(df[erv_oat_enter_col] - df[erv_eat_enter_col])
|
158
|
+
|
159
|
+
# Calculate ERV effectiveness
|
160
|
+
# ε = (T_leaving - T_entering) / (T_exhaust - T_entering)
|
161
|
+
erv_effectiveness = (df[erv_oat_leaving_col] - df[erv_oat_enter_col]) / (
|
162
|
+
df[erv_eat_enter_col] - df[erv_oat_enter_col]
|
163
|
+
)
|
164
|
+
|
165
|
+
# Determine operating mode based on OAT
|
166
|
+
heating_mode = df[erv_oat_enter_col] < oat_low_threshold
|
167
|
+
cooling_mode = df[erv_oat_enter_col] > oat_high_threshold
|
168
|
+
|
169
|
+
# Check effectiveness against thresholds
|
170
|
+
low_effectiveness_htg = heating_mode & (
|
171
|
+
erv_effectiveness < erv_efficiency_min_heating
|
172
|
+
)
|
173
|
+
high_effectiveness_htg = heating_mode & (
|
174
|
+
erv_effectiveness > erv_efficiency_max_heating
|
175
|
+
)
|
176
|
+
low_effectiveness_clg = cooling_mode & (
|
177
|
+
erv_effectiveness < erv_efficiency_min_cooling
|
178
|
+
)
|
179
|
+
high_effectiveness_clg = cooling_mode & (
|
180
|
+
erv_effectiveness > erv_efficiency_max_cooling
|
181
|
+
)
|
182
|
+
|
183
|
+
# Combine conditions:
|
184
|
+
# Fault occurs when ERV effectiveness is outside expected range
|
185
|
+
# and there's sufficient temperature difference between OAT and RAT
|
186
|
+
combined_check = (oat_rat_delta >= oat_rat_delta_min) & (
|
187
|
+
low_effectiveness_htg
|
188
|
+
| high_effectiveness_htg
|
189
|
+
| low_effectiveness_clg
|
190
|
+
| high_effectiveness_clg
|
191
|
+
)
|
192
|
+
|
193
|
+
# Set fault flag
|
194
|
+
self._set_fault_flag(df, combined_check, "fc16_flag")
|
195
|
+
|
196
|
+
return df
|
@@ -0,0 +1,119 @@
|
|
1
|
+
import numpy as np
|
2
|
+
import pandas as pd
|
3
|
+
|
4
|
+
from open_fdd.core.base_fault import BaseFaultCondition
|
5
|
+
from open_fdd.core.components import FaultInputColumn, InstanceAttribute
|
6
|
+
from open_fdd.core.exceptions import InvalidParameterError
|
7
|
+
from open_fdd.core.mixins import FaultConditionMixin
|
8
|
+
|
9
|
+
INPUT_COLS = [
|
10
|
+
FaultInputColumn(
|
11
|
+
name="oat_col",
|
12
|
+
constant_form="OAT_COL",
|
13
|
+
description="Outside air temperature",
|
14
|
+
unit="°F",
|
15
|
+
required=True,
|
16
|
+
type=float,
|
17
|
+
),
|
18
|
+
FaultInputColumn(
|
19
|
+
name="mat_col",
|
20
|
+
constant_form="MAT_COL",
|
21
|
+
description="Mixed air temperature",
|
22
|
+
unit="°F",
|
23
|
+
required=True,
|
24
|
+
type=float,
|
25
|
+
),
|
26
|
+
FaultInputColumn(
|
27
|
+
name="cooling_sig_col",
|
28
|
+
constant_form="COOLING_SIG_COL",
|
29
|
+
description="Cooling signal",
|
30
|
+
unit="%",
|
31
|
+
required=True,
|
32
|
+
type=float,
|
33
|
+
),
|
34
|
+
FaultInputColumn(
|
35
|
+
name="economizer_sig_col",
|
36
|
+
constant_form="ECONOMIZER_SIG_COL",
|
37
|
+
description="Economizer signal",
|
38
|
+
unit="%",
|
39
|
+
required=True,
|
40
|
+
type=float,
|
41
|
+
),
|
42
|
+
]
|
43
|
+
|
44
|
+
FAULT_PARAMS = [
|
45
|
+
InstanceAttribute(
|
46
|
+
name="outdoor_degf_err_thres",
|
47
|
+
constant_form="OUTDOOR_DEGF_ERR_THRES",
|
48
|
+
description="Outdoor air temperature error threshold",
|
49
|
+
unit="°F",
|
50
|
+
type=float,
|
51
|
+
),
|
52
|
+
InstanceAttribute(
|
53
|
+
name="mix_degf_err_thres",
|
54
|
+
constant_form="MIX_DEGF_ERR_THRES",
|
55
|
+
description="Mixed air temperature error threshold",
|
56
|
+
unit="°F",
|
57
|
+
type=float,
|
58
|
+
),
|
59
|
+
]
|
60
|
+
|
61
|
+
|
62
|
+
class FaultConditionTen(BaseFaultCondition, FaultConditionMixin):
|
63
|
+
"""Class provides the definitions for Fault Condition 10.
|
64
|
+
Outdoor air temperature and mix air temperature should
|
65
|
+
be approx equal in economizer plus mech cooling mode.
|
66
|
+
|
67
|
+
py -3.12 -m pytest open_fdd/tests/ahu/test_ahu_fc10.py -rP -s
|
68
|
+
"""
|
69
|
+
|
70
|
+
input_columns = INPUT_COLS
|
71
|
+
fault_params = FAULT_PARAMS
|
72
|
+
equation_string = (
|
73
|
+
"fc10_flag = 1 if |OAT - MAT| > √(εOAT² + εMAT²) in "
|
74
|
+
"economizer + mech cooling mode for N consecutive values else 0 \n"
|
75
|
+
)
|
76
|
+
description_string = (
|
77
|
+
"Fault Condition 10: Outdoor air temperature and mixed air temperature "
|
78
|
+
"should be approximately equal in economizer plus mechanical cooling mode \n"
|
79
|
+
)
|
80
|
+
error_string = "One or more required columns are missing or None \n"
|
81
|
+
|
82
|
+
@FaultConditionMixin._handle_errors
|
83
|
+
def apply(self, df: pd.DataFrame) -> pd.DataFrame:
|
84
|
+
"""Apply the fault condition to the DataFrame."""
|
85
|
+
# Apply common checks
|
86
|
+
self._apply_common_checks(df)
|
87
|
+
|
88
|
+
# Get column values using accessor methods
|
89
|
+
oat_col = self.get_input_column("oat_col")
|
90
|
+
mat_col = self.get_input_column("mat_col")
|
91
|
+
cooling_sig_col = self.get_input_column("cooling_sig_col")
|
92
|
+
economizer_sig_col = self.get_input_column("economizer_sig_col")
|
93
|
+
|
94
|
+
# Get parameter values using accessor methods
|
95
|
+
outdoor_degf_err_thres = self.get_param("outdoor_degf_err_thres")
|
96
|
+
mix_degf_err_thres = self.get_param("mix_degf_err_thres")
|
97
|
+
|
98
|
+
# Check analog outputs [data with units of %] are floats only
|
99
|
+
columns_to_check = [
|
100
|
+
economizer_sig_col,
|
101
|
+
cooling_sig_col,
|
102
|
+
]
|
103
|
+
self._apply_analog_checks(df, columns_to_check, check_greater_than_one=True)
|
104
|
+
|
105
|
+
# Perform calculations
|
106
|
+
abs_mat_minus_oat = abs(df[mat_col] - df[oat_col])
|
107
|
+
mat_oat_sqrted = np.sqrt(mix_degf_err_thres**2 + outdoor_degf_err_thres**2)
|
108
|
+
|
109
|
+
combined_check = (
|
110
|
+
(abs_mat_minus_oat > mat_oat_sqrted)
|
111
|
+
# Verify AHU is running in OS 3 cooling mode with minimum OA
|
112
|
+
& (df[cooling_sig_col] > 0.01)
|
113
|
+
& (df[economizer_sig_col] > 0.9)
|
114
|
+
)
|
115
|
+
|
116
|
+
# Set fault flag
|
117
|
+
self._set_fault_flag(df, combined_check, "fc10_flag")
|
118
|
+
|
119
|
+
return df
|
@@ -0,0 +1,139 @@
|
|
1
|
+
import pandas as pd
|
2
|
+
|
3
|
+
from open_fdd.core.base_fault import BaseFaultCondition
|
4
|
+
from open_fdd.core.components import FaultInputColumn, InstanceAttribute
|
5
|
+
from open_fdd.core.exceptions import InvalidParameterError
|
6
|
+
from open_fdd.core.mixins import FaultConditionMixin
|
7
|
+
|
8
|
+
INPUT_COLS = [
|
9
|
+
FaultInputColumn(
|
10
|
+
name="sat_col",
|
11
|
+
constant_form="SAT_COL",
|
12
|
+
description="Supply air temperature",
|
13
|
+
unit="°F",
|
14
|
+
required=True,
|
15
|
+
type=float,
|
16
|
+
),
|
17
|
+
FaultInputColumn(
|
18
|
+
name="sat_sp_col",
|
19
|
+
constant_form="SAT_SP_COL",
|
20
|
+
description="Supply air temperature setpoint",
|
21
|
+
unit="°F",
|
22
|
+
required=True,
|
23
|
+
type=float,
|
24
|
+
),
|
25
|
+
FaultInputColumn(
|
26
|
+
name="cooling_sig_col",
|
27
|
+
constant_form="COOLING_SIG_COL",
|
28
|
+
description="Cooling signal",
|
29
|
+
unit="%",
|
30
|
+
required=True,
|
31
|
+
type=float,
|
32
|
+
),
|
33
|
+
FaultInputColumn(
|
34
|
+
name="economizer_sig_col",
|
35
|
+
constant_form="ECONOMIZER_SIG_COL",
|
36
|
+
description="Economizer signal",
|
37
|
+
unit="%",
|
38
|
+
required=True,
|
39
|
+
type=float,
|
40
|
+
),
|
41
|
+
]
|
42
|
+
|
43
|
+
FAULT_PARAMS = [
|
44
|
+
InstanceAttribute(
|
45
|
+
name="supply_degf_err_thres",
|
46
|
+
constant_form="SUPPLY_DEGF_ERR_THRES",
|
47
|
+
description="Supply air temperature error threshold",
|
48
|
+
unit="°F",
|
49
|
+
type=float,
|
50
|
+
),
|
51
|
+
InstanceAttribute(
|
52
|
+
name="mix_degf_err_thres",
|
53
|
+
constant_form="MIX_DEGF_ERR_THRES",
|
54
|
+
description="Mixed air temperature error threshold",
|
55
|
+
unit="°F",
|
56
|
+
type=float,
|
57
|
+
),
|
58
|
+
InstanceAttribute(
|
59
|
+
name="outdoor_degf_err_thres",
|
60
|
+
constant_form="OUTDOOR_DEGF_ERR_THRES",
|
61
|
+
description="Outdoor air temperature error threshold",
|
62
|
+
unit="°F",
|
63
|
+
type=float,
|
64
|
+
),
|
65
|
+
InstanceAttribute(
|
66
|
+
name="ahu_min_oa_dpr",
|
67
|
+
constant_form="AHU_MIN_OA_DPR",
|
68
|
+
description="Minimum outdoor air damper position",
|
69
|
+
unit="fraction",
|
70
|
+
type=float,
|
71
|
+
),
|
72
|
+
]
|
73
|
+
|
74
|
+
|
75
|
+
class FaultConditionThirteen(BaseFaultCondition, FaultConditionMixin):
|
76
|
+
"""Class provides the definitions for Fault Condition 13.
|
77
|
+
Supply air temperature too high in full cooling mode.
|
78
|
+
This fault checks if SAT is too high compared to SAT setpoint
|
79
|
+
in OS3 (economizer + mechanical cooling) and OS4 (mechanical cooling only) modes.
|
80
|
+
|
81
|
+
py -3.12 -m pytest open_fdd/tests/ahu/test_ahu_fc13.py -rP -s
|
82
|
+
"""
|
83
|
+
|
84
|
+
input_columns = INPUT_COLS
|
85
|
+
fault_params = FAULT_PARAMS
|
86
|
+
equation_string = (
|
87
|
+
"fc13_flag = 1 if (SAT > SATSP + εSAT) and "
|
88
|
+
"((CLG > 0.9 and ECO > 0.9) or (CLG > 0.9 and ECO = MIN_OA)) "
|
89
|
+
"for N consecutive values else 0 \n"
|
90
|
+
)
|
91
|
+
description_string = (
|
92
|
+
"Fault Condition 13: Supply air temperature too high in full cooling mode "
|
93
|
+
"in OS3 (economizer + mechanical cooling) and OS4 (mechanical cooling only) modes \n"
|
94
|
+
)
|
95
|
+
error_string = "One or more required columns are missing or None \n"
|
96
|
+
|
97
|
+
@FaultConditionMixin._handle_errors
|
98
|
+
def apply(self, df: pd.DataFrame) -> pd.DataFrame:
|
99
|
+
"""Apply the fault condition to the DataFrame."""
|
100
|
+
# Apply common checks
|
101
|
+
self._apply_common_checks(df)
|
102
|
+
|
103
|
+
# Get column values using accessor methods
|
104
|
+
sat_col = self.get_input_column("sat_col")
|
105
|
+
sat_sp_col = self.get_input_column("sat_sp_col")
|
106
|
+
cooling_sig_col = self.get_input_column("cooling_sig_col")
|
107
|
+
economizer_sig_col = self.get_input_column("economizer_sig_col")
|
108
|
+
|
109
|
+
# Get parameter values using accessor methods
|
110
|
+
supply_degf_err_thres = self.get_param("supply_degf_err_thres")
|
111
|
+
ahu_min_oa_dpr = self.get_param("ahu_min_oa_dpr")
|
112
|
+
|
113
|
+
# Check analog outputs [data with units of %] are floats only
|
114
|
+
columns_to_check = [
|
115
|
+
economizer_sig_col,
|
116
|
+
cooling_sig_col,
|
117
|
+
]
|
118
|
+
self._apply_analog_checks(df, columns_to_check, check_greater_than_one=True)
|
119
|
+
|
120
|
+
# Check if SAT is too high compared to setpoint
|
121
|
+
sat_too_high = df[sat_col] > (df[sat_sp_col] + supply_degf_err_thres)
|
122
|
+
|
123
|
+
# Check operating modes:
|
124
|
+
# OS3: Economizer + full mechanical cooling (ECO > 0.9 and CLG > 0.9)
|
125
|
+
os3_mode = (df[economizer_sig_col] > 0.9) & (df[cooling_sig_col] > 0.9)
|
126
|
+
|
127
|
+
# OS4: Full mechanical cooling only (ECO = MIN_OA and CLG > 0.9)
|
128
|
+
os4_mode = (df[economizer_sig_col] <= ahu_min_oa_dpr) & (
|
129
|
+
df[cooling_sig_col] > 0.9
|
130
|
+
)
|
131
|
+
|
132
|
+
# Combine conditions:
|
133
|
+
# Fault occurs when SAT is too high in either OS3 or OS4 mode with full cooling
|
134
|
+
combined_check = sat_too_high & (os3_mode | os4_mode)
|
135
|
+
|
136
|
+
# Set fault flag
|
137
|
+
self._set_fault_flag(df, combined_check, "fc13_flag")
|
138
|
+
|
139
|
+
return df
|