Skip to main content
Version: 2.6

Processing Networks

The HumanOS® Kernel comes with a built-in semantic processing network (SPN) capability. This allows to process and correlate data.

These processing networks are not hardwired! Typically, they are placed in the system as a schema. Due to rules, a processing network class is dynamically instantiated and wired to data nodes; and removed dynamically once removal rules are triggered.

In the following graphic notations, we use following terminology:

NameShort.Description
Processing NodeProcProcessing nodes describe active transformation and evaluation nodes. Also referred as processors.
Processing NetworkNThe processing network is a special group node containing the complete processing schema
Input PortsPiInput ports are openings of processing nodes. They allow the processing node to access the outside world (reading).
Output PortPoOutput ports are openings of processing nodes. They allow the processing node to access the outside world (writing).
LinkLinkLinks between ports or ports and data nodes. Also referred as port couplings, they transfer the information from output ports to input ports of other processors.

The root object is a "ProcessingNetwork".

AttributeDescriptionData Type
IdId of the network. Empty if multiple instances can be created from that schemaSystem.Guid
NameName of the networkSystem.String
ProcessorsArray of processors in the networkTProcessingNodeInfo[]
LinksArray of interconnecting links between the processors.TProcessingLinkInfo[]
DataNodesArray of data nodes.TDataNodeInfo[]

Example:

{
"ProcessingNetworks": [
{
"Id": "77B6AACB-B306-4E50-901A-9E12CC706E1D",
"Name": "HumanOS.PeSeL.Correlations.DataProcessors",
"Processors": [],
"Links": [],
"DataNodes": []
}
]
}

Processor Nodes

A processor defines an active code able to process data periodically or event-driven.

The processor node is described by following attributes:

AttributeDescriptionData Type
IdId of the processor. Empty if processor can be instantiated multiple times.System.Guid
NameName of the processorSystem.String
TypeType of processor.EProcessingNodeType
AsynchProcessingThe processing is decoupled from the event sender if set to True. If the processing uses much processor time, it is recommended to set the flag to True. Only for event-based processors.System.Boolean
SamplingRateThe rate at which the data is renewed (default 0s).System.Float
InitialDataInitial data of the processor. Depends on the processor type.System.String[]
PortsCommunication portsTPortInfo[]

Following processor types are available:

TypeDescription
SituationProcessingNodeProcessor for data processing and situation analysis. The correlation logic is limited to simple predicates for situation evaluation.
ExtendedSituationProcessingNodeProcessor for data processing and situation analysis. The correlation logic can be implemented as C#-script. This allows complex situation and correlation analysis.
CSharpScriptProcessingNodeProcessor for data processing and situation analysis based on a script file.
DataAggregatorProcessor to aggregate inputs to a complex entity.
ProxyProcessingNodeProxy processor to bind an external processor logic from a PeMiL Plugin by typename
CSharpScriptStreamProcessingNode[DEPRECATED] Use CSharpScriptProcessingNode instead and set SamplingRate greater than zero.
EventProcessingProxyNode[DEPRECATED] Use ProxyProcessingNode instead and set SamplingRate to zero.
StreamProcessingProxyNode[DEPRECATED] Use ProxyProcessingNode instead and set SamplingRate greater than zero.

Event Driven Processors

If the SamplingRate is set to 0 (zero) the processor is triggered each time a value changes (event driven).

Event Driven Delayed Processors

Event driven processors support an additional setting called DelayTime. This allows to delay the trigger to process the events and is often used to filter high frequency event changes.

PropertyDescriptionData Type
DelayTime[OPTIONAL] The delay time delays the processing in milliseconds.System.Int32

The delay time can be helpful if several events trigger almost at the same time. This could cause immediate situation states, that are not really interesting to higher level systems. In this case, a delay helps to reduce immediate situations delivering only the final situation after n milliseconds.

Example of a delay time of 3 seconds:

{
"Id": "35C93A18-F43A-4866-AFEC-1F25A36B8D6E",
"Name": "MachineStateProcessor",
"Type": "SituationProcessingNode",
"AsynchProcessing": false,
"Properties": [
{
"Name": "DelayTime",
"Value": 3000,
"DataType": "System.Int32"
}
]
}

Sampled Processors

If the SamplingRate is set greater than 0 (zero), the processor is triggered periodically (in seconds).

NOTE

The sampled processors are recommended for streaming data, such as axis values. This reduces the CPU load of the executing process.

Ports

Each processor needs port for communication. Ports are sub elements of the processor. Ports are described by following attributes:

AttributeDescriptionData Type
NameName of the port. The name is used in all correlation predicates to reference that data acquired through the corresponding port.System.String
DataTypeDatatype of the information used to process.System.Type
FlowDirectionDirection of the information flow.
  • Input: The processor is able to read data through the port
  • Output: The processor is able to send data through the port
