G2 Project

Controlling a Furnace

Due Friday February 9, 2007

 

G2 is specifically designed for real time control:

In this application you will exercise G2 in a characteristic application.  This exercise is adapted from an exercise used by Gensym in the training they offer their customers.

The setup:

I have created a knowledgebase called FURNACE.kb.  It has some basic definitions in it with which you will work implementing this project.  This kb is in the same directory as g2 (/usr/local/gensym/g2-8.0r1/g2/FURNACE.kb).  You can load this kb, do your development, and save your new version to your own directory.

 

When you load the FURNACE.kb, start g2 and wait for the initialization to occur.  I have used some Gensym modules (specifically for the little navigation buttons) in this kb, and those modules need to initialize themselves at the start.  You will know initialization is complete when a row of menu choices appears at the top of the screen.  Put yourself in DEVELOPER user-mode so that the navigation buttons will behave in their helpful way for you.

 

Your task:

You will develop an application that monitors the temperature and water flow of a furnace.  Your application will:

 

Step 1:

To represent the temperature of a furnace, you need to remember that the temperature information will be coming from an external sensor.  Therefore we will use a g2-variable to represent the temperature, because g2-variables can receive information from an external data source.

 

Your temperature variable will need particular values for some attributes like validity-interval and data-server, so create a new class of g2-variable called “gsi-indefinite-var” as follows:

 

We won’t be connecting to a sensor, but we will build the application so that we could connect immediately via a bridge application.

 

Specify the temperature attribute of the furnace class as being “given by” a gsi-indefinite-var.

 

Create an instance of a furnace and name it HOT-ONE.

 

Create two action-buttons which conclude values of 320 degrees and 280 degrees, respectively, to the temperature of HOT-ONE.  These will provide values to the variable for testing other logic.

 

Step 2:

You need to record whether or not a furnace is in a high-temperature-state (true or false).  Add such an attribute to the furnace class.

 

Write a rule that concludes that a furnace is in a high-temperature-state when the temperature is greater than 300. 

 

Write another rule that will conclude the reverse when the temperature is less than 300.

 

Use ‘IF” rules rather than “WHENEVER” rules for this work, because IF rules are invoked by forward chaining, and cause processing only when the value in the rule’s antecedent changes.  WHENEVER rules would fire on every “event” of receiving data, whether or not the value has changed.

 

When you test your rules, you will probably find that they do not work.  This is because float-variables by default do not forward chain.  The reason for this default behavior is that float-variables whose values change by inconsequential amounts on each reading could cause unnecessary processing.  In our case, change the class definition for gsi-indefinite-var to “do forward chain, breadth-first backward chain”.  You accomplish this with attribute-initializations in the class definition.

 

Test your rule, and make sure it is generic -- i.e., it should work for any furnace, not just HOT-ONE.

 

Step 3:

We want to avoid hard-coding the high temperature limit into our rules and procedures.  Add an attribute to your furnace class called “high-temperature-limit”.  Make it a simple attribute with an initial value of 300.

 

Change your rules so that they refer to the high-temperature-limit instead of the number 300.

 

Step 4:

When the temperature is high (and only when the temperature is high), we want to monitor the water-flow in the furnace.  Water-flow will also come from GSI in a real application.  Create another g2-variable class called “gsi-2sec-var” as follows:

 

Add an attribute to your furnace class called water-flow, and use the gsi-2sec-var class to define it.  Also add a simple attribute called average-flow that will be a quantity, with an initial value of 20.

 

Eventually the application will run on-line, but for now we can write a rule to model the water-flow.  This will allow the water-flow variable to seek data, for the time being, from the G2 inference engine.  Write a rule that will unconditionally conclude that the water-flow of hot-one = the average-flow of hot-one + random( -2, 2 ).  Watch to see if the water-flow of hot-one is being updated?  It is not being updated because nothing is causing data-seeking.

 

Data-seeking can be caused by 1) a variable’s update-interval, 2) the update-interval of a display like a readout-table or a trend-chart, 3) the evaluation of an expression elsewhere in the kb which requires a value for the variable, 4) a “collect data” statement in a procedure, or 5) an “update” action (less common).  To cause data-seeking, display the table for HOT-ONE, and then display the subtable for water-flow.  Edit the default-update-interval for water-flow to set the interval to 5 seconds.  You should now see the value being updated -- the update interval causes data-seeking, and G2 backward chains to the rule in the previous paragraph to get a new value for water-flow.  The water-flow of the furnace should change every 5 seconds.  The value of water-flow will be within +/- 2 of the average-flow.

 

To make it easy to change conditions, make two action-buttons, one of which sets the average-flow of HOT-ONE to 16, and one of which sets the average-flow of HOT-ONE to 20.  Make sure that the values of water-flow follow the changes to average-flow in a reasonable way (e.g., if average-flow is 16, the water-flow should vary between 14 and 18).

 

Step 5:

When the temperature gets too high, you want to monitor water-flow in the furnace.  Write a rule that will react to water-flow of less than 18 and warn the operator (“inform the operator that ...”).  The rule should not be invoked by forward-chaining, because that would cause the rule to fire every time a new value arrives for water-flow.  Instead, use a scan-interval on your rule to check the water-flow every 5 seconds.  Make the rule generic so that it will apply to any furnace.  Test the rule using the action-buttons you created in the step above.  You should see the warning when you set the water-flow to be less than 18.

 

If the temperature is not too high, there’s no need to monitor the water-flow.  Name the rule you just wrote WATER-FLOW-RULE so that you can programmatically change its behavior.  Then create another rule that will turn on scanning IF a furnace is in a high-temperature-state.  When high-temperature-state becomes true, the rule should ‘change the text of the scan-interval of water-flow-rule to “5 seconds” ’

 

Write another rule to change the text of water-flow-rule to “none” when the furnace is not in a high-temperature-state.

 

Test your work using the action-buttons you created in the first step to change the temperature of the furnace.  When the temperature of the furnace becomes too hot, your water-flow-rule should start checking the flow of water.  If, under high temperature conditions, the water-flow is too low, you should see the warning message.  Once the furnace temperature goes down, the water-flow-rule should stop checking the flow of water.

 

Step 6:

Alert the operator when a furnace becomes unsafe.  A furnace is unsafe if it enters a high-temperature-state for more than 20 seconds. 

 

A useful approach to this kind of problem is to represent “states” as objects.  The state object can have many useful attributes, such as time-entered, time-exited, duration, maximum-temperature, supervisor-on-duty, etc., etc. 

 

Create a new class definition for hi-temp-state.  Add the attributes starting-time and ending-time.  Starting-time and ending-time can be simple quantitative attributes. 

 

Edit the rule you wrote for testing the high-temperature-state of any furnace so that it also, in order, creates a hi-temp-state object, and transfers the hi-temp-state object to the workspace of the furnace.

 

To organize the state objects you can use a list.  Create a new class definition called “OCCURRENCES-LIST”; make it a subclass of item-list.  Using attribute-initializations, establish the object-type for the list: “element type for item-list: hi-temp-state”  This will enforce the rule that only hi-temp-state objects can be inserted into a list of this class.

 

Go back to your furnace class definition, and add an attribute called occurrences-of-high-temp.  Specify that this attribute is an instance of an occurrences-list.  Now each furnace will have an attribute that represents a list of all the hi-temp-states.

 

Edit again the rule you wrote for testing the high-temperature-state of any furnace, so that the rule “inserts” the new hi-temp-state “at the end of the occurrences-of-high-temp” of the furnace.  At the same time, remove the statement that transfers the hi-temp-state object to the workspace (this is no longer needed, as the hi-temp-state objects will be accessible from the list occurrences-of-high-temp).  Test the rule.  Show the table for hot-one; click on the occurrences-of-high-temp attribute and choose “describe.”  You will see representations of the hi-temp-state objects in the list.

 

Edit the rule you wrote for testing the high-temperature-state of any furnace so that it also records the starting time of the hi-temp-state (use the expression, “the current time”).

 

Edit the rule you wrote for detecting the return from a high-temperature-state of any furnace so that it also records the ending time of the condition.  To record the ending time, refer to the “last” hi-temp-state in the occurrences-of-high-temp of the furnace.  Also, for the “corner case” of there being no state objects in the list, you need to check for existence first: “if the last hi-temp-state in the occurrences-of-high-temp of F exists ...”

 

The duration of a hi-temp-state is also important, and to compute that easily we will take advantage of a G2 “generic formula.”  First, define a new subclass of quantitative variable called “inference-engine-var” with these characteristics:

Now add an attribute to the hi-temp-state class called “duration”, and have it defined by an inference-engine-var.

 

To create a generic formula, select New Definition --> generic-formula from a workspace menu.  The generic-formula has language for conditional expressions that we can take advantage of.  In the one case, the state object will have both starting and ending times, and the duration will simply be the difference.  In the other case, the state object will have a starting time and no ending time, and the duration will be the difference between the current time and the starting time.  Here is language that will work:

 

If you don’t see anything changing in any hi-temp-state object as a result of the generic formula, it is because nothing is causing data-seeking, so G2 is not consulting the formula.  One way to cause data-seeking is to apply an update-interval to the inference-engine-var class that is used for the duration attribute.  Change the default update interval of inference-engine-var to 1 second.  Now every second the duration of every state object will be updated.

 

Write a rule that displays an alarm message if the duration of a hi-temp-state exceeds 10 seconds.  Cause the rule to be invoked by giving it a scan interval of 2 seconds.  Again, since there might not be any hi-temp-state in the list initially, you need to check for existence.  Here is some language that will work:

for any furnace F if the last hi-temp-state in the occurrences-of-high-temp of F exists and the duration of the last hi-temp-state in the occurrences-of-high-temp of F > 10 then inform the operator for the next 2 seconds that “.....”

 

Now change your class definition for furnace to add an attribute “overheating-duration” which initially is set to 10.  Change the rule you just wrote to refer to that attribute instead of the hard-coded value of 10.

 

Etc... (optional)

Feel free to further explore.  Try adding a readout table that shows “the number of elements in the occurrences-of-high-temp of hot-one” so that you see how often the furnace heat limit has been exceeded.  Add a rule that declares the furnace to be damaged if it enters a high temperature condition 3 or more times.

Details:

Give some thought to the content of various workspaces in your kb.  Try to organize things so they look good and make sense.

 

Your kb should be named XYZ-FURNACE.KB, where ‘XYZ’ are your initials.  After loading the initial kb from the /g2/ directory, save your kb in your own directory structure.  To submit your kb, send it to me as an e-mail attachment.