Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Local loop verify #8

Merged
merged 12 commits into from
Oct 1, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions CITATION.cff
Original file line number Diff line number Diff line change
Expand Up @@ -39,5 +39,5 @@ abstract: >-
ANIMATE)
license: BSD-2-Clause
commit: a8b74df506f141d7840403a06a255959157bcc1e
version: 0.1.0
date-released: '2023-03-31'
version: 0.3.0
date-released: '2023-09-30'
8 changes: 5 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@ See the Publications section for more information and example of uses of the fra
- Demos are located in `demo/`
- Visit [API documentation page](https://pnnl.github.io/ConStrain/) to learn about how to use the ConStrain API.
- Visit [Guideline 36 Verification Items List](./design/g36_lib_contents.md) to learn more about the ASHRAE Guideline 36 related verification in ConStrain verification library.
- Visit [Local Loop Verification Items List](./design/local_loop_verification_items_list.md) to learn more about local loop performance verification library.
- Visit [Brick Integration Doc](./design/brick_integration_doc.md) to learn more about the beta version of brick schema integration API.

<!-- ## Note

Expand All @@ -66,12 +68,12 @@ See the Publications section for more information and example of uses of the fra

## Publications

- Chen Y., M. Wetter, X. Lei, J. Lerond, P.K. Anand, Y. Jung, P. Ehrlich, and D.L. Vrabie. 2023. "Control Performance Verification – The Hidden Opportunity of Ensuring High Performance of Building Control System." In Building Simulation 2023 Conference (Submitted)
- Lei X., J. Lerond, Y. Jung, and Y. Chen. 2023. "Development of an Application Programming Interface for a Building Systems Control Performance Verification Framework." In 2023 ASHRAE Annual Conference (In Press)
- Chen Y., M. Wetter, X. Lei, J. Lerond, P.K. Anand, Y. Jung, P. Ehrlich, and D.L. Vrabie. 2023. "Control Performance Verification – The Hidden Opportunity of Ensuring High Performance of Building Control System." In Building Simulation 2023 Conference
- Lei X., J. Lerond, Y. Jung, and Y. Chen. 2023. "Development of an Application Programming Interface for a Building Systems Control Performance Verification Framework." In 2023 ASHRAE Annual Conference
- [Chen Y., J. Lerond, X. Lei, and M.I. Rosenberg. 2021. "A Knowledge-based Framework for Building Energy Model Performance Verification." In Building Simulation 2021 Conference](https://publications.ibpsa.org/conference/paper/?id=bs2021_30725)

## Referencing

If you wish to cite ConStrain in academic work please cite the above publication.
If you wish to cite ConStrain in academic work please use: Lei, X., Lerond, J., Jung, Y. J., & Chen, Y. (2023). ConStrain (Version 0.3.0) [Computer software]. https://github.com/github/ConStrain

<!-- Pending DOI for new ConStrain -->
120 changes: 120 additions & 0 deletions design/local_loop_lib_contents.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
# Local Loop Performance Verification Library Items

----

## Local Loop Performance Verification - Set Point Tracking

### Description

This verification checks the set point tracking ability of local control loops.

### Verification logic

With a threshold of 5% of abs(set_point) (if the set point is 0, then the threshold is default to be 0.01), if the number of samples of which the error is larger than this threshold is beyond 5% of number of all samples, then this verification fails; Otherwise, it passes.

### Data requirements

- feedback_sensor: feedback sensor reading of the subject to be controlled towards a set point
- set_point: set point value


## Local Loop Performance Verification - Set Point Unmet Hours

### Description

This verification checks the set point tracking ability of local control loops.

### Verification logic

Instead of checking the number of samples among the whole data set for which the set points are not met, this verification checks the total accumulated time that the set points are not met within a threshold of 5% of abs(set_point) (if the set point is 0, then the threshold is default to be 0.01).

If the accumulated time of unmet set point is beyond 5% of the whole duration the data covers, then this verification fails; otherwise, it passes.

### Data requirements

- feedback_sensor: feedback sensor reading of the subject to be controlled towards a set point
- set_point: set point value

## Local Loop Performance Verification - Direct Acting Loop Actuator Maximum Saturation

### Description

This verification checks that a direct acting control loop would saturate its actuator to maximum when the error is consistently above the set point [^1].

### Verification logic

If the sensed data values are consistently above its set point, and after a default of 1 hour, the control command is still not saturated to maximum, then the verification fails; Otherwise, it passes.

### Data requirements

- feedback_sensor: feedback sensor reading of the subject to be controlled towards a set point
- set_point: set point value
- cmd : control command
- cmd_max: control command range maximum value

## Local Loop Performance Verification - Direct Acting Loop Actuator Minimum Saturation

### Description

This verification checks that a direct acting control loop would saturate its actuator to minimum when the error is consistently below the set point [^1].

### Verification logic

If the sensed data values are consistently below its set point, and after a default of 1 hour, the control command is still not saturated to minimum, then the verification fails; Otherwise, it passes.

### Data requirements

- feedback_sensor: feedback sensor reading of the subject to be controlled towards a set point
- set_point: set point value
- cmd : control command
- cmd_min: control command range minimum value

## Local Loop Performance Verification - Reverse Acting Loop Actuator Maximum Saturation

### Description

This verification checks that a reverse acting control loop would saturate its actuator to maximum when the error is consistently below the set point [^1].

### Verification logic

If the sensed data values are consistently below its set point, and after a default of 1 hour, the control command is still not saturated to maximum, then the verification fails; Otherwise, it passes.

### Data requirements

- feedback_sensor: feedback sensor reading of the subject to be controlled towards a set point
- set_point: set point value
- cmd : control command
- cmd_max: control command range maximum value

## Local Loop Performance Verification - Reverse Acting Loop Actuator Minimum Saturation

### Description

This verification checks that a reverse acting control loop would saturate its actuator to minimum when the error is consistently above the set point [^1].

### Verification logic

If the sensed data values are consistently above its set point, and after a default of 1 hour, the control command is still not saturated to minimum, then the verification fails; Otherwise, it passes.

### Data requirements

- feedback_sensor: feedback sensor reading of the subject to be controlled towards a set point
- set_point: set point value
- cmd : control command
- cmd_min: control command range minimum value

<!-- ## Local Loop Performance Verification - Loop Activation Hunting

### Description

This verification checks if a loop has hunting behavior in terms of frequently activate and deactivate its actuator. -->

## Local Loop Performance Verification - Actuator Rate of Change

### Description

This verification checks if a local loop actuator has dramatic change of its actuating command. This verification is implemented as instructed by ASHRAE Guideline 36 2021 Section 5.1.9 in Verification Item `G36OutputChangeRateLimit`.



[^1]: Lei, Xuechen, Yan Chen, Mario Bergés, and Burcu Akinci. "Formalized control logic fault definition with ontological reasoning for air handling units." Automation in Construction 129 (2021): 103781.
86 changes: 86 additions & 0 deletions schema/library.json
Original file line number Diff line number Diff line change
Expand Up @@ -1055,5 +1055,91 @@
],
"description_verification_type": "rule-based",
"assertions_type": "pass"
},
"LocalLoopSetPointTracking": {
"library_item_id": 47,
"description_brief": "Local Loop Performance Verification - Set Point Tracking",
"description_datapoints": {
"feedback_sensor": "feedback sensor reading of the subject to be controlled towards a set point",
"set_point": "set point value"
},
"description_assertions": [
"With a threshold of 5% of abs(set_point) (if the set point is 0, then the threshold is default to be 0.01), if the number of samples of which the error is larger than this threshold is beyond 5% of number of all samples, then this verification fails; Otherwise, it passes."
],
"description_verification_type": "procedure-based",
"assertions_type": "pass"
},
"LocalLoopUnmetHours": {
"library_item_id": 48,
"description_brief": "Local Loop Performance Verification - Set Point Unmet Hours",
"description_datapoints": {
"feedback_sensor": "feedback sensor reading of the subject to be controlled towards a set point",
"set_point": "set point value"
},
"description_assertions": [
"Instead of checking the number of samples among the whole data set for which the set points are not met, this verification checks the total accumulated time that the set points are not met within a threshold of 5% of abs(set_point) (if the set point is 0, then the threshold is default to be 0.01)."
],
"description_verification_type": "procedure-based",
"assertions_type": "pass"
},
"LocalLoopSaturationDirectActingMax": {
"library_item_id": 49,
"description_brief": "Local Loop Performance Verification - Direct Acting Loop Actuator Maximum Saturation",
"description_datapoints": {
"feedback_sensor": "feedback sensor reading of the subject to be controlled towards a set point",
"set_point": "set point value",
"cmd": "control command",
"cmd_max": "control command range maximum value"
},
"description_assertions": [
"If the sensed data values are consistently above its set point, and after a default of 1 hour, the control command is still not saturated to maximum, then the verification fails; Otherwise, it passes."
],
"description_verification_type": "procedure-based",
"assertions_type": "pass"
},
"LocalLoopSaturationDirectActingMin": {
"library_item_id": 50,
"description_brief": "Local Loop Performance Verification - Direct Acting Loop Actuator Minimum Saturation",
"description_datapoints": {
"feedback_sensor": "feedback sensor reading of the subject to be controlled towards a set point",
"set_point": "set point value",
"cmd": "control command",
"cmd_min": "control command range minimum value"
},
"description_assertions": [
"If the sensed data values are consistently below its set point, and after a default of 1 hour, the control command is still not saturated to minimum, then the verification fails; Otherwise, it passes."
],
"description_verification_type": "procedure-based",
"assertions_type": "pass"
},
"LocalLoopSaturationReverseActingMax": {
"library_item_id": 51,
"description_brief": "Local Loop Performance Verification - Reverse Acting Loop Actuator Maximum Saturation",
"description_datapoints": {
"feedback_sensor": "feedback sensor reading of the subject to be controlled towards a set point",
"set_point": "set point value",
"cmd": "control command",
"cmd_max": "control command range maximum value"
},
"description_assertions": [
"If the sensed data values are consistently below its set point, and after a default of 1 hour, the control command is still not saturated to maximum, then the verification fails; Otherwise, it passes."
],
"description_verification_type": "procedure-based",
"assertions_type": "pass"
},
"LocalLoopSaturationReverseActingMin": {
"library_item_id": 52,
"description_brief": "Local Loop Performance Verification - Reverse Acting Loop Actuator Minimum Saturation",
"description_datapoints": {
"feedback_sensor": "feedback sensor reading of the subject to be controlled towards a set point",
"set_point": "set point value",
"cmd": "control command",
"cmd_min": "control command range minimum value"
},
"description_assertions": [
"If the sensed data values are consistently above its set point, and after a default of 1 hour, the control command is still not saturated to minimum, then the verification fails; Otherwise, it passes."
],
"description_verification_type": "procedure-based",
"assertions_type": "pass"
}
}
63 changes: 63 additions & 0 deletions src/library/LocalLoopSaturationDirectActingMax.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
"""
## Local Loop Performance Verification - Direct Acting Loop Actuator Maximum Saturation

### Description

This verification checks that a direct acting control loop would saturate its actuator to maximum when the error is consistently above the set point.

### Verification logic

If the sensed data values are consistently above its set point, and after a default of 1 hour, the control command is still not saturated to maximum, then the verification fails; Otherwise, it passes.

### Data requirements

- feedback_sensor: feedback sensor reading of the subject to be controlled towards a set point
- set_point: set point value
- cmd: control command
- cmd_max: control command range maximum value

"""