EPortDirection
ProtocolCommunication protocolEPortProtocol
NecessityIs the port used as mandatory or optional for the processing engineENecessity
PublicFlag, if the port is public. Ports must be set to public when they should be automatically wired with external data nodes. Additionally, they need the port matching property.System.Boolean
TriggerTypeDefines how an event driven processor is triggered by the port. This value is ignored for sampled processors.EPortTriggerType

Available Protocols

Following values can be used for the communication protocol:

ProtocolDescription
EventPassingInformation is event based
StreamingInformation is stream based
MessagingInformation is received as message (alarm). DataType must be HumanOS.Kernel.DataModel.TAbstractEventItem, HumanOS.Kernel.Base

Trigger Types

Following trigger types are available:

TriggerTypeDescription
DefaultDefault settings of the HumanOS Kernel. Currently set to OnChange
OnEventThe processor is triggered if an event passes through the port. (An event can contain the same value again, but with a different timestamp).
OnChangeThe processor is triggered if the value, the state or the meta data changes.
OnPositiveFlankThe processor is triggered if the value has a positive flank to its previous value.
OnNegativeFlankThe processor is triggered if the value has a negative flank to its previous value.
NoneThe processor is not triggered at all.
NOTE

OnPositiveFlank and OnNegativeFlank can only be used for numerical values and strings. For strings, a positive flank is a string in higher alphabetical order, a negative flank vis-versa.

Necessity of Ports

The following necessity values can be set to input ports:

NecessityDescription
OptionalDefault value of the port. The processing engine can work even if this port has no valid data (DataState != good)
MandatoryThe processing engine can work only if all mandatory ports have valid data (DataState == good)
NOTE

If a processing node has mandatory ports, the output ports are set to BadNotActive if at least one of the mandatory ports are not ready.

NOTE

For port matching check Port Matching Rules.

Example of a processing node with one input port:

{
"Id": "41612BA0-AFC9-43E2-AE86-86A97E22B7B1",
"Name": "RunningStateProcessor",
"Type": "SituationProcessingNode",
"AsynchProcessing": false,
"InitialData": [],
"Ports": [
{
"Name": "AvailableState",
"Public": true,
"DataType": "System.Int32",
"FlowDirection": "Input",
"Protocol": "EventPassing",
"Necessity": "Mandatory",
"Properties": [
{
"Name": "PortMatchId",
"Value": "AvailableType"
}
]
},
{
"Name": "ProgramState",
"Public": true,
"DataType": "System.Int32",
"FlowDirection": "Input",
"Protocol": "EventPassing",
"Necessity": "Optional",
"Properties": [
{
"Name": "PortMatchId",
"Value": "ProgramStateType"
}
]
},
{
"Name": "RunningState",
"Public": true,
"DataType": "System.Int32",
"FlowDirection": "Output",
"Protocol": "EventPassing",
"Properties": [
{
"Name": "PortMatchId",
"Value": "RunningStateType"
}
]
}
]
}

Linking ports and data nodes within a processing network is described by Links.

NameDescriptionData Type
NameName of the linkSystem.String
TypeNameHumanOS class name of the link.System.Type
Node1RefNameReference to an output portSystem.String
Node2RefNameReference to an input portSystem.String
DataTypeDefines the data type of the linkSystem.String

Example of internal linking two processors:

{
"Id": "77B6AACB-B306-4E50-901A-9E12CC706E1D",
"Name": "HumanOS.PeSeL.Correlations.DataProcessors",
"Processors": [
{
"Id": "35C93A18-F43A-4866-AFEC-1F25A36B8D6E",
"Name": "Processing1",
"Type": "SituationProcessingNode",
"AsynchProcessing": false,
"InitialData": [
"InValue < 0 => (-1)",
"InValue > 0 => 1",
"=> 0"
],
"Ports": [
{
"Name": "InValue",
"DataType": "System.Int32",
"FlowDirection": "Input",
"Protocol": "EventPassing"
},
{
"Name": "InverterOut",
"DataType": "System.Int32",
"FlowDirection": "Output",
"Protocol": "EventPassing"
}
]
},
{
"Id": "CFEF5DC4-CF1D-44AF-82C3-BD3289C1815F",
"Name": "Processing2",
"Type": "SituationProcessingNode",
"AsynchProcessing": false,
"InitialData": [
" => AmplifierIn*1.1"
],
"Ports": [
{
"Name": "AmplifierIn",
"DataType": "System.Int32",
"FlowDirection": "Input",
"Protocol": "EventPassing"
},
{
"Name": "OutValue",
"DataType": "System.Double",
"FlowDirection": "Output",
"Protocol": "EventPassing"
}
]
}
],
"Links": [
{
"Name": "Connection1",
"Node1RefName": "InverterOut",
"Node2RefName": "AmplifierIn",
"DataType": "System.Int32"
}
]
}

