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