CPG Network basics

CPG Network basics — How to construct and use a network

Principles and Concepts

The CPG network library is a general dynamical systems simulator. Although as the name suggests it focusses on implementing Central Pattern Generators, it can basicly be used to model any kind of dynamical system.

The library takes an Object Oriented approach into modelling a dynamical system. Such a system then consists of a number of state containers, which each contain any number of state variables. In programming terms these are simply objects with a certain set of properties assigned to them. Each property furthermore is a mathematical expression which can reference other properties from the object in which it is defined. For instance, you could have a property a = 1 and b = 2 * a.

Apart from state containers, you can transmit information from one state container to another, with a certain transfer function, using links. A link simply connects two containers together and defines a set of actions. An action consists of a target property in the object to which it links, and a mathematical expression which transfers a value to that target property at each simulation step of the system. This transfer function can use any properties from the object it originates from.

Now, this is not strictly a dynamical system yet, since it only is able to set a property to a specific value at each time step. However, any property can be marked to be integrated during simulation. The result of this is that when such property is targeted by a link, the resulting value will be multiplied by the timestep and added to the current value of that property. Furthermore, multiple links can act on the same property, resulting in all their respective transmitted values being added to the property.

To illustrate this with a simple example, take the following first order non-linear dynamical system:

To model this simple system using the library we need one state container with an x, g_x and X property. The initial values of these properties should be chosen such that the system actually does something interesting, for example respective values 0.1, 1 and 1 could be taken. Furthermore we mark x to be integrated.

CpgNetwork *network = cpg_network_new ();
CpgObject *object = CPG_OBJECT (cpg_state_new ("state"));

cpg_object_add_property (object, "x", "0.1", TRUE);
cpg_object_add_property (object, "g_x", "1", FALSE);
cpg_object_add_property (object, "X", "1", FALSE);

cpg_network_add_object (network, object);

As defined above, the network will not do anything when being simulated since we only defined some states. To model the equation as specified above, we need to add a link to the system transfering information. Since nothing prevents us from adding a link from and to the same object, we do just that. The link should have one action, targetting the x property and transferring information as defined in the equation:

/* Continue with example above */
CpgLink *link = cpg_link_new ("integration", object, object);

cpg_link_add_action (link, 
                     cpg_object_get_property (object, "x"),
                     "g_x * (X * X - x * x) * x");

cpg_network_add_object (network, CPG_OBJECT (link));

Now the network is complete it can be simulated using cpg_network_run.

Note

Links are just another type of object, as such they can also have properties (although these can not be targed by links themselves). You can use these properties in the link actions. This can be useful if you need to precalculate some value and use it in several link actions in the same link.

Construction

There are basicly two ways to create a new network. The first is simply by using cpg_network_new to create an empty network. After the network is created, you can start building it by adding states and links to the network using cpg_network_add_object (as done above). Although you might be able to construct fairly simple networks like this quite easily, at some point your networks will become bigger and more complex. To this end, you can write the network using the CPG Network XML specification. Once written, you can construct a network from such a file using cpg_network_new_from_file. To illustrate, the example system defined above can be written in XML format as follows:

<cpg>
  <network>
    <state id="state">
      <property name="x" integrated="yes">0.1</property>
      <property name="g_x">1</property>
      <property name="X">1</property>
    </state>
    <link id="integration" from="state" to="state">
      <action target="x">g_x * (X * X - x * x) * x</action>
    </link>
  </network>
</cpg>

After a network has been loaded from the XML file, you can manipulate in the same way as if it was constructed by hand. This means you can modify some properties of objects in the network or add and remove states and links as needed.

Manipulating a Network

Every aspect of the network can be manipulated using the network API. There are a few methods in particular that are used to retrieve objects and set or get certain properties of those objects.

To get a specific object from the network, you can use cpg_network_get_object using the objects unique id. To get a list of all the states in the network, use cpg_network_get_states and for a list of links use cpg_network_get_links.

Each object in the network basicly consists of a set of properties which contain mathematical expressions. To get a specific property from an object you can use cpg_object_get_property. Similar to getting all states from the network, you can use cpg_object_get_properties to get a list of all properties on an object. The functions cpg_object_add_property and cpg_object_remove_property can be used to respectively add and remove properties from the object.

To get the current value of a CpgProperty you can use cpg_property_get_value. Similarly, use cpg_property_set_value_expression to set the value of a property to a mathematical expression.

Note

Make sure that your network has been compiled (cpg_network_compile) before accessing the property value with cpg_property_get_value.

Mathematical expressions

The mathematical expressions you can use are very similar to the mathematical expressions in many C based programming languages. It also uses the same presedence and priorities of operators as in C. The standard arithmetic operators are supported: +, -, *, /, %, unary -, unary +. Most logical operators are also supported: &&, ||, <, > <=, >=, ==, !. Additionally, you can use the ternary operator for small conditional statements (e.g. a > b ? c : d). One additional operator which does not exist in C, but is supported by the network is the power operator: **.

A number of functions is also implemented: cos, sin, tan, acos, asin, atan, atan2, sqrt, invsqrt, min, max, exp, floor, ceil, round, abs, pow, rand, ln, log, hypot, exp2, sinh, cosh, tanh, lerp, sqsum. Here ln and log both refer to the natural logarithm. rand generate a random number between 0 and 1. You can use 2 arguments to rand to give a range in which the random number has to be generated. Beside functions, you can also use the constants pi and e.

You can not only use operators, functions and constants in mathematical expressions, but also refer to any other property within the context of execution. For all objects, this context includes the global properties and properties of the object in which the expression is defined. Links have two additional context objects, namely the from and to objects. The properties from the from object are implicitly available in the context. A special syntax allows you to access properties from the to object: to.x (you can do the same for from if you like specifying those explicitly). The priority from high to low is: object, globals for objects, and object, from, globals for links.

Using global variables

One thing that might be useful to know is that you can define global accessible variables within the network. Two special globals are already defined by default, they signify the network simulation time (t) and the current simulation step size (dt). The time variable in particular can be useful when experimenting with perturbing some values in the network using simple conditional statements equivalent to the ternary operator many programming languages (t < 2 ? 1 : 0).

In network terminology, global variables are defined within a special CpgObject which you can access as any other object in the network (thus using cpg_object_add_property to add new global properties). Use cpg_network_get_globals to get the networks' globals object.