-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
99ec069
commit 23b65bb
Showing
3 changed files
with
134 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,84 @@ | ||
""" | ||
G36 2021 | ||
### Description | ||
Section 5.16 interpretation: | ||
- With Relief damper or relief fan | ||
- when eonomizer control is not in lockout, and actual damper positions are controlled by the SAT control loop. Above only set the lower limit for OA damper. Track MinOAsp with a reverse-acting loop and map output to | ||
- OA (economizer) damper minimum position MinOA-P | ||
- return air damper maximum positivion MaxRA-P | ||
- when economizer is in lockout for more than 10 minutes (exceeding economizer high limit conditions in Section 5.1.17), the dampers are controlled to meet minimum OA requirements | ||
- fully open RA damper | ||
- set MaxOA-P = MinOA-P, control OA damper to meet MinOAsp | ||
- modulate RA damper to maintain MinOAsp (return air damper position equals to MaxRA-P) | ||
Verification Item 1: | ||
- when economizer condition okay and occupied, check OA beyond minOA, leave actual control of dampers to SAT control | ||
### Verification logic | ||
```python | ||
if not economizer_lockout(outdoor_air_temp, economizer_high_limit_sp) and sys_mode == 'occupied': | ||
if oudoor_damper_command >= MinOA-P and outdoor_air_flow >= MinOAsp: | ||
pass | ||
else: | ||
fail | ||
else: | ||
untested | ||
``` | ||
### Data requirements | ||
- outdoor_air_temp: outdoor air temperature | ||
- economizer_high_limit_sp: economizer lockout high limit set point | ||
- outdoor_damper_command: outdoor air damper command | ||
- MinOA-P: minimum outdoor air damper position set point | ||
- MinOAsp: minimum outdoor air flow rate setpoint | ||
- outdoor_air_flow: outdoor air flow rate | ||
- sys_mode: AHU system mode mode, enumeration of ['occupied', 'unoccupied', 'cooldown', 'warmup', 'setback', 'setup'] | ||
""" | ||
|
||
import pandas as pd | ||
from checklib import RuleCheckBase | ||
from datetime import datetime | ||
import numpy as np | ||
|
||
|
||
class G36MinOAwEconomizer(RuleCheckBase): | ||
points = [ | ||
"outdoor_air_temp", | ||
"economizer_high_limit_sp", | ||
"outdoor_damper_command", | ||
"MinOA-P", | ||
"outdoor_air_flow", | ||
"MinOAsp", | ||
"sys_mode", | ||
] | ||
|
||
def economizer_lockout(self, outdoor_air_temp, economizer_hjgh_limit_sp): | ||
if outdoor_air_temp > economizer_hjgh_limit_sp: | ||
return True | ||
else: | ||
return False | ||
|
||
def ts_verify_logic(self, t): | ||
if ( | ||
not self.economizer_lockout( | ||
t["outdoor_air_temp"], t["economizer_high_limit_sp"] | ||
) | ||
) and (t["sys_mode"].strip().lower() == "occupied"): | ||
if (t["outdoor_damper_command"] >= t["MinOA-P"]) and ( | ||
t["outdoor_air_flow"] >= t["MinOAsp"] | ||
): | ||
return True | ||
else: | ||
return False | ||
else: | ||
return np.nan | ||
|
||
def verify(self): | ||
self.result = self.df.apply(lambda t: self.ts_verify_logic(t), axis=1) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
import unittest, sys | ||
import datetime | ||
|
||
sys.path.append("./src") | ||
from lib_unit_test_runner import * | ||
from library import * | ||
|
||
import json | ||
import pandas as pd | ||
import numpy as np | ||
|
||
|
||
class TestG36MinOAwEconomizer(unittest.TestCase): | ||
def test_minoa_economizer_pass_untest_fail(self): | ||
points = [ | ||
"outdoor_air_temp", | ||
"economizer_high_limit_sp", | ||
"outdoor_damper_command", | ||
"MinOA-P", | ||
"outdoor_air_flow", | ||
"MinOAsp", | ||
"sys_mode", | ||
] | ||
|
||
data = [ | ||
[20, 24, 25, 20, 2000, 1500, "occupied"], | ||
[20, 24, 25, 20, 2000, 1500, "unoccupied"], | ||
[25, 24, 25, 20, 2000, 1500, "unoccupied"], | ||
[20, 24, 19, 20, 2000, 1500, "occupied"], | ||
[20, 24, 25, 20, 1400, 1500, "occupied"], | ||
[20, 24, 15, 20, 1000, 1500, "occupied"], | ||
] | ||
|
||
df = pd.DataFrame(data, columns=points) | ||
|
||
results = pd.Series( | ||
list(run_test_verification_with_data("G36MinOAwEconomizer", df).result) | ||
) | ||
|
||
expected_results = pd.Series([True, np.nan, np.nan, False, False, False]) | ||
|
||
self.assertTrue(results.equals(expected_results)) | ||
|
||
pass | ||
|
||
|
||
if __name__ == "__main__": | ||
unittest.main() |