bdsim


Namebdsim JSON
Version 1.1.1 PyPI version JSON
download
home_page
SummarySimulate dynamic systems expressed in block diagram form using Python
upload_time2023-05-22 10:04:04
maintainer
docs_urlNone
author
requires_python>=3.7
licenseMIT License Copyright (c) 2020 Peter Corke Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
keywords python block diagram dynamic simulation
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            [![A Python Robotics Package](https://raw.githubusercontent.com/petercorke/robotics-toolbox-python/master/.github/svg/py_collection.min.svg)](https://github.com/petercorke/robotics-toolbox-python)
[![QUT Centre for Robotics Open Source](https://github.com/qcr/qcr.github.io/raw/master/misc/badge.svg)](https://qcr.github.io)

[![PyPI version](https://badge.fury.io/py/bdsim.svg)](https://badge.fury.io/py/bdsim)
![Python Version](https://img.shields.io/pypi/pyversions/bdsim.svg)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)

[![Build Status](https://github.com/petercorke/bdsim/workflows/build/badge.svg?branch=master)](https://github.com/petercorke/bdsim/actions?query=workflow%3Abuild)
[![Coverage](https://codecov.io/gh/petercorke/bdsim/branch/master/graph/badge.svg)](https://codecov.io/gh/petercorke/bdsim)
[![PyPI - Downloads](https://img.shields.io/pypi/dm/bdsim)](https://pypistats.org/packages/bdsim)
[![GitHub stars](https://img.shields.io/github/stars/petercorke/bdsim.svg?style=social&label=Star)](https://GitHub.com/petercorke/bdsim/stargazers/)

<table style="border:0px">
<tr style="border:0px">
<td style="border:0px">
<img src="https://github.com/petercorke/bdsim/raw/master/figs/BDSimLogo_NoBackgnd@2x.png" width="300"></td>
<td style="border:0px">
A Python block diagram simulation package</a>
<ul>
<li><a href="https://github.com/petercorke/bdsim">GitHub repository </a></li>
<li><a href="https://petercorke.github.io/bdsim">Documentation</a></li>
<li><a href="https://github.com/petercorke/bdsim/wiki">Wiki (examples and details)</a></li>
<li><a href="installation#">Installation</a></li>
<li>Dependencies: numpy, scipy, matplotlib, <a href="https://github.com/petercorke/ansitable">ansitable</a>, ffmpeg (if rendering animations as a movie)</li>
</ul>
</td>
</tr>
</table>

`bdsim` is Python 3 package that enables modelling and simulation of continuous-time, discrete-time or hybrid dynamic systems.  Systems are conceptualized in block diagram form, but represented in terms of Python objects. 

  <table>
  <tr>
  <td>
  <img width=450 src="https://github.com/petercorke/bdsim/raw/master/figs/bd1-sketch.png">
  </td>
  <td style="padding-left: 20px;">
  <pre style="font-size:10px;">
  # define the blocks
  demand = bd.STEP(T=1, name='demand')
  sum = bd.SUM('+-')
  gain = bd.GAIN(10)
  plant = bd.LTI_SISO(0.5, [2, 1])
  scope = bd.SCOPE(styles=['k', 'r--'])
  # connect the blocks
  bd.connect(demand, sum[0], scope[1])
  bd.connect(plant, sum[1])
  bd.connect(sum, gain)
  bd.connect(gain, plant)
  bd.connect(plant, scope[0])
  </pre>
  </td>
  </tr>
  </table>

Key features include:

* The block diagram can be created easily using Python code, rather than drawing boxes and wires. This enables use of your favourite IDE, standard version control tools and development workflows.
* Wires can communicate *any* Python type such as scalars, lists, dicts, NumPy arrays, objects, and functions. For robotics and vision applications using the [Spatial Maths Toolbox for Python](https://github.com/petercorke/spatialmath-python) wires could send values such as `SE3`, `UnitQuaternion` or `Twist3` objects.
* Over 70 blocks for linear, nonlinear functions, display blocks, as well as continuous- and discrete-time dynamics
  * Easy to add your own block, it's simply a class
  * Subsystems are supported, and a subsystem can be independently instantiated multiple times in a system.  Subsystems can also be nested.
  * Blocks from other toolboxes are automatically discovered and included. There are blocks for some functions in the  [Robotics Toolbox for Python](https://github.com/petercorke/robotics-toolbox-python) (such as arm, ground and aerial robots) and [Machine Vision Toolbox for Python](https://github.com/petercorke/machinevision-toolbox-python) (such as cameras). These are defined in the `blocks` folder of those toolboxes.
* The diagram can be executed in a headless configuration, particularly useful on an embedded computer like a RaspberryPi.
* A [python-based graphical editor](bdedit-the-graphical-editing-tool)
  * allows graphical creation of block diagrams
  * the diagram is stored in a human readable/editable JSON file with extension `.bd`
  * creates good-quality graphics for inclusion in publications
  * can launch `bdsim` to import and execute the model
  * automatically discovers all bsdim and toolbbox blocks and adds them to the block library menu
  * icons can be easily created using any image creation tool or a LaTeX expression 

# Getting started

We first sketch the dynamic system we want to simulate as a block diagram, for example this simple first-order system

![block diagram](https://github.com/petercorke/bdsim/raw/master/figs/bd1-sketch.png)

which we can express concisely with `bdsim` as (see [`bdsim/examples/eg1.py`](https://github.com/petercorke/bdsim/blob/master/examples/eg1.py))

```python
     1  #!/usr/bin/env python3
     2  import bdsim	
     4  sim = bdsim.BDSim()  # create simulator
     5  bd = sim.blockdiagram()  # create an empty block diagram
     6	
     7	# define the blocks
     8	demand = bd.STEP(T=1, name='demand')
     9	sum = bd.SUM('+-')
    10	gain = bd.GAIN(10)
    11	plant = bd.LTI_SISO(0.5, [2, 1], name='plant')
    12	scope = bd.SCOPE(styles=['k', 'r--'])
    13	
    14	# connect the blocks
    15	bd.connect(demand, sum[0], scope[1])
    17	bd.connect(sum, gain)
    18	bd.connect(gain, plant)
    19	bd.connect(plant, sum[1], scope[0])
    20	
    21	bd.compile()          # check the diagram
    22
    23	sim.report(bd)   # list the system
    24  out = sim.run(bd, 5)   # simulate for 5s
```
which is just 15 lines of executable code.

The red block annotations on the hand-drawn diagram are used as the names of the variables holding references to the block instance. The blocks can also have user-assigned names, see lines 8 and 11, which are used in diagnostics and as labels in plots.

After the blocks are created their input and output ports need to be connected. In `bdsim` all wires are point to point, a *one-to-many* connection is implemented by *many* wires,
for example
```
bd.connect(source, dest1, dest2, ...)
```
creates individual wires from `source` -> `dest1`, `source` -> `dest2` and so on.
Ports are designated using Python indexing notation, for example `block[2]` is port 2 (the third port) of `block`.  Whether it is an input or output port depends on context.
In the example above an index on the first argument refers to an output port, while on the second (or subsequent) arguments it refers to an input port.  If a block has only a single input or output port then no index is required, 0 is assumed.

A group of ports can be denoted using slice notation, for example 
```
bd.connect(source[2:5], dest[3:6)
```
will connect `source[2]` -> `dest[3]`, `source[3]` -> `dest[4]`, `source[4]` -> `dest[5]`.
The number of wires in each slice must be consistent.  You could even do a cross over by connecting `source[2:5]` to `dest[6:3:-1]`.

Line 21 assembles all the blocks and wires, instantiates subsystems, checks connectivity to create a flat wire list, and then builds the dataflow execution plan.

Line 23 generates a report, in tabular form, showing a summary of the block diagram:

```
┌────────┬──────────┬────────┬────────┬─────────────┐
│ block  │   type   │ inport │ source │ source type │
├────────┼──────────┼────────┼────────┼─────────────┤
│demand@ │ step     │        │        │             │
├────────┼──────────┼────────┼────────┼─────────────┤
│gain.0  │ gain     │ 0      │ sum.0  │ float64     │
├────────┼──────────┼────────┼────────┼─────────────┤
│plant   │ lti_siso │ 0      │ gain.0 │ float64     │
├────────┼──────────┼────────┼────────┼─────────────┤
│scope.0 │ scope    │ 0      │ plant  │ float64     │
│        │          │ 1      │ demand │ int         │
├────────┼──────────┼────────┼────────┼─────────────┤
│sum.0   │ sum      │ 0      │ demand │ int         │
│        │          │ 1      │ plant  │ float64     │
└────────┴──────────┴────────┴────────┴─────────────┘
```

Line 24 runs the simulation for 5 seconds 
using the default variable-step RK45 solver and saves output values at least every 0.05s.  It
causes the following output

```
>>> Start simulation: T = 5.00, dt = 0.050
  Continuous state variables: 1
     x0 =  [0.]
  Discrete state variables:   0

no graphics backend specified: Qt5Agg found, using instead of MacOSX

bdsim ◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉◉ 100.0% - 0s

<<< Simulation complete
  block diagram evaluations: 784
  block diagram exec time:   0.075 ms
  time steps:                123
  integration intervals:     2
```

This provides a summary of the number of states for the complete system: the number of continuous states, the number
of discrete states, and the initial value of the state vectors.

During execution a progress bar is updated and scope blocks pops up a graphical window

![bdsim output](https://github.com/petercorke/bdsim/raw/master/figs/Figure_1.png)

The simulation results are in a container object (`BDStruct`)
```
>>> out
t      = ndarray:float64 (123,)
x      = ndarray:float64 (123, 1)
xnames = ['plantx0'] (list)
ynames = [] (list)            
```
which contains an array of time values, an array of state values, and a list of the
names of the state variables.

By default the `.run()` method at line 24 blocks blocks the script until all figure
windows are closed (by pressing the operating system close button or typing "q"), or the
script is killed with SIGINT. If you want to continue the script with the figures still
active then the `hold=False` option should be set.

If we wished to also record additional outputs, we can add them as _watched_ signals
```
out = sim.run(bd, watch=[demand, sum])  # simulate for 5s
```
and now the output is
```
>>> out
t      = ndarray:float64 (123,)
x      = ndarray:float64 (123, 1)
xnames = ['plantx0'] (list)
y0     = ndarray:float64 (123,)
y1     = ndarray:int64 (123,)
ynames = ['plant[0]', 'demand[0]'] (list)
```
where

- `t` the time vector: ndarray, shape=(M,)
- `x` is the state vector: ndarray, shape=(M,N), one row per timestep
- `xnames` is a list of the names of the states corresponding to columns of `x`, eg. "plant.x0"

The `watch` argument is a list of outputs to log, in this case `plant` defaults
to output port 0.  This information is saved in additional variables `y0`, `y1`
etc.  `ynames` is a list of the names of the watched variables.

An alternative system report, created by `sim.report(bd, type="lists")` is more detailed
```
Blocks::

┌───┬─────────┬─────┬──────┬────────┬─────────┬───────┐
│id │    name │ nin │ nout │ nstate │ ndstate │ type  │
├───┼─────────┼─────┼──────┼────────┼─────────┼───────┤
│ 0 │  demand │   0 │    1 │      0 │       0 │ step  │
│ 1 │   sum.0 │   2 │    1 │      0 │       0 │ sum   │
│ 2 │  gain.0 │   1 │    1 │      0 │       0 │ gain  │
│ 3 │   plant │   1 │    1 │      1 │       0 │ LTI   │
│ 4 │ scope.0 │   2 │    0 │      0 │       0 │ scope │
└───┴─────────┴─────┴──────┴────────┴─────────┴───────┘

Wires::

┌───┬──────┬──────┬──────────────────────────┬─────────┐
│id │ from │  to  │       description        │  type   │
├───┼──────┼──────┼──────────────────────────┼─────────┤
│ 0 │ 0[0] │ 1[0] │ demand[0] --> sum.0[0]   │ int     │
│ 1 │ 0[0] │ 4[1] │ demand[0] --> scope.0[1] │ int     │
│ 2 │ 3[0] │ 1[1] │ plant[0] --> sum.0[1]    │ float64 │
│ 3 │ 1[0] │ 2[0] │ sum.0[0] --> gain.0[0]   │ float64 │
│ 4 │ 2[0] │ 3[0] │ gain.0[0] --> plant[0]   │ float64 │
│ 5 │ 3[0] │ 4[0] │ plant[0] --> scope.0[0]  │ float64 │
└───┴──────┴──────┴──────────────────────────┴─────────┘
```
In the first table we can see key information about each block, its `id` (used internally), name, the number of input and output ports, the number of
continuous- and discrete-time states, and the type which is the block class.  Note that the name is auto-generated based on the type, except if it has
been set explicitly as for the blocks `demand` and `plant`.

The second table shows all wires in point-to-point form, showing the start and end block and port (the block is represented here by its `id`) and the type of the object sent along the wire.

To save figures we need to make two modifications, changing line 4 to
```
     4  sim = bdsim.BDSim(hold=False)  # create simulator
```
which prevents `.run()` from blocking and then deleting all the figures.
Then, after the `.run()` we add 
```
     25 scope.savefig()  # save scope figure
```
If the filename is not given it defaults to the block name, in this case `scope.0.pdf`.


The output can be pickled and written to a file

```[shell]
examples/eg1.py -o
python -mpickle bd.out
t      = ndarray:float64 (123,)
x      = ndarray:float64 (123, 1)
xnames = ['plantx0'] (list)
y0     = ndarray:float64 (123,)
y1     = ndarray:int64 (123,)
ynames = ['plant[0]', 'demand[0]'] (list)
```

by default the results are written to `bd.out`, use the option `--out FILE` to set it
to a specific value.

The block parameters can also be overridden from the command line without having to 
edit the code.  To increase the loop gain we could write:
```[shell]
examples/eg1.py --set gain.0:K=20
```

More details on this Wiki about:

- [Adding blocks](https://github.com/petercorke/bdsim/wiki/Adding-blocks)
- [Connecting blocks](https://github.com/petercorke/bdsim/wiki/Connecting-blocks)
- [Running the simulation](https://github.com/petercorke/bdsim/wiki/Running)
- [Command line options](https://github.com/petercorke/bdsim/wiki/Runtime-options)

## Other examples

In the folder `bdsim/examples` you can find a few other runnable examples:

- [`eg1.py`](https://github.com/petercorke/bdsim/blob/master/examples/eg1.py) the example given above
- [`waveform.py`](https://github.com/petercorke/bdsim/blob/master/examples/waveform.py) two signal generators connected to two scopes

Examples from Chapter four of _Robotics, Vision & Control 2e (2017)_:

- [`rvc4_2.py`](https://github.com/petercorke/bdsim/blob/master/examples/rvc4_2.py) Fig 4.2 - a car-like vehicle with bicycle kinematics driven by a rectangular pulse steering signal
- [`rvc4_4.py`](https://github.com/petercorke/bdsim/blob/master/examples/rvc4_4.py) Fig 4.4 - a car-like vehicle driving to a point

![RVC Figure 4.4](https://github.com/petercorke/bdsim/raw/master/figs/rvc4_4.gif)

- [`rvc4_6.py`](https://github.com/petercorke/bdsim/blob/master/examples/rvc4_6.py) Fig 4.6 - a car-like vehicle driving to/along a line

![RVC Figure 4.6](https://github.com/petercorke/bdsim/raw/master/figs/rvc4_6.gif)

- [`rvc4_8.py`](https://github.com/petercorke/bdsim/blob/master/examples/rvc4_8.py) Fig 4.8 - a car-like vehicle using pure-pursuit trajectory following

![RVC Figure 4.6](https://github.com/petercorke/bdsim/raw/master/figs/rvc4_8.gif)

- [`rvc4_11.py`](https://github.com/petercorke/bdsim/blob/master/examples/rvc4_11.py) Fig 4.11 a car-like vehicle driving to a pose

![RVC Figure 4.11](https://github.com/petercorke/bdsim/raw/master/figs/rvc4_11.gif)

Figs 4.8 (pure pursuit) and Fig 4.21 (quadrotor control) are yet to be done.

# A more concise way

Wiring, and some simple arithmetic blocks like `GAIN`, `SUM` and `PROD` can be implicitly generated by overloaded Python operators.  This strikes a nice balance between block diagram coding and Pythonic programming.

```
     1  #!/usr/bin/env python3
     2
     3  import bdsim
     4
     5  sim = bdsim.BDSim()  # create simulator
     6  bd = sim.blockdiagram()  # create an empty block diagram
     7
     8  # define the blocks
     9  demand = bd.STEP(T=1, name='demand')
    10  plant = bd.LTI_SISO(0.5, [2, 1], name='plant')
    11  scope = bd.SCOPE(styles=['k', 'r--'], movie='eg1.mp4')
    12
    13  # connect the blocks using Python syntax
    14  scope[0] = plant
    15  scope[1] = demand
    16  plant[0] = 10 * (demand - plant)
    17
    18  bd.compile()   # check the diagram
    19  bd.report()    # list all blocks and wires
    20
    22  out = sim.run(bd, 5, watch=[plant,])  # simulate for 5s
```
This requires fewer lines of code and the code is more readable. Importantly, it results in in *exactly the same* block diagram in terms of blocks and wires
```
Wires::

┌───┬──────┬──────┬──────────────────────────────┬─────────┐
│id │ from │  to  │         description          │  type   │
├───┼──────┼──────┼──────────────────────────────┼─────────┤
│ 0 │ 1[0] │ 2[0] │ plant[0] --> scope.0[0]      │ float64 │
│ 1 │ 0[0] │ 2[1] │ demand[0] --> scope.0[1]     │ int     │
│ 2 │ 0[0] │ 3[0] │ demand[0] --> _sum.0[0]      │ int     │
│ 3 │ 1[0] │ 3[1] │ plant[0] --> _sum.0[1]       │ float64 │
│ 4 │ 3[0] │ 4[0] │ _sum.0[0] --> _gain.0(10)[0] │ float64 │
│ 5 │ 4[0] │ 1[0] │ _gain.0(10)[0] --> plant[0]  │ float64 │
└───┴──────┴──────┴──────────────────────────────┴─────────┘
```
The implicitly created blocks have names prefixed with an underscore.

# bdedit: the graphical editing tool

![block diagram](https://github.com/petercorke/bdsim/raw/master/figs/eg1-bdedit.png)

`bdedit` is a multi-platform PyQt5-based graphical tool to create, edit, render and execute block diagram models.

From the examples folder
```
% bdedit eg1.bd
```
will create a display like that shown above.  Pushing the run button, top left (triangle in circle) will spawn `bdrun` as a subprocess which will:

* parse the JSON file
* instantiate all blocks and wires
* compile and run the diagram

# Article

I published [this article on LinkedIn](https://www.linkedin.com/pulse/journey-toward-open-source-block-diagram-simulation-peter-corke/?trackingId=wrJYinHUgAHDq63Nv65PnA%3D%3D), which describes the thought process behind bdsim.

# Limitations

There are lots!  The biggest is that `bdsim` is based on a very standard variable-step integrator from the scipy library.  For discontinuous inputs (step, square wave, triangle wave, piecewise constant) the transitions get missed.  This also makes it inaccurate to simulate hybrid discrete-continuous time systems.  We really need a better integrator, perhaps [`odedc`](https://help.scilab.org/docs/6.1.0/en_US/odedc.html) from SciLab could be integrated.



            

Raw data

            {
    "_id": null,
    "home_page": "",
    "name": "bdsim",
    "maintainer": "",
    "docs_url": null,
    "requires_python": ">=3.7",
    "maintainer_email": "",
    "keywords": "python,block diagram,dynamic simulation",
    "author": "",
    "author_email": "Peter Corke <rvc@petercorke.com>",
    "download_url": "https://files.pythonhosted.org/packages/f2/cb/0531fb767d6a3a24f337208cd8d37b4749878a76b13b6701f322056c4798/bdsim-1.1.1.tar.gz",
    "platform": null,
    "description": "[![A Python Robotics Package](https://raw.githubusercontent.com/petercorke/robotics-toolbox-python/master/.github/svg/py_collection.min.svg)](https://github.com/petercorke/robotics-toolbox-python)\n[![QUT Centre for Robotics Open Source](https://github.com/qcr/qcr.github.io/raw/master/misc/badge.svg)](https://qcr.github.io)\n\n[![PyPI version](https://badge.fury.io/py/bdsim.svg)](https://badge.fury.io/py/bdsim)\n![Python Version](https://img.shields.io/pypi/pyversions/bdsim.svg)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)\n\n[![Build Status](https://github.com/petercorke/bdsim/workflows/build/badge.svg?branch=master)](https://github.com/petercorke/bdsim/actions?query=workflow%3Abuild)\n[![Coverage](https://codecov.io/gh/petercorke/bdsim/branch/master/graph/badge.svg)](https://codecov.io/gh/petercorke/bdsim)\n[![PyPI - Downloads](https://img.shields.io/pypi/dm/bdsim)](https://pypistats.org/packages/bdsim)\n[![GitHub stars](https://img.shields.io/github/stars/petercorke/bdsim.svg?style=social&label=Star)](https://GitHub.com/petercorke/bdsim/stargazers/)\n\n<table style=\"border:0px\">\n<tr style=\"border:0px\">\n<td style=\"border:0px\">\n<img src=\"https://github.com/petercorke/bdsim/raw/master/figs/BDSimLogo_NoBackgnd@2x.png\" width=\"300\"></td>\n<td style=\"border:0px\">\nA Python block diagram simulation package</a>\n<ul>\n<li><a href=\"https://github.com/petercorke/bdsim\">GitHub repository </a></li>\n<li><a href=\"https://petercorke.github.io/bdsim\">Documentation</a></li>\n<li><a href=\"https://github.com/petercorke/bdsim/wiki\">Wiki (examples and details)</a></li>\n<li><a href=\"installation#\">Installation</a></li>\n<li>Dependencies: numpy, scipy, matplotlib, <a href=\"https://github.com/petercorke/ansitable\">ansitable</a>, ffmpeg (if rendering animations as a movie)</li>\n</ul>\n</td>\n</tr>\n</table>\n\n`bdsim` is Python 3 package that enables modelling and simulation of continuous-time, discrete-time or hybrid dynamic systems.  Systems are conceptualized in block diagram form, but represented in terms of Python objects. \n\n  <table>\n  <tr>\n  <td>\n  <img width=450 src=\"https://github.com/petercorke/bdsim/raw/master/figs/bd1-sketch.png\">\n  </td>\n  <td style=\"padding-left: 20px;\">\n  <pre style=\"font-size:10px;\">\n  # define the blocks\n  demand = bd.STEP(T=1, name='demand')\n  sum = bd.SUM('+-')\n  gain = bd.GAIN(10)\n  plant = bd.LTI_SISO(0.5, [2, 1])\n  scope = bd.SCOPE(styles=['k', 'r--'])\n  # connect the blocks\n  bd.connect(demand, sum[0], scope[1])\n  bd.connect(plant, sum[1])\n  bd.connect(sum, gain)\n  bd.connect(gain, plant)\n  bd.connect(plant, scope[0])\n  </pre>\n  </td>\n  </tr>\n  </table>\n\nKey features include:\n\n* The block diagram can be created easily using Python code, rather than drawing boxes and wires. This enables use of your favourite IDE, standard version control tools and development workflows.\n* Wires can communicate *any* Python type such as scalars, lists, dicts, NumPy arrays, objects, and functions. For robotics and vision applications using the [Spatial Maths Toolbox for Python](https://github.com/petercorke/spatialmath-python) wires could send values such as `SE3`, `UnitQuaternion` or `Twist3` objects.\n* Over 70 blocks for linear, nonlinear functions, display blocks, as well as continuous- and discrete-time dynamics\n  * Easy to add your own block, it's simply a class\n  * Subsystems are supported, and a subsystem can be independently instantiated multiple times in a system.  Subsystems can also be nested.\n  * Blocks from other toolboxes are automatically discovered and included. There are blocks for some functions in the  [Robotics Toolbox for Python](https://github.com/petercorke/robotics-toolbox-python) (such as arm, ground and aerial robots) and [Machine Vision Toolbox for Python](https://github.com/petercorke/machinevision-toolbox-python) (such as cameras). These are defined in the `blocks` folder of those toolboxes.\n* The diagram can be executed in a headless configuration, particularly useful on an embedded computer like a RaspberryPi.\n* A [python-based graphical editor](bdedit-the-graphical-editing-tool)\n  * allows graphical creation of block diagrams\n  * the diagram is stored in a human readable/editable JSON file with extension `.bd`\n  * creates good-quality graphics for inclusion in publications\n  * can launch `bdsim` to import and execute the model\n  * automatically discovers all bsdim and toolbbox blocks and adds them to the block library menu\n  * icons can be easily created using any image creation tool or a LaTeX expression \n\n# Getting started\n\nWe first sketch the dynamic system we want to simulate as a block diagram, for example this simple first-order system\n\n![block diagram](https://github.com/petercorke/bdsim/raw/master/figs/bd1-sketch.png)\n\nwhich we can express concisely with `bdsim` as (see [`bdsim/examples/eg1.py`](https://github.com/petercorke/bdsim/blob/master/examples/eg1.py))\n\n```python\n     1  #!/usr/bin/env python3\n     2  import bdsim\t\n     4  sim = bdsim.BDSim()  # create simulator\n     5  bd = sim.blockdiagram()  # create an empty block diagram\n     6\t\n     7\t# define the blocks\n     8\tdemand = bd.STEP(T=1, name='demand')\n     9\tsum = bd.SUM('+-')\n    10\tgain = bd.GAIN(10)\n    11\tplant = bd.LTI_SISO(0.5, [2, 1], name='plant')\n    12\tscope = bd.SCOPE(styles=['k', 'r--'])\n    13\t\n    14\t# connect the blocks\n    15\tbd.connect(demand, sum[0], scope[1])\n    17\tbd.connect(sum, gain)\n    18\tbd.connect(gain, plant)\n    19\tbd.connect(plant, sum[1], scope[0])\n    20\t\n    21\tbd.compile()          # check the diagram\n    22\n    23\tsim.report(bd)   # list the system\n    24  out = sim.run(bd, 5)   # simulate for 5s\n```\nwhich is just 15 lines of executable code.\n\nThe red block annotations on the hand-drawn diagram are used as the names of the variables holding references to the block instance. The blocks can also have user-assigned names, see lines 8 and 11, which are used in diagnostics and as labels in plots.\n\nAfter the blocks are created their input and output ports need to be connected. In `bdsim` all wires are point to point, a *one-to-many* connection is implemented by *many* wires,\nfor example\n```\nbd.connect(source, dest1, dest2, ...)\n```\ncreates individual wires from `source` -> `dest1`, `source` -> `dest2` and so on.\nPorts are designated using Python indexing notation, for example `block[2]` is port 2 (the third port) of `block`.  Whether it is an input or output port depends on context.\nIn the example above an index on the first argument refers to an output port, while on the second (or subsequent) arguments it refers to an input port.  If a block has only a single input or output port then no index is required, 0 is assumed.\n\nA group of ports can be denoted using slice notation, for example \n```\nbd.connect(source[2:5], dest[3:6)\n```\nwill connect `source[2]` -> `dest[3]`, `source[3]` -> `dest[4]`, `source[4]` -> `dest[5]`.\nThe number of wires in each slice must be consistent.  You could even do a cross over by connecting `source[2:5]` to `dest[6:3:-1]`.\n\nLine 21 assembles all the blocks and wires, instantiates subsystems, checks connectivity to create a flat wire list, and then builds the dataflow execution plan.\n\nLine 23 generates a report, in tabular form, showing a summary of the block diagram:\n\n```\n\u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n\u2502 block  \u2502   type   \u2502 inport \u2502 source \u2502 source type \u2502\n\u251c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524\n\u2502demand@ \u2502 step     \u2502        \u2502        \u2502             \u2502\n\u251c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524\n\u2502gain.0  \u2502 gain     \u2502 0      \u2502 sum.0  \u2502 float64     \u2502\n\u251c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524\n\u2502plant   \u2502 lti_siso \u2502 0      \u2502 gain.0 \u2502 float64     \u2502\n\u251c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524\n\u2502scope.0 \u2502 scope    \u2502 0      \u2502 plant  \u2502 float64     \u2502\n\u2502        \u2502          \u2502 1      \u2502 demand \u2502 int         \u2502\n\u251c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524\n\u2502sum.0   \u2502 sum      \u2502 0      \u2502 demand \u2502 int         \u2502\n\u2502        \u2502          \u2502 1      \u2502 plant  \u2502 float64     \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n```\n\nLine 24 runs the simulation for 5 seconds \nusing the default variable-step RK45 solver and saves output values at least every 0.05s.  It\ncauses the following output\n\n```\n>>> Start simulation: T = 5.00, dt = 0.050\n  Continuous state variables: 1\n     x0 =  [0.]\n  Discrete state variables:   0\n\nno graphics backend specified: Qt5Agg found, using instead of MacOSX\n\nbdsim \u25c9\u25c9\u25c9\u25c9\u25c9\u25c9\u25c9\u25c9\u25c9\u25c9\u25c9\u25c9\u25c9\u25c9\u25c9\u25c9\u25c9\u25c9\u25c9\u25c9\u25c9\u25c9\u25c9\u25c9\u25c9\u25c9\u25c9\u25c9\u25c9\u25c9\u25c9\u25c9 100.0% - 0s\n\n<<< Simulation complete\n  block diagram evaluations: 784\n  block diagram exec time:   0.075 ms\n  time steps:                123\n  integration intervals:     2\n```\n\nThis provides a summary of the number of states for the complete system: the number of continuous states, the number\nof discrete states, and the initial value of the state vectors.\n\nDuring execution a progress bar is updated and scope blocks pops up a graphical window\n\n![bdsim output](https://github.com/petercorke/bdsim/raw/master/figs/Figure_1.png)\n\nThe simulation results are in a container object (`BDStruct`)\n```\n>>> out\nt      = ndarray:float64 (123,)\nx      = ndarray:float64 (123, 1)\nxnames = ['plantx0'] (list)\nynames = [] (list)            \n```\nwhich contains an array of time values, an array of state values, and a list of the\nnames of the state variables.\n\nBy default the `.run()` method at line 24 blocks blocks the script until all figure\nwindows are closed (by pressing the operating system close button or typing \"q\"), or the\nscript is killed with SIGINT. If you want to continue the script with the figures still\nactive then the `hold=False` option should be set.\n\nIf we wished to also record additional outputs, we can add them as _watched_ signals\n```\nout = sim.run(bd, watch=[demand, sum])  # simulate for 5s\n```\nand now the output is\n```\n>>> out\nt      = ndarray:float64 (123,)\nx      = ndarray:float64 (123, 1)\nxnames = ['plantx0'] (list)\ny0     = ndarray:float64 (123,)\ny1     = ndarray:int64 (123,)\nynames = ['plant[0]', 'demand[0]'] (list)\n```\nwhere\n\n- `t` the time vector: ndarray, shape=(M,)\n- `x` is the state vector: ndarray, shape=(M,N), one row per timestep\n- `xnames` is a list of the names of the states corresponding to columns of `x`, eg. \"plant.x0\"\n\nThe `watch` argument is a list of outputs to log, in this case `plant` defaults\nto output port 0.  This information is saved in additional variables `y0`, `y1`\netc.  `ynames` is a list of the names of the watched variables.\n\nAn alternative system report, created by `sim.report(bd, type=\"lists\")` is more detailed\n```\nBlocks::\n\n\u250c\u2500\u2500\u2500\u252c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252c\u2500\u2500\u2500\u2500\u2500\u252c\u2500\u2500\u2500\u2500\u2500\u2500\u252c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n\u2502id \u2502    name \u2502 nin \u2502 nout \u2502 nstate \u2502 ndstate \u2502 type  \u2502\n\u251c\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524\n\u2502 0 \u2502  demand \u2502   0 \u2502    1 \u2502      0 \u2502       0 \u2502 step  \u2502\n\u2502 1 \u2502   sum.0 \u2502   2 \u2502    1 \u2502      0 \u2502       0 \u2502 sum   \u2502\n\u2502 2 \u2502  gain.0 \u2502   1 \u2502    1 \u2502      0 \u2502       0 \u2502 gain  \u2502\n\u2502 3 \u2502   plant \u2502   1 \u2502    1 \u2502      1 \u2502       0 \u2502 LTI   \u2502\n\u2502 4 \u2502 scope.0 \u2502   2 \u2502    0 \u2502      0 \u2502       0 \u2502 scope \u2502\n\u2514\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n\nWires::\n\n\u250c\u2500\u2500\u2500\u252c\u2500\u2500\u2500\u2500\u2500\u2500\u252c\u2500\u2500\u2500\u2500\u2500\u2500\u252c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n\u2502id \u2502 from \u2502  to  \u2502       description        \u2502  type   \u2502\n\u251c\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524\n\u2502 0 \u2502 0[0] \u2502 1[0] \u2502 demand[0] --> sum.0[0]   \u2502 int     \u2502\n\u2502 1 \u2502 0[0] \u2502 4[1] \u2502 demand[0] --> scope.0[1] \u2502 int     \u2502\n\u2502 2 \u2502 3[0] \u2502 1[1] \u2502 plant[0] --> sum.0[1]    \u2502 float64 \u2502\n\u2502 3 \u2502 1[0] \u2502 2[0] \u2502 sum.0[0] --> gain.0[0]   \u2502 float64 \u2502\n\u2502 4 \u2502 2[0] \u2502 3[0] \u2502 gain.0[0] --> plant[0]   \u2502 float64 \u2502\n\u2502 5 \u2502 3[0] \u2502 4[0] \u2502 plant[0] --> scope.0[0]  \u2502 float64 \u2502\n\u2514\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n```\nIn the first table we can see key information about each block, its `id` (used internally), name, the number of input and output ports, the number of\ncontinuous- and discrete-time states, and the type which is the block class.  Note that the name is auto-generated based on the type, except if it has\nbeen set explicitly as for the blocks `demand` and `plant`.\n\nThe second table shows all wires in point-to-point form, showing the start and end block and port (the block is represented here by its `id`) and the type of the object sent along the wire.\n\nTo save figures we need to make two modifications, changing line 4 to\n```\n     4  sim = bdsim.BDSim(hold=False)  # create simulator\n```\nwhich prevents `.run()` from blocking and then deleting all the figures.\nThen, after the `.run()` we add \n```\n     25 scope.savefig()  # save scope figure\n```\nIf the filename is not given it defaults to the block name, in this case `scope.0.pdf`.\n\n\nThe output can be pickled and written to a file\n\n```[shell]\nexamples/eg1.py -o\npython -mpickle bd.out\nt      = ndarray:float64 (123,)\nx      = ndarray:float64 (123, 1)\nxnames = ['plantx0'] (list)\ny0     = ndarray:float64 (123,)\ny1     = ndarray:int64 (123,)\nynames = ['plant[0]', 'demand[0]'] (list)\n```\n\nby default the results are written to `bd.out`, use the option `--out FILE` to set it\nto a specific value.\n\nThe block parameters can also be overridden from the command line without having to \nedit the code.  To increase the loop gain we could write:\n```[shell]\nexamples/eg1.py --set gain.0:K=20\n```\n\nMore details on this Wiki about:\n\n- [Adding blocks](https://github.com/petercorke/bdsim/wiki/Adding-blocks)\n- [Connecting blocks](https://github.com/petercorke/bdsim/wiki/Connecting-blocks)\n- [Running the simulation](https://github.com/petercorke/bdsim/wiki/Running)\n- [Command line options](https://github.com/petercorke/bdsim/wiki/Runtime-options)\n\n## Other examples\n\nIn the folder `bdsim/examples` you can find a few other runnable examples:\n\n- [`eg1.py`](https://github.com/petercorke/bdsim/blob/master/examples/eg1.py) the example given above\n- [`waveform.py`](https://github.com/petercorke/bdsim/blob/master/examples/waveform.py) two signal generators connected to two scopes\n\nExamples from Chapter four of _Robotics, Vision & Control 2e (2017)_:\n\n- [`rvc4_2.py`](https://github.com/petercorke/bdsim/blob/master/examples/rvc4_2.py) Fig 4.2 - a car-like vehicle with bicycle kinematics driven by a rectangular pulse steering signal\n- [`rvc4_4.py`](https://github.com/petercorke/bdsim/blob/master/examples/rvc4_4.py) Fig 4.4 - a car-like vehicle driving to a point\n\n![RVC Figure 4.4](https://github.com/petercorke/bdsim/raw/master/figs/rvc4_4.gif)\n\n- [`rvc4_6.py`](https://github.com/petercorke/bdsim/blob/master/examples/rvc4_6.py) Fig 4.6 - a car-like vehicle driving to/along a line\n\n![RVC Figure 4.6](https://github.com/petercorke/bdsim/raw/master/figs/rvc4_6.gif)\n\n- [`rvc4_8.py`](https://github.com/petercorke/bdsim/blob/master/examples/rvc4_8.py) Fig 4.8 - a car-like vehicle using pure-pursuit trajectory following\n\n![RVC Figure 4.6](https://github.com/petercorke/bdsim/raw/master/figs/rvc4_8.gif)\n\n- [`rvc4_11.py`](https://github.com/petercorke/bdsim/blob/master/examples/rvc4_11.py) Fig 4.11 a car-like vehicle driving to a pose\n\n![RVC Figure 4.11](https://github.com/petercorke/bdsim/raw/master/figs/rvc4_11.gif)\n\nFigs 4.8 (pure pursuit) and Fig 4.21 (quadrotor control) are yet to be done.\n\n# A more concise way\n\nWiring, and some simple arithmetic blocks like `GAIN`, `SUM` and `PROD` can be implicitly generated by overloaded Python operators.  This strikes a nice balance between block diagram coding and Pythonic programming.\n\n```\n     1  #!/usr/bin/env python3\n     2\n     3  import bdsim\n     4\n     5  sim = bdsim.BDSim()  # create simulator\n     6  bd = sim.blockdiagram()  # create an empty block diagram\n     7\n     8  # define the blocks\n     9  demand = bd.STEP(T=1, name='demand')\n    10  plant = bd.LTI_SISO(0.5, [2, 1], name='plant')\n    11  scope = bd.SCOPE(styles=['k', 'r--'], movie='eg1.mp4')\n    12\n    13  # connect the blocks using Python syntax\n    14  scope[0] = plant\n    15  scope[1] = demand\n    16  plant[0] = 10 * (demand - plant)\n    17\n    18  bd.compile()   # check the diagram\n    19  bd.report()    # list all blocks and wires\n    20\n    22  out = sim.run(bd, 5, watch=[plant,])  # simulate for 5s\n```\nThis requires fewer lines of code and the code is more readable. Importantly, it results in in *exactly the same* block diagram in terms of blocks and wires\n```\nWires::\n\n\u250c\u2500\u2500\u2500\u252c\u2500\u2500\u2500\u2500\u2500\u2500\u252c\u2500\u2500\u2500\u2500\u2500\u2500\u252c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n\u2502id \u2502 from \u2502  to  \u2502         description          \u2502  type   \u2502\n\u251c\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524\n\u2502 0 \u2502 1[0] \u2502 2[0] \u2502 plant[0] --> scope.0[0]      \u2502 float64 \u2502\n\u2502 1 \u2502 0[0] \u2502 2[1] \u2502 demand[0] --> scope.0[1]     \u2502 int     \u2502\n\u2502 2 \u2502 0[0] \u2502 3[0] \u2502 demand[0] --> _sum.0[0]      \u2502 int     \u2502\n\u2502 3 \u2502 1[0] \u2502 3[1] \u2502 plant[0] --> _sum.0[1]       \u2502 float64 \u2502\n\u2502 4 \u2502 3[0] \u2502 4[0] \u2502 _sum.0[0] --> _gain.0(10)[0] \u2502 float64 \u2502\n\u2502 5 \u2502 4[0] \u2502 1[0] \u2502 _gain.0(10)[0] --> plant[0]  \u2502 float64 \u2502\n\u2514\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n```\nThe implicitly created blocks have names prefixed with an underscore.\n\n# bdedit: the graphical editing tool\n\n![block diagram](https://github.com/petercorke/bdsim/raw/master/figs/eg1-bdedit.png)\n\n`bdedit` is a multi-platform PyQt5-based graphical tool to create, edit, render and execute block diagram models.\n\nFrom the examples folder\n```\n% bdedit eg1.bd\n```\nwill create a display like that shown above.  Pushing the run button, top left (triangle in circle) will spawn `bdrun` as a subprocess which will:\n\n* parse the JSON file\n* instantiate all blocks and wires\n* compile and run the diagram\n\n# Article\n\nI published [this article on LinkedIn](https://www.linkedin.com/pulse/journey-toward-open-source-block-diagram-simulation-peter-corke/?trackingId=wrJYinHUgAHDq63Nv65PnA%3D%3D), which describes the thought process behind bdsim.\n\n# Limitations\n\nThere are lots!  The biggest is that `bdsim` is based on a very standard variable-step integrator from the scipy library.  For discontinuous inputs (step, square wave, triangle wave, piecewise constant) the transitions get missed.  This also makes it inaccurate to simulate hybrid discrete-continuous time systems.  We really need a better integrator, perhaps [`odedc`](https://help.scilab.org/docs/6.1.0/en_US/odedc.html) from SciLab could be integrated.\n\n\n",
    "bugtrack_url": null,
    "license": "MIT License  Copyright (c) 2020 Peter Corke  Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:  The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.  THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ",
    "summary": "Simulate dynamic systems expressed in block diagram form using Python",
    "version": "1.1.1",
    "project_urls": {
        "documentation": "https://petercorke.github.io/bdsim/",
        "homepage": "https://github.com/petercorke/bdsim",
        "repository": "https://github.com/petercorke/bdsim"
    },
    "split_keywords": [
        "python",
        "block diagram",
        "dynamic simulation"
    ],
    "urls": [
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "8eba551eaf38d5059003af67f5afdff4dbace790c3a80d8548dd785710d113e9",
                "md5": "9bb2b59402f96abe6baa31a7df6632e4",
                "sha256": "65db0e428810c49a629b53cff4bfc3bd71d65aa9a559888a14997ae86ca7cd0c"
            },
            "downloads": -1,
            "filename": "bdsim-1.1.1-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "9bb2b59402f96abe6baa31a7df6632e4",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": ">=3.7",
            "size": 277397,
            "upload_time": "2023-05-22T10:04:01",
            "upload_time_iso_8601": "2023-05-22T10:04:01.471458Z",
            "url": "https://files.pythonhosted.org/packages/8e/ba/551eaf38d5059003af67f5afdff4dbace790c3a80d8548dd785710d113e9/bdsim-1.1.1-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "f2cb0531fb767d6a3a24f337208cd8d37b4749878a76b13b6701f322056c4798",
                "md5": "8ed8930d13415c29f678e2a7ef11c359",
                "sha256": "04ad65cc2c12bbd3596664da48dc8358f9b8edb7a9690983d0cadb69a8c3c358"
            },
            "downloads": -1,
            "filename": "bdsim-1.1.1.tar.gz",
            "has_sig": false,
            "md5_digest": "8ed8930d13415c29f678e2a7ef11c359",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": ">=3.7",
            "size": 263715,
            "upload_time": "2023-05-22T10:04:04",
            "upload_time_iso_8601": "2023-05-22T10:04:04.177010Z",
            "url": "https://files.pythonhosted.org/packages/f2/cb/0531fb767d6a3a24f337208cd8d37b4749878a76b13b6701f322056c4798/bdsim-1.1.1.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2023-05-22 10:04:04",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "petercorke",
    "github_project": "bdsim",
    "travis_ci": false,
    "coveralls": false,
    "github_actions": true,
    "lcname": "bdsim"
}
        
Elapsed time: 0.07411s