SensorUserFunction

A sensor defined by a user function. The sensor is intended to collect sensor values of a list of given sensors and recombine the output into a new value for output or control purposes. It is also possible to use this sensor without any dependence on other sensors in order to generate output for, e.g., any quantities in mbs or solvers.

Parameters

The parameters of the item; in a dictionary, its type is ‘UserFunction’:

name

type

size

default

description

name

String

‘’

sensor’s unique name

sensorNumbers

ArraySensorIndex

[]

(symbol: \(\mathbf{n}_s = [s_0,\,\ldots,\,s_n]\tp\)) optional list of \(n\) sensor numbers for use in user function

factors

Vector

[]

(symbol: \(\mathbf{f}_s = [f_0,\,\ldots,\,f_m]\tp\)) optional list of \(m\) factors which can be used, e.g., for weighting sensor values

writeToFile

Bool

True

True: write sensor output to file; flag is ignored (interpreted as False), if fileName=’’

fileName

String

‘’

directory and file name for sensor file output; empty: no file is written; a relative name is placed in exudyn.config.outputDirectory if that is set; the directory is created if it does not exist

sensorUserFunction

SensorUserFunctionSensorUserFunction

0

A Python function which defines the time-dependent user function, which usually evaluates one or several sensors and computes a new sensor value, see example

storeInternal

Bool

False

true: store sensor data in memory (faster, but may consume large amounts of memory); false: internal storage not available

visualization

VSensorUserFunction

parameters for visualization of item

Visualization parameters

VSensorUserFunction has no parameters.

Drawing

The item draws nothing.

Detailed description

The sensor collects data via a user function, which completely describes the output itself. Note that the sensorNumbers and factors need to be consistent. The return value of the user function is a list of float numbers which cast to a std::vector in pybind. This list can have arbitrary dimension, but should be kept constant during simulation.

Userfunction: sensorUserFunction(mbs, t, sensorNumbers, factors, configuration) A user function, which computes a sensor output from other sensor outputs (or from generic time dependent functions). The configuration in general will be the exudyn.ConfigurationType.Current, but others could be used as well except for SensorMarker.

The user function arguments are as follows:

arguments / return

type or size

description

mbs

MainSystem

provides MainSystem mbs to which object belongs

t

Real

current time in mbs

sensorNumbers

Array \(\in \Ncal^n\)

list of sensor numbers

factors

Vector \(\in \Rcal^n\)

list of factors that can be freely used for the user function

configuration

ConfigurationType

usually the exudyn.ConfigurationType.Current, but could also be different in user defined functions.

return value

Vector \(\in \Rcal^{n_r}\)

returns list or numpy array of sensor output values; size \(n_r\) is implicitly defined by the returned list and may not be changed during simulation.

Example:

import exudyn as exu
from exudyn.itemInterface import *
from math import pi, atan2
SC = exu.SystemContainer()
mbs = SC.AddSystem()
node = mbs.AddNode(NodePoint(referenceCoordinates = [1,1,0],
                             initialCoordinates=[0,0,0],
                             initialVelocities=[0,-1,0]))
mbs.AddObject(MassPoint(nodeNumber = node, mass=1))

sNode = mbs.AddSensor(SensorNode(nodeNumber=node, fileName='solution/sensorTest.txt',
                      outputVariableType=exu.OutputVariableType.Position))

#user function for sensor, convert position into angle:
def UFsensor(mbs, t, sensorNumbers, factors, configuration):
    val = mbs.GetSensorValues(sensorNumbers[0]) #x,y,z
    phi = atan2(val[1],val[0]) #compute angle from x,y: atan2(y,x)
    return [factors[0]*phi] #return angle in degree

sUser = mbs.AddSensor(SensorUserFunction(sensorNumbers=[sNode], factors=[180/pi],
                                 fileName='solution/sensorTest2.txt',
                                 sensorUserFunction=UFsensor))

#assemble and solve system for default parameters
mbs.Assemble()
mbs.SolveDynamic()

if False:
    from exudyn.plot import PlotSensor
    PlotSensor(mbs, [sNode, sNode, sUser], [0, 1, 0])

Mini example

#a value computed from other sensors: the distance between two mass points
nA = mbs.AddNode(NodePoint(referenceCoordinates=[0,0,0], initialVelocities=[-1,0,0]))
nB = mbs.AddNode(NodePoint(referenceCoordinates=[1,0,0], initialVelocities=[0,1,0]))
mbs.AddObject(ObjectMassPoint(nodeNumber=nA, mass=1))
mbs.AddObject(ObjectMassPoint(nodeNumber=nB, mass=1))
sA = mbs.AddSensor(SensorNode(nodeNumber=nA, outputVariableType=exu.OutputVariableType.Position, writeToFile=False))
sB = mbs.AddSensor(SensorNode(nodeNumber=nB, outputVariableType=exu.OutputVariableType.Position, writeToFile=False))
def UFdistance(mbs, t, sensorNumbers, factors, configuration):
    pA = mbs.GetSensorValues(sensorNumbers[0], configuration)
    pB = mbs.GetSensorValues(sensorNumbers[1], configuration)
    return [np.linalg.norm(np.array(pB) - np.array(pA))]
sDistance = mbs.AddSensor(SensorUserFunction(sensorNumbers=[sA, sB], sensorUserFunction=UFdistance,
                                             storeInternal=True, writeToFile=False))

mbs.Assemble()
mbs.SolveDynamic()

#at t=1: pA = [-1,0,0], pB = [1,1,0]
exu.sys['testResult'] = mbs.GetSensorValues(sDistance) #sqrt(5), a scalar for one value

Examples (Ex) and TestModels (TM) that show this item, with weblink to github: sensorUserFunctionTest.py (TM)