Situation Processing Node

The situation processing node can process complex situations out of several data access points and messages.

Initial Data - Correlation Predicates

The initial data node contains all correlations of the situation processing. Predicates are processed from top to bottom. The processing stops on the first predicate whose condition returns true.

Predicates take the form: <condition> => <result>

The => can be read as "leads-to".

Variable names can be used within the condition and result terms. The variable name corresponds to the name of the input ports.

Else-Statement

Your list of predicates should end with an "else"-statement, otherwise processors might miss some situations.

The else-statement is a simple "true", or leave the condition empty:

true => 100

or

 => 100

Logical Expressions

Several variables can be combined in logical expressions. Possible expressions are:

  • and or &&
  • or or ||

HumanOS uses the standard operator precedence that is and goes before or. It is good practice to use brackets to indicate the your precedence.

{
"Id": "35C93A18-F43A-4866-AFEC-1F25A36B8D6E",
"Name": "MachineStateProcessor",
"Type": "SituationProcessingNode",
"InitialData": [
"AvailableState <= 0 => 0",
"ProgramState == 5 => 1",
"OperationMode != 4 => 100",
"OperationMode == 4 and ProgramState == 1 => 200",
"OperationMode == 4 and ProgramState == 2 => 300",
"OperationMode == 4 and ProgramState == 4 => 301",
"=> 302"
]
}

It is also possible to use regular C# expressions.

Example

{
"Id": "35C93A18-F43A-4866-AFEC-1F25A36B8D6E",
"Name": "MachineStateProcessor",
"Type": "SituationProcessingNode",
"InitialData": [
"AvailableState <= 0 => 0",
"ProgramState == 5 => 1",
"OperationMode != 4 => 100",
"OperationMode == 4 and ProgramName.Contains(\"warmlauf\", StringComparison.OrdinalIgnoreCase) => 200",
"=> 0"
]
}

Generating more than one Output Value

In general, the situation processor is used to correlate several input values to on output value. But, it is possible to generate multiple output values at the same time.

For instance, if some text should describe the generated value, it is useful to generate the value and description at the same time to prevent inconsistency at the end of a processing network.

See also Inconsistent Data Correlations.

Example

Following example is used to generate the machine state and is corresponding machine state name. The two output ports MachineState and MachineStateName are written at the same time, if a predicate is triggered and executed.

{
"Id": "35C93A18-F43A-4866-AFEC-1F25A36B8D6E",
"Name": "MachineStateProcessor",
"Type": "SituationProcessingNode",
"InitialData": [
"AvailableState <= 0 => MachineState=0; MachineStateName=\"POWER OFF\"",
"ProgramState == 5 => MachineState=1; MachineStateName=\"STOP\"",
"OperationMode != 4 => MachineState=100; MachineStateName=\"PRODUCTION\"",
"OperationMode == 4 and ProgramName.Contains(\"warmlauf\", StringComparison.OrdinalIgnoreCase) => MachineState=200; MachineStateName=\"SETUP\"",
"=> MachineState=0; MachineStateName=\"UNKNOWN\""
]
}

C#-Script Processing Node

The extended version of the situation processing node allows more flexible data correlation. Instead of predicates, a C# script is used to describe the processing algorithm.

By default, the script files are placed in the folder $(ConfigPath)\Scripts\Processing\.

In case the script file belongs to a device.json file, the script files are placed in the folder $(ConfigPath)\$(plugin-name)\.

Initial Data

The script file is declared in the initial data section.

Example

{
"Id": "35C93A18-F43A-4866-AFEC-1F25A36B8D6E",
"Name": "MachineStateProcessor",
"Type": "CSharpScriptProcessingNode",
"AsynchProcessing": false,
"InitialData": [
"MyScriptFile.cs"
]
}

Message Handling

The situation processing also allows to access alarm messages. At least one input port must be linked to the alarm event pool to get messages from hardware devices.

Following methods can be used to handle messages:

MethodDescriptionParameters
hasAlarmMessageChecks if an alarm message is pending. Example: bool hasAlarmMessage(string strPortName, string strConditionName)strPortName: Name of the message port; strConditionName: Name of the condition e.g. Alarm 100
getAlarmMessageGets the alarm message if available (otherwise null). Example: TAlarmItem getAlarmMessage(string strPortName, string strConditionName)strPortName: Name of the message port; strConditionName: Name of the condition e.g. Alarm 100
getAllAlarmMessagesGets all pending alarm message. Example: List<TAlarmItem> getAllAlarmMessages(string strPortName)strPortName: Name of the message port

