Using DiaBloS: Some Practical Examples#

This package provides some examples, as a way to demonstrate some of the capabilities that this program has. These examples are contained in ‘.dat’ files, located in the ‘Examples’ folder, and are executed as any file saved by the user.

Sine integration#

Description:

This example shows the process for integrating a sinusoidal signal, using the RK45 method and then comparing the result with the mathematically correct curve.

Demonstration:

The math expression for the process is the following

\[y(t) = \int_0^t A\,\sin(\omega\,t + \phi_0) dt\]

calculating the integral rigorously, we arrive at the following expression:

\[y(t) = 1 + A\,\cos(\omega\,t + \phi_0)\]

rewriting \(\cos(\theta)\) as \(\sin(\theta + \pi/2)\):

\[y(t) = 1 + A\,\sin(\omega\,t + \phi_0 + \pi/2)\]

if \(A = 1\), \(\omega = 1\) y \(\phi_0 = 0\), the resulting expression for \(y(t)\) is:

\[y(t) = 1 + \sin(t + pi/2)\]

This is exemplified as the addition of a step of amplitude 1 and a sinusoidal starting at \(\phi_0 = \pi/2\) at time \(t_0 = 0\). Then an example comparing the integration process and the exact curve can be done.

Graph composition:
Graph 1:
  1. A Step up block with amplitude \(1\) and no delay.

  2. A Sine block with an initial angle of \(\pi/4\) to form \(\cos(t)\).

  3. An Adder block to form \(y(t)\) defined above with the previous two blocks.

  4. A Scope block to observe the result of the operation.

Graph 2:
  1. A Sine block to form \(\sin(t)\), the base function that will be integrated.

  2. An Integrator block using the RK45 method and initial condition set in zero.

  3. A Scope block to observe the result of the operation.

Vectorial integration#

Description:

This example shows a integration with the RK45 method, but the inputs and outputs are vectors instead of scalar values.

Demonstration:

The Step block has support for vector outputs of the type:

1. Vectorial: [a, b, c, d].
2. Matrix: [[a, b], [c, d]]
3. 3D Matrix: [[[a, b], [c, d]], [[e, f], [g, h]]]

A graph is formed representing a simple feedback system, consisting of an integrator connected in feedback. The input values are defined by two vector sources which are added together. This value is used for a feedback system represented by the following transfer function:

\[y(t) = e^{-t} \ast u(t) \leftrightarrow \frac{Y(s)}{U(s)} = \frac{1}{s+1}\]

It should be noted that for this case, the initial conditions of the Integrator block must be of the same dimensions as its input. Since for this case it will be a vector of two elements, the initial conditions must be defined as \([0.0, 0.0]\), if you want to start at zero for both.

Graph Composition:
  1. A Step up block with amplitude \([1.5, 2.0]\) delayed in \(5\) seconds.

  2. Another Step up block with amplitude \([1.0, 0.5]\) and no delay.

  3. An Adder block to add the outputs of both blocks.

  4. Another Adder block to subtract the output of the previous block with the output of the Integrator block.

  5. An Integrator block using the RK45 method to obtain the integration of the Adder’s output with initial conditions set in \([0.0, 0.0]\).

  6. A Scope block to observe the result of the operation.

Gaussian noise#

Description:

This example shows a vectorial output (2 signals) with added noise.

Demonstration:

The Noise block allows the creation of Gaussian noise for simulation effects. It only requires defining \(mu\) and \(sigma\) and then adding the result to the target signal.

The graph to be shown is a system where the Step block’s amplitude is \([5.0, -2.5]\), separates the vector into two independent signals, adding a Gaussian noise to each.

Graph Composition:
  1. A Step up block with amplitude \([5.0, -2.5]\) delayed in \(2.5\) seconds.

  2. A Demultiplexer block to split the vector from the Step block and treat each element as an independent signal.

  3. Two Noise blocks with \(\mu = 0\) and \(\sigma = 1\) to produce gaussian noise.

  4. Two Gain block with gain of \(0.5\) to attenuate the signal amplitude from the noise blocks.

  5. Two Adder blocks to add the noise ouput to each signal coming from the Demultiplexer.

  6. A Scope block to observe the result of the operation.

Signal products#

Description:

