Visualizing Simulink Model Structure with Pyparsing
November 12th, 2008
To try out some programmatic access to Simulink models, I have been using a modified version of Kjell Magne Fauske’s pyparsing Simulink parser.
I convert the structure of the model to text in the format of the DOT graphics language, so you can use the wellknown Graphviz application to create nice visualizations of your model-structure. Graphviz supports direct output to PDF, so it is also pretty nifty as a way of documenting your model.
Here is the sourcecode of my little tool, I hope you find it useful :
"""
A simple generator of DOT graphics-files from Simulink models.
Credits:
This is basically a modified version of the MDL parser written by
Kjell Magne Fauske - see http://www.fauskes.net/nb/parsing-simulink/.
Thanks Kjell!
"""
__author__ = 'Alex Scheel Meyer'
__license__ = 'MIT'
import sys
from pyparsing import *
# parse actions
def convertNumbers(s,l,toks):
"""Convert tokens to int or float"""
# Taken from jsonParser.py
n = toks[0]
try:
return int(n)
except ValueError, ve:
return float(n)
def joinStrings(s,l,toks):
"""Join string split over multiple lines"""
return ["".join(toks)]
# Define grammar
dblString = dblQuotedString.setParseAction( removeQuotes )
mdlNumber = Combine( Optional('-') + ( '0' | Word('123456789',nums) ) + Optional( '.' + Word(nums) ) + Optional( Word('eE',exact=1) + Word(nums+'+-',nums) ) )
mdlObject = Forward()
mdlName = Word('$'+'.'+'_'+alphas+nums)
mdlValue = Forward()
# Strings can be split over multiple lines
mdlString = (dblString + Optional(OneOrMore(Suppress(LineEnd()) + LineStart() + dblString)))
mdlElements = delimitedList( mdlValue )
mdlArray = Group(Suppress('[') + Optional(mdlElements) + Suppress(']') )
mdlMatrix =Group(Suppress('[') + (delimitedList(Group(mdlElements),';')) \
+ Suppress(']') )
mdlValue << ( mdlNumber | mdlName| mdlString | mdlArray | mdlMatrix )
memberDef = Group( mdlName + mdlValue ) | Group(mdlObject)
mdlMembers = OneOrMore( memberDef)
mdlObject << ( mdlName+Suppress('{') + Optional(mdlMembers) + Suppress('}') )
mdlNumber.setParseAction( convertNumbers )
mdlString.setParseAction(joinStrings)
mdlparser = mdlObject
def findSystems(mdlItem, systemName, knownSystems):
for item in mdlItem:
if item[0] == 'System':
subsystemName = item[1][1]
if subsystemName in knownSystems:
knownSystems[subsystemName] += 1
subsystemName = subsystemName + '(' + str(knownSystems[subsystemName]) + ')'
else:
knownSystems[subsystemName] = 1
print '"' + systemName + '" -> "' + subsystemName + '";'
findSystems(item, subsystemName, knownSystems)
if item[0] == 'Block':
findSystems(item, systemName, knownSystems)
if __name__ == '__main__':
import pprint
filename = sys.argv[1]
if len(filename) > 0 :
input = open(filename, 'r')
data = input.read()
result = mdlparser.parseString(data)
print "digraph {"
knownSystems = {}
findSystems(result, filename, knownSystems)
print "}"
Leave a Reply