The TAlarmItem contains several fields that could be used for processing. See TAlarmItem reference.

Example

{
"Id": "{94CC989E-B9FE-49B2-83CD-C874B05DB23D}",
"Name": "AlarmingProcessor",
"Type": "CSharpScriptProcessingNode",
"AsynchProcessing": false,
"Properties": [
{
"Name": "DelayTime",
"Value": 500,
"DataType": "System.Int32"
}
],
"InitialData": [
"TAlarmProcessor.cs"
],
"Ports": [
{
"Name": "Alarms",
"Public": true,
"DataType": "HumanOS.Kernel.DataModel.TAbstractEventItem, HumanOS.Kernel.Base",
"FlowDirection": "Input",
"Protocol": "Messaging",
"Properties": [
{
"Name": "PortMatchId",
"Value": "Port_Alarms"
}
]
},
{
"Name": "NumberOfActiveAlarms",
"Public": true,
"DataType": "System.Int32",
"FlowDirection": "Output",
"Protocol": "EventPassing",
"Properties": [
{
"Name": "PortMatchId",
"Value": "Port_NumberOfActiveAlarms"
}
]
}
]
}

Example of C# script

using HumanOS.Kernel.DataModel;
using HumanOS.Kernel.Processing;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace HumanOS.IoT.Gateway.Config.Scripts.Processing
{
/// <summary>
/// Implements the mt connect alarm processor
/// </summary>
internal class TAlarmProcessor : TAbstractProcessingScriptObject
{
/// <see cref="TAbstractProcessingScriptObject"/>
public override void process(IProcessingNode Processor)
{
// get all alarm messages from ae pool
List<TAlarmItem> lstAlarmItems = Processor.getAllAlarmMessages("Alarms");

// set number of active alarms
Processor.setProperty<int>("NumberOfActiveAlarms", lstAlarmItems.Count);
}
}
}

Proxy Processing Nodes

A proxy processing node encapsulates an external processor. Typically, the external processor is loaded as a PeMiL-plugin.

The property ProcessorType specifies the processor class provided by an external plugin.

PropertyDescriptionData Type
ProcessorTypeType name of the processor class to load from PeMiL plugin.System.String

Example of a TensorFlow processor:

{
"Id": "35C93A18-F43A-4866-AFEC-1F25A36B8D6E",
"Name": "TensorFlow Processing",
"Type": "EventProcessingProxyNode",
"AsynchProcessing": false,
"InitialData": [],
"Properties": [
{
"Name": "ProcessorType",
"Value": "HumanOS.PeMiL.Processors.TensorFlow.TTensorFlowProcessor, HumanOS.PeMiL.Processors.TensorFlow"
}
]
}

Data Aggregation

Data aggregation processor can be used to create a complex data object (entity) out of single data nodes (values). Therefore, a processor collects different data in its inputs and aggregates them to a new complex object.

The data aggregation processor requires an output port of type HumanOS.Kernel.DataModel.Entity.TGenericEntity, HumanOS.Kernel.Base.

NOTE

The generic entity data can be processed by different pervasive service plugins, e.g. OPC-UA server or different data logger plugins.

Example

{
"Id": "dcbece37-8fcd-46cc-8e11-a5ac76b67fad",
"Name": "DataAggregatorProcessor",
"InitialData": [],
"Type": "DataAggregator",
"Ports": [
{
"Name": "Value1",
"DataType": "System.Int32",
"Public": true,
"Properties": [
{
"Name": "PortMatchId",
"DataType": "System.String",
"Value": "Value1Type"
}
]
},
{
"Name": "Value2",
"DataType": "System.Double",
"Public": true,
"Properties": [
{
"Name": "PortMatchId",
"DataType": "System.String",
"Value": "Value2Type"
}
]
},
{
"Name": "OutputPort",
"DataType": "HumanOS.Kernel.DataModel.Entity.TGenericEntity, HumanOS.Kernel.Base",
"FlowDirection": "Output",
"Public": true,
"Properties": [
{
"Name": "PortMatchId",
"DataType": "System.String",
"Value": "OutType"
}
]
}
]
}

Trouble Shooting

Inconsistent Data Correlations

In larger and interconnected processing networks, it can happen that same signals arrive earlier than others. This phenomena occurs due to async processing of the network and non-deterministic thread scheduling of the hosting operating system.

There are different ways to overcome such a behavior:

  1. Try to process information that belongs together in one processor. Here, you can use multiple outputs or the datatype TGenericEntity as a structure to combine all relevant information in one

  2. Use a trigger to collect all relevant information first and then to process them once the trigger is set.