This example shows element-wise products between vectors and a scalar signal and a vector.

Demonstration:

The Sigproduct block is used to multiply the values of each iteration between different signals. Defining \(y_1\) and \(y_2\), as two output signals from two different blocks, the following signal multiplications can be observed:

  1. Scalar with scalar: If \(y_1 = a\) and \(y_2 = b\) then \(y_3 = a\, b\).

  2. Scalar with vector: If \(y_1 = a\) and \(y_2 = [b, c]\) then \(y_3 = [a\, b, a\, c]\).

  3. Vector with vector: If \(y_1 = [a, b]\) and \(y_2 = [c, d]\) then \(y_3 = [a, c, b, b, d]\).

An example graph is shown where the multiplication between three different sources is observed, based on the three types of multiplication described above.

Graph Composition:
  1. A Step up block with amplitude \(5.0\) delayed in \(1\) second.

  2. Another Step up block with amplitude \([2.0, -3.0]\) with no delay.

  3. A Step down block with amplitude \([0.75, 1.5]\) delayed in \(2\) seconds.

  4. A Multiplexer block to append the Step blocks’ outputs in one simple vector.

  5. A Terminator block to finish the branch of the graph that will not be plotted.

  6. Two Sigproduct blocks, one to multiply the output of the first and second Step blocks, and another to multiply the output of the second and third Step blocks.

  7. Two Scope blocks to observe the results of the operations.

Export data#

Description:

This example shows how signal data can be exported in ‘.npz’ format.

Demonstration:

The Export block is used to save data of signals created during the simulation. It is enough to add this block and define the labels within the settings of this block.

In particular, the function for exporting data consists of two parts:

  1. Data acquisition: During the simulation, the block will accumulate data in ordered vectors, each associated with a label. associated to a label. If labels have not been previously defined, or if they are not enough to cover all the vectors to be created, the block will vectors to be created, the system adds default names to complete the list. A matrix is then created a matrix is then created that will append the values added by each simulation loop.

  2. Data conversion: At the end of the simulation, all the vectors of the Export blocks are taken (if there are more than one), and all the data is assembled. more than one), and a larger matrix is assembled, which will be exported as .npz by means of the numpy library.

After completing a simulation process, a .npz file will be created and found inside the ‘saves’ folder, with the same name as the savefile (by default ‘data.npz’). Note that this example only exports the files. Being able to read them can be done with Python, Excel or similar.

Graph Composition:
  1. A Step up block with amplitude \(1\) and no delay.

  2. A Sine block with an initial angle of \(\pi/4\) to form \(\cos(t)\).

  3. An Adder block to form \(1+\cos(t)\) with the previous two blocks.

  4. A Multiplexer block to produce a 2D vector with the Step block’s output as first element and \(1+\cos(t)\) (Adder block’s output) as second element.

  5. An Export block to save the data from the Multiplexer block and then export it as a file in .npz format.

External source#

Description:

This example shows an external function implemented as a source block.

Demonstration:

The Block block associates user-defined functions to give more options for graph simulation.

The only parameter needed to modify is the function name (and .py file) located in the usermodels folder. After loading this, the block acquires the data defined in the file to change, number of inputs, outputs, block type and color.

For this case, it is important to define the block inputs as \(0\) and the block type as \(0\) (source).

Details on how to create such functions can be found in Usermodel functions.

Graph Composition:
  1. An External block linked to the external usermodel function my_function_src.

  2. Two Scope blocks to observe the outputs of the External block.

External Z-process#

Description:

This example shows an external function implemented as a Z-process block.

Demonstration:

The Block block associates user-defined functions to give more options for graph simulation.

The only parameter needed to modify is the function name (and .py file) located in the usermodels folder. After loading this, the block acquires the data defined in the file to change, number of inputs, outputs, block type and color.

For this case, it is important to define the block type as \(2\) (z-process).

Details on how to create such functions can be found in Usermodel functions.

Graph Composition:
  1. A Step up block with amplitude \(1\) and no delay.

  2. An External block linked to the external usermodel function my_function_pcs.

  3. A Scope block to observe the result of the operation.

External integrator (N-process)#

Description:

This example shows an external function implemented as a N-process block. In this case, an integrator using the same RK45 method already implemented in the Integrator block.

The Block block associates user-defined functions to give more options for graph simulation.

The only parameter needed to modify is the function name (and .py file) located in the usermodels folder. After loading this, the block acquires the data defined in the file to change, number of inputs, outputs, block type and color.

For this case, it is important to define the block type as \(1\) (n-process).

Details on how to create such functions can be found in Usermodel functions, details on how the RK45 integration method works, see Graph simulation algorithm.

Graph Composition:
  1. A Step up block with amplitude \(1\) and no delay.

  2. An External block linked to the external usermodel function external_rk45.

  3. A Scope block to observe the result of the operation.

External derivator (Z-process)#

Description:

This example shows an external function implemented as a Z-process block. In this case a variable step-size derivator (direct feedthrough function).

Demonstration:

The Block block associates user-defined functions to give more options for graph simulation.

The only parameter needed to modify is the function name (and .py file) located in the usermodels folder. After loading this, the block acquires the data defined in the file to change, number of inputs, outputs, block type and color.

For this case, it is important to define the block type as \(2\) (z-process).

Details on how to create such functions can be found in Usermodel functions.

Graph Composition:
  1. A Ramp block with slope \(1\) and no delay.

  2. An External block linked to the external usermodel function external_derivative.

  3. A Scope block to observe the result of the operation.

Convergent ODE system#

Description:

This example shows the same convergent ODE system implemented in three different ways.

Demonstration:

A particular ordinary differential equation is used as an example:

\[\ddot{y} + 0.4\,\dot{y} + y = u\]

if \(x_1 = y\) and \(x_2 = \dot{y}\) this ODE can be represented in vector form as:

\[\begin{split}X' &= f(X,U)\\ \begin{bmatrix} \dot{x}_1 \\ \dot{x}_2 \end{bmatrix} &= \begin{bmatrix} x_2 \\ -x_1 -0.4\, x_2 + u \end{bmatrix}\end{split}\]

and in the same time, it can be converted to a matrix system of the type \(X'= A\,X + B\,U\).

\[\begin{split}\begin{bmatrix} \dot{x}_1 \\ \dot{x}_2 \end{bmatrix} &= \begin{bmatrix} 0 & 1 \\ -1 & -0.4 \end{bmatrix} \begin{bmatrix} x_1 \\ x_2 \end{bmatrix} + \begin{bmatrix} 0 \\ 1 \end{bmatrix} u\end{split}\]

So three instances of this problem are created to simulate:

  1. Using an external function, where value \(U\) and vector \(X=[x_1, x_2]\) are received, to deliver \(\dot{X} = f(X,U)\).

  2. Using gain and adder blocks to form the matrix notation (\(X'= A,X + B,U\)) before integrating it.

  3. Using the non-vector system definition, first by calculating \(ddot{y}\), then integrate it to find \(dot{y}\) and then integrate once again to find \(y\).

Graph Composition:
Graph 1:
  1. A Step up block with amplitude \(1\) and no delay.

  2. An External block linked to the external user model function ode_system_conv.

  3. An Integrator block using the RK45 method to obtain the integration of the previous operation’s result.

  4. A Scope block to observe the output of the Integrator block.

  5. An Export block to save the data from the Integrator block and then export it as a file in .npz format.

Graph 2:
  1. A Step up block with amplitude \(1\) and no delay.

  2. A Gain block to multiply the output of the Step block with the vector \(B = [0.0, 1.0]\) producing \(BU\).

  3. A Gain block to multiply the output vector of the Integrator block with the matrix \(A = [[0.0, 1.0], [-1.0, -0.4]]\) producing \(AX\).

  4. An Adder block to add the output of both Gain blocks, producing \(AX+BU\).

  5. An Integrator block using the RK45 method to obtain \(X\) from the Adder block’s output, and initial conditions set in \([0.0, 0.0]\).

  6. A Scope block to observe the output of the Integrator block.

  7. An Export block to save the data from the Integrator block and then export it as a file in .npz format.

Graph 3:
  1. A Step up block with amplitude \(1\) and no delay.

  2. An Integrator block that integrates the value of the Adder block’s output to obtain \(x_2\).

  3. A Gain block to multiply \(x_2\) by \(-0.4\) and be used in the Adder block as future input.

  4. Another Integrator block that integrates \(x_2\) to get \(x_1\).

  5. Another Gain block used to multiply \(x_1\) by \(-1\) and be used in the Adder block as future input.

  6. An Adder block that adds the result of both Gain blocks and the Step block’s output to get \(\dot{x}_2\).

  7. A Multiplexer block to produce a vector with the output values of the Integrator blocks.

  8. A Scope block to observe the output of the Multiplexer block.

  9. An Export block to save the data from the Multiplexer block and then export it as a file in .npz format.

Critical ODE system#

Description:

This example shows the same critical ODE system implemented in three different ways, compared to the exact curve.

Demonstration:

A particular ordinary differential equation system is used vector form as an example:

\[\begin{split}X' &= f(X,U)\\ \begin{bmatrix} \dot{x}_1 \\ \dot{x}_2 \end{bmatrix} &= \begin{bmatrix} x_2 \\ -x_1 + u \end{bmatrix}\end{split}\]

and in the same time, it can be converted to a matrix system of the type \(X'= A\,X + B\,U\).

\[\begin{split}\begin{bmatrix} \dot{x}_1 \\ \dot{x}_2 \end{bmatrix} &= \begin{bmatrix} 0 & 1 \\ -1 & 0 \end{bmatrix} \begin{bmatrix} x_1 \\ x_2 \end{bmatrix} + \begin{bmatrix} 0 \\ 1 \end{bmatrix} u\end{split}\]

Knowing that \(A\) is the rotation matrix when \(\theta = 90^{\circ}\), and setting \(u = 1\), the equations can be rewritten as:

\[\begin{split}x_1 &= 1 - \cos(t) \\ x_2 &= \sin(t)\end{split}\]

So four instances of this problem are created to simulate:

  1. Using an external function as source, the exact value of the curves.

  2. Using an external function, where value \(U\) and vector \(X=[x_1, x_2]\) are received, to deliver \(\dot{X} = f(X,U)\).

  3. Using gain and adder blocks to form the matrix notation (\(X'= A,X + B,U\)) before integrating it.

  4. Using the non-vector system definition, first by calculating \(\dot{x}_2\), then integrate it to find \(x_2 = \dot{x}_1\) and then integrate once again to find \(x_1\).

Graph Composition:
Graph 1:
  1. An External block linked to the external user model function ode_exact_crit.

    1. A Scope block to observe the output of the External block.

Graph 2:
  1. A Step up block with amplitude \(1\) and no delay.

  2. An External block linked to the external user model function ode_system_crit.

  3. An Integrator block using the RK45 method to obtain the integration of the previous operation’s result.

  4. A Scope block to observe the output of the Integrator block.

  5. An Export block to save the data from the Integrator block and then export it as a file in .npz format.

Graph 3:
  1. A Step up block with amplitude \(1\) and no delay.

  2. A Gain block to multiply the output of the Step block with the vector \(B = [0.0, 1.0]\) producing \(BU\).

  3. A Gain block to multiply the output vector of the Integrator block with the matrix \(A = [[0.0, 1.0], [-1.0, -0.4]]\) producing \(AX\).

  4. An Adder block to add the output of both Gain blocks, producing \(AX+BU\).

  5. An Integrator block using the RK45 method to obtain \(X\) from the Adder block’s output, and initial conditions set in \([0.0, 0.0]\).

  6. A Scope block to observe the output of the Integrator block.

  7. An Export block to save the data from the Integrator block and then export it as a file in .npz format.

Graph 4:
  1. A Step up block with amplitude \(1\) and no delay.

  2. An Integrator block that integrates the value of the Adder block’s output to obtain \(x_2\).

  3. A Gain block to multiply \(x_2\) by \(-0.4\) and be used in the Adder block as future input.

  4. Another Integrator block that integrates \(x_2\) to get \(x_1\).

  5. Another Gain block used to multiply \(x_1\) by \(-1\) and be used in the Adder block as future input.

  6. An Adder block that adds the result of both Gain blocks and the Step block’s output to get \(\dot{x}_2\).

  7. A Multiplexer block to produce a vector with the output values of the Integrator blocks.

  8. A Scope block to observe the output of the Multiplexer block.

  9. An Export block to save the data from the Multiplexer block and then export it as a file in .npz format.

Watertank control#

Description:

This example shows the classic watertank control problem, trying to stabilize the height of the water using a PI control.

Demonstration:

According to Bernoulli’s principle the equation representing the height of water in a pond is:

\[\dot{h}(t) = \frac{1}{A_e}u - \frac{A_s}{A_e}\sqrt{2g\cdot h(t)}\]

where, \(A_e = 3.14[m]\) is the base area for the pond, \(A_s = 3.14\cdot 10^{-4}[m]\) is the drainage section area and \(g = 9.81[m/s^2]\) is the gravitational acceleration.

To control the system, a PI controller is used to adjust the height of the water, under a reference \(h_{ref}\):

\[u(t) = k_p\,(h_{ref} - h(t)) + k_i\,\int_0^t(h_{ref} - h(t)) dt\]

The controller requires only a couple of user-adjustable constants, which for this case are: \(k_p = 10.0\) and \(k_i = 55.5\).

However, since the PI controller also contains an integration stage, this formula can be rewritten, while retaining its validity in the system, as follows:

\[\dot{u} = -k_p\,\dot{h}(t) + k_i\,(h_{ref} - h(t))\]

Then, it is possible to rewrite the pond water height control model as a system of two equations:

\[\begin{split}\begin{bmatrix} \dot{h}(t) \\ \dot{u}(t) \end{bmatrix} = \begin{bmatrix} 1/A_e \cdot u(t) - A_s/A_e \cdot \sqrt{2g \cdot h(t)} \\ -k_p \cdot \dot{h}(t) + k_i \cdot (r - h(t)) \end{bmatrix}\end{split}\]

The system of equations is modeled as a block diagram using primarily basic blocks. In addition, two External blocks are added to perform functions that are not available by default, as a way to also show implementation examples for user-defined blocks; one to perform the square root operation, while the other to saturate the input value to prevent the water level from going beyond the physical limits that are set.

Also, the system of two equations is modeled as one External block connected to a Integrator block, to compare the performance of both methods.

The reference is taken as \(h_{ref1} = 1.25[m]\) during the first \(5.0\) seconds, and \(h_{ref2} = 0.5[m]\) in the following \(5.0[s]\), simulating in total \(10.0\) seconds at a sampling rate of \(0.01[s]\).

Graph composition:
Shared blocks:
  1. A Step up block with amplitude \(1.25\).

  2. Another Step up block with amplitude \(0.75\) delayed in \(5\) seconds.

  3. An Adder block to subtract the output of both blocks to have an amplitude of \(0.5\) after \(5\) seconds.

Graph 1:
  1. An Adder block to subtract the reference (from the previous Adder block) with the actual calculated value of \(h\).

  2. A Gain block to multiply the previously calculated subtraction by \(k_i\).

  3. A Gain block to multiply \(\dot{h}\) by \(k_p\).

  4. An Adder block to subtract the results of the previous two Gain blocks to obtain \(\dot{u}\).

  5. An Integrator block that integrates \(\dot{u}\) to obtain \(u\).

  6. A Gain block to multiply \(u\) by \(1/A_e\).

  7. An External block linked to the external usermodel function sqrt_pcs, to calculate the square root.

  8. An Gain block to multiply the result of sqrt_pcs with \(A_s/A_e\).

  9. An Adder block to subtract \(u/A_e\) and the result of the previous Gain to obtain \(\dot{h}\).

  10. An Integrator block that integrates \(\dot{h}\) to obtain \(h\).

  11. An External block linked to the external usermodel function sat_pcs, to restrict the value of \(h\) between \(0\) and \(2\).

  12. An Export block to save the data from \(h\) and then export it as a file in .npz format.

  13. A Scope block to observe the result of \(h\) in time.

Graph 2:
  1. An External block linked to the external usermodel function watertank_code.

  2. An Integrator block using the RK45 method to obtain the integration of the previous operation’s result.

  3. A Demux block to split the output vector in \(h\) and \(u\) to plot only the former element.

  4. A Terminator block to finish the branch of \(u\).

  5. An Export block to save the data from \(h\) and then export it as a file in .npz format.

  6. A Scope block to observe the result of \(h\) in time.