Causal Block Diagrams (CBD) Modelling Extension in AToM3ContentsPurpose
Hierarchical Modelling
How to do it in AToM3
Again, press "genMDC" button to generate Model Description Class file. Model Description ClassNow before we run the simulation using the standalonw simulator, let's take a look at Model Description Class. Model Description Class stores all topological information of the original graphical model, it can be used:
Each type of visual block has a corresponding block class. In order to clearly represent blocks and easily manipulate them during simulation, a block class hierarchy for all kinds of blocks in CBD is created, as shown in the following figure. As you can see, all other classes inherit from BaseBlock class. The relation between types of visual blocks and corresponding block classes is as follows:
The signals attribute contains a list of signals generated by the block. The linksIN attribute contains a list of all other blocks linking into this block. Each element of the list is a tuple of four elements: the link-in block object, the name of the connection between these two blocks, the name of "inport_name" and the name of "outport_name" (only meaningful for the connection with a ChildBlock). The IC attribute of TimeDelayBlock class contains a tuple of link-in IC block object and name of connection between them. The TRUE_in attribute of TestBlock class contains a tuple of link-in TRUE_in block object and name of connection between them. FALSE_in attribute is the same. The model_instance attribute of ChildBlock class contains instance object of the referring model. Here's the Model Description Class generated from Double Integrator model: ////////////////////////////////////////////////////////////////// # Casual Block Class from math import * from BaseBlock import * class DI: def __init__(self, initParams={}): self.__initParams = initParams self.__blocks = [] # build blocks self.v_x = TimeDelayBlock("v_x", "Integrator", 0.1) self.__blocks.append(self.v_x) self.IC = BaseBlock("IC", "Inport") self.__blocks.append(self.IC) self.IN = BaseBlock("IN", "Inport") self.__blocks.append(self.IN) self.x = TimeDelayBlock("x", "Integrator", 0.1) self.__blocks.append(self.x) self.x_0 = ConstantBlock("x_0", "Constant", 4.0) self.__blocks.append(self.x_0) # build connections self.v_x.linksIN.append((self.IN, "s2", "", "")) self.v_x.linksIN.append((self.IC, "s3", "", "")) self.v_x.IC = (self.IC, "s3", "", "") self.x.linksIN.append((self.x_0, "s1", "", "")) self.x.linksIN.append((self.v_x, "s4", "", "")) self.x.IC = (self.x_0, "s1", "", "") # parameters initialization for block in self.__blocks: if isinstance(block, ConstantBlock): if (self.__initParams.has_key(block.getBlockName()) == 1): block.init_value = self.__initParams[block.getBlockName()] # to access all blocks outside the model def getBlocks(self): return self.__blocks ////////////////////////////////////////////////////////////////// As you can see from above, there are three main parts in __init__ method. We'll talk about the third part in "Parameterization" section later. Standalone Simulator
First, let's see how to build a simulation using the standalone simulator. ////////////////////////////////////////////////////////////////// # import simulator class from ST_Simulator import * # import the generated Model Description Class of a CBD model from thrown_ball import * def example(): # provide an instance of a model (the top-level model of hierarchical models) # to instantiate a simulator instance and use default parameters for the model s = ST_Simulator(thrown_ball()) # specify the duration of the simulation, let's try 32 iterations here for i in range(32): # run the simulation once s.simulate() # print out signals of all blocks s.dumpSignals() ////////////////////////////////////////////////////////////////// The output is really hard to read. Later we'll show how to use PyPlotter to make it pretty readable. In order to detect algebraic loops of a hierarchical model, besides the usual way of loop detection, we need to flatten the hierarchical model first. Why? See the following example: It's a two-level hierarchical model. For sure, the top level model has an algebraic loop and so does the whole hierarchical model. How about the following model: Since there is a Delay block inside M1_L2 model, although the top level model has an algebraic loop, the whole model is loop-free. The idea behind Flattening is very simple: if all blocks are in the same level, then the loop detection becomes easy to accomplish. The flattening is a recursive process. After the process, all Inport, Outport and Child blocks are eliminated. Obviously, flattening is a simple but not the best solution for loop detection of hierarchical model. One disadvantage is the structures of all models of each level will be known or exposed by this process. Most of time, when you build a hierarchical model, although you have several instances of the same child model, you want each of these instances to behave differently during simulation. Parameterization can help you to achieve this goal. See the following examples: You soon realize there is a need to abstract some part of the above model and model that part as a seperate model to get a hierarchical model. But you should also notice that the constant blocks "x_0" and "y_0" have different initial values. So after building the whole hierarchical model with a child model called "DI" (Double Integrators) in which the constant block's default value is 4.0, you need to specify the desired initial values of the constant blocks in different model instances, by giving a list of initial values (a map of map) to the construction method of the top-level model. This is illustrated in figure 9. Plot OutputsPyPlotter is a easy-to-use tool for simple plotting. It will be installed as a Python library. There is an example showing how to use to display results from our simulations: ////////////////////////////////////////////////////////////////// from ST_Simulator import * from thrown_ball import * from PyPlotter import tkGfx as GfxDriver # 'awtGfx' for jython from PyPlotter import Graph, Gfx def example(): s = ST_Simulator(thrown_ball({"cb13":{"x_0":0.0}, "cb15":{"x_0":2.0}})) for i in range(30): s.simulate() plot(s) def plot(s): blocks = s.getModel().getBlocks() xaxis = [] yaxis = [] for block in blocks: if (block.getBlockName() == "cb13.x"): for signal in block.signals: xaxis.append(signal) elif (block.getBlockName() == "cb15.x"): for signal in block.signals: yaxis.append(signal) gfx = GfxDriver.Window(title="Ballistic Problem") gr = Graph.Cartesian(gfx, 0, 0, 40, 14) gr.addPen("X vs Y (theta = 45 degree)", Gfx.RED_PEN) i = 0 for x in xaxis: gr.addValue("X vs Y (theta = 45 degree)", x, yaxis[i]) i += 1 gfx.waitUntilClosed() if __name__=="__main__": example() ////////////////////////////////////////////////////////////////// When you run the above simulation program, you'll get the following figure: AppendixPythonPyPlotter AToM3 (it should be already installed in any teaching machines at the third floor of Trottier as: /usr/local/pkgs/atom3/atom.sh) Causal Block Diagrams formalism (unpack it into the AToM3 workspace folder under your home directory; some functions of the standalone simulator are removed temporarily for teaching purpose.) Tips: In any teaching machine at Trottier, the AToM3 is under: /usr/local/pkgs/atom3/
|
Maintained by Ximeng Sun. | Last Modified: 2008/09/10 00:03:05. |