import pandas as pd
from checklib import RuleCheckBase


class LocalLoopSaturationDirectActingMax(RuleCheckBase):
points = ["feedback_sensor", "set_point", "cmd", "cmd_max"]

def saturation_flag(self, t):
if 0 <= t["cmd_max"] - t["cmd"] <= 0.01:
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should the 0.01 be a "user-input" with a default value? Similarly to how we handle tolerances.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there any circumstances where the command might be negative for some reason? In other words should we use abs(t["cmd_max"] - t["cmd"])?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

for 1), my intention is to require as little user inputs / config as possible, so that 0.01 is used. We can certainly change it to a parameter later;
for 2), if it is negative, I would prefer to fail the verification or raise an error. For now, if it is negative, then this would be considered "not saturated", so it has a larger chance of reporting fail than pass.

return True
else:
return False

def err_flag(self, t):
if t["feedback_sensor"] > t["set_point"]:
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same comment as above for the command. I doubt it but still wanted to raise the question in case you think that it might be an issue.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To me this is a different issue from the comment earlier. Because this is a direct acting controller, then saturating towards maximum is the expected behavior when the sensor reading is constantly above the set point, not the other way around.

return True
else:
return False

def verify(self):
self.saturation = self.df.apply(lambda t: self.saturation_flag(t), axis=1)
self.err = self.df.apply(lambda t: self.err_flag(t), axis=1)
self.result = pd.Series(index=self.df.index)
err_start_time = None
err_time = 0
for cur_time, cur in self.df.iterrows():
if self.err.loc[cur_time]:
if err_start_time is None:
err_start_time = cur_time
else:
err_time = (
cur_time - err_start_time
).total_seconds() / 3600 # in hours
else: # reset
err_start_time = None
err_time = 0

if err_time > 1 and (not self.saturation.loc[cur_time]):
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

>= 1 instead of > 1?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I use > 1 to make it a tiny bit more difficult to fail

result_flag = False
else:
result_flag = True

self.result.loc[cur_time] = result_flag
63 changes: 63 additions & 0 deletions src/library/LocalLoopSaturationDirectActingMin.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
"""
## Local Loop Performance Verification - Direct Acting Loop Actuator Minimum Saturation

### Description

This verification checks that a direct acting control loop would saturate its actuator to minimum when the error is consistently below the set point.

### Verification logic

If the sensed data values are consistently below its set point, and after a default of 1 hour, the control command is still not saturated to minimum, then the verification fails; Otherwise, it passes.

### Data requirements

- feedback_sensor: feedback sensor reading of the subject to be controlled towards a set point
- set_point: set point value
- cmd: control command
- cmd_min: control command range minimum value

"""

import pandas as pd
from checklib import RuleCheckBase


class LocalLoopSaturationDirectActingMin(RuleCheckBase):
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would it make sense to have only one verification that would handle min/max? The logic is essentially the same.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

similar to above, I think min and max are for sensor reading on two sides of the set points separately.

points = ["feedback_sensor", "set_point", "cmd", "cmd_min"]

def saturation_flag(self, t):
if 0 <= t["cmd"] - t["cmd_min"] <= 0.01:
return True
else:
return False

def err_flag(self, t):
if t["feedback_sensor"] < t["set_point"]:
return True
else:
return False

def verify(self):
self.saturation = self.df.apply(lambda t: self.saturation_flag(t), axis=1)
self.err = self.df.apply(lambda t: self.err_flag(t), axis=1)
self.result = pd.Series(index=self.df.index)
err_start_time = None
err_time = 0
for cur_time, cur in self.df.iterrows():
if self.err.loc[cur_time]:
if err_start_time is None:
err_start_time = cur_time
else:
err_time = (
cur_time - err_start_time
).total_seconds() / 3600 # in hours
else: # reset
err_start_time = None
err_time = 0

if err_time > 1 and (not self.saturation.loc[cur_time]):
result_flag = False
else:
result_flag = True

self.result.loc[cur_time] = result_flag
Loading
Loading