-
Notifications
You must be signed in to change notification settings - Fork 34
Subsystems
This example is given in examples/subsys.py
. We will build the example incrementally
#!/usr/bin/env python3
import bdsim
sim = bdsim.BDSim()
is the standard boilerplate for using the bdsim
package.
Next, we define our subsystem. It is a block diagram created in the conventional way
# create simple subsystem as a blockdiagram
ss = sim.blockdiagram(name="subsystem1")
squarer = ss.FUNCTION(lambda x: x**2)
sum = ss.SUM("++")
inp = ss.INPORT(2)
outp = ss.OUTPORT(1)
ss.connect(inp[0], squarer)
ss.connect(squarer, sum[0])
ss.connect(inp[1], sum[1])
ss.connect(sum, outp)
The only thing different so far is that there are INPORT
and OUTPORT
blocks. These are the interface between this block diagram and the block diagram that encloses (or contains) it.
INPORT(2)
specifies that this subsystem has two inputs, from the outside it looks like a 2-input block. Within the subsystem, the outputs of this block are the signals fed to the subsystem's input ports from the enclosing block diagram.
OUTPORT(1)
specifies that this subsystem has one output, from the outside it looks like a 1-output block. Within the subsystem, the inputs of this block are the signals from the subsystem's output ports that are used in the enclosing block diagram.
# create main system as a blockdiagram
main = sim.blockdiagram()
x = main.WAVEFORM("sine", 1, "Hz")
const = main.CONSTANT(1)
scope = main.SCOPE()
subsys = main.SUBSYSTEM(ss, name="squarer") # instantiate the subsystem
main.connect(x, subsys[0])
main.connect(const, subsys[1])
main.connect(subsys, scope)
The wiring connects the waveform generator and the constant to inputs 0 and 1 respectively of the subsystem. The single output of the subsystem is wired to the scope.
The compilation step effectively inserts the subsystem into the top-level block diagram
main.compile(verbose=False)
sim.report(main)
The report shows the resulting system. The subsystem has been inlined and we now have a flat wirelist
┌───────────────────┬────────┬────────────────────┬─────────────┐
│ block │ inport │ source │ source type │
├───────────────────┼────────┼────────────────────┼─────────────┤
│constant.0 │ │ │ │
├───────────────────┼────────┼────────────────────┼─────────────┤
│scope.0 │ 0 │ squarer/outport.0 │ float │
├───────────────────┼────────┼────────────────────┼─────────────┤
│squarer/function.0 │ 0 │ squarer/inport.0 │ float │
├───────────────────┼────────┼────────────────────┼─────────────┤
│squarer/inport.0 │ 0 │ waveform.0 │ float │
│ │ 1 │ constant.0 │ int │
├───────────────────┼────────┼────────────────────┼─────────────┤
│squarer/outport.0 │ 0 │ squarer/sum.0 │ float │
├───────────────────┼────────┼────────────────────┼─────────────┤
│squarer/sum.0 │ 0 │ squarer/function.0 │ float │
│ │ 1 │ squarer/inport.0 │ int │
├───────────────────┼────────┼────────────────────┼─────────────┤
│waveform.0@ │ │ │ │
└───────────────────┴────────┴────────────────────┴─────────────┘
Note: @ = event source
Note that the input and output port blocks are still present in the block diagram. They are essentially no op blocks that pass the signals through. They can be useful for diagnostics because we can add the outputs of these blocks to the watch list. We could just as easily watch any signal inside the subsystem, for example we could watch squarer/function.0
.
The blocks within the subsystem have names like Unix paths, they are prefixed by the subsystem's name. A block in subsystem1
which was enclosed by subsystem2
would have a name like subsystem2/subsystem1/block
.
We could instantiate the subsystem multiple times, but for each instantiation the subsystem must have a unique name, since bdsim
requires that all blocks have unique names. Here we forced the subsystem's name to
be squarer
but if had left that out, the first instantiation would have been named subsystem.0
, the next one subsystem.1
and so on. If a block within the subsystem had a user-assigned name then the different subsystem prefixes would ensure that each instance of that block would have a unique name.
Finally, we can run the system in the usual manner
sim.run(main, T=5) # simulate for 5s
Copyright (c) Peter Corke 2020-23
- Home
- FAQ
- Changes
- Adding blocks
- Block path
- Connecting blocks
- Subsystems
- Compiling
- Running
- Runtime options
- Discrete-time blocks
- Figures
- Real time control
- PID control
- Coding patterns