In some cases, the utilization of a piece of equipment can be determined by retrieving the time that the equipment was actually running and producing product.
Flow has a Time In State retrieval method and with the use of a Filter tag, one can determine utilization based on one filter condition, such as the equipment's State tag.
But what if your business rule to determine this is a little more complex? For example, what if the equipment is only considered to be in use when it is in a certain state AND when the flow rate exceeds a threshold value?
This is where custom expressions come into play. With a custom expression, you can evaluate complex conditions and re-use Flow retrieval methods, such as the Time in State retrieval method.
After all, you don't want to rewrite functionality that comes in the box!
Example
Assume that we are monitoring the actual state of a piece of equipment (tag: FL001.State) and the incoming product flow rate (tag: 110-FQ-001.PV).
The business rule is that the equipment is being utilized only if its state is 0 AND the flow rate is greater than 10hl/hr
The total time that the equipment was being utilized can be evaluated with the following custom expression:
List<TranslationRow> data = (List<TranslationRow>)Data; List<TranslationRow> dataFiltered = new List<TranslationRow>(); foreach(var row in data) {
TranslationRow rownew = new TranslationRow();
rownew.Timestamp = row.Timestamp; //Only add the value in the equipment is in state 0 and the product flow is greater than 10 hl/h // double? value = ((row.Results[FL001.State].Value == 0) && (row.Results[110-FQ-001.PV].Value > 10))? 1.0 : 0.0; rownew.Results = new List<Result>(); //Add quality of 192 (Always good) - The minimum quality value of the two tags could also been used // rownew.Results.Add(new Result(value,192)); dataFiltered.Add(rownew); } Aggregations<TranslationRow> aggregations = new Aggregations<TranslationRow> (dataFiltered , input => {return new Flow.DataSource.Utilities.Point ( input.Timestamp, input.Results[0].Value, input.Results[0].Quality); });
//Evaluate the time in state if the resulting point in the list is 1 (True) //
return aggregations.TimeInState(PeriodStart, PeriodEnd, point=> point.Value == 1);
After adding the two tags (FL001.State and 110-FQ-001.PV) as Items to the custom expression, one can write C# code to evaluate and return the utilization of the equipment.
- Flow retrieves all data points (timestamp, value and quality) for each item for the period (e.g. for the hour in an hourly measure) and store these in the Data object.
- In this expression, each row of Data is iterated through, and any rows where FL001.State is 0 AND 110-FQ-001.PV > 10 is added to a list named dataFiltered
- Once the filtered data is in an object of type Aggregations (a Flow object), one can use the built-in aggregation methods. In this case, the TimeInState method is used to return the total duration for which the equipment was in the specified condition
Note that TimeInState will always return a duration in milliseconds.
For more information, see the section on Custom Expressions.