Search code examples
pythonmatlabsimulink

Share Python object between blocks in Simulink


I have created a class in Python. In my application this class is a kind of lookup table.

Here is a sample class to illustrate the topic :

class ExampleClass:

    def __init__(self, var1):
        self.prop1 = var1

    def get_property(self):
        return self.prop1

Matlab offers the ability to call Python modules directly within the Matlab environment (see Matlab docs)

One calls Python like :

>>> py.importlib.import_module("ExampleClass")
>>> x = py.ExampleClass.ExampleClass(1)
>>> x.get_property()
ans =

     1

What I would like to do is to make x available in Simulink m-function blocks in order to call get_property() from all the m-function blocks. Note that the creation of x is computationally expensive, therefore I want to load it in the workspace once when initializing the simulation.

What I tried so far : I tried passing my ExampleClass to the m-functions via a mask parameter, but I get an error :

Error:Expression 'object name' for type of data 'x' did not evaluate to a valid type.

Which is understandable because Simulink does not allow to use datatypes other than int, double and other standard data types.

Is there a way around to be able to call x.get_property()from my m-functions ?


Solution

  • Efficient access to python variables

    To date, there is no efficient way to access those variables. For other ways to access them, see below.

    Using coder.extrinsic and evalin

    Note : This workaround works so I share it here but the performance is not satisfactory due to the evalin and coder.extrinsic calls.

    It is possible to use objects within the base workspace from a Simulink m-function block with the following functions:

    Object creation in the base workspace

    >>> py.importlib.import_module("ExampleClass")
    >>> x = py.ExampleClass.ExampleClass(1)
    

    In the Simulink m-function block :

    function out = fcn()
        coder.extrinsic('get_property_in_matlab') % goes outside of Simulink
        out = 0; % Initialize output type for Simulink
        out = get_property_in_matlab();
    end
    

    In Matlab we define a function to call x

    function [res] = get_property_in_matlab()
        x_in_matlab = evalin('base', 'x'); % Get the object from base workspace
        res = x_in_matlab.get_property(); % Use the get property method
    end
    

    This workaround works but the penalty of using coder.extrinsic and evalin renders this solution unusable performance-wise in my case.

    Using a Matlab System block

    See documentation. This yields the same performance as previous try with coder.extrinsic and evalin.

    Create a Simulink object : New --> System Object --> Simulink Extension

    Then create a property for the object

     % Public, tunable properties
        properties
            ex_class_obj   
        end
    

    In the constructor add the object value :

    methods
            % Constructor
            function obj = example_class_caller(varargin)
                % Support name-value pair arguments when constructing object
                setProperties(obj,nargin,varargin{:})
                obj.ex_class_obj = evalin('base', 'x');    
            end
        end
    ...
    

    Make sure to choose Interpreted execution.

    Finally perform your computation in stepImpl:

            function y = stepImpl(obj)
                % Implement algorithm. Calculate y as a function of input u and
                % discrete states.
                
                y= obj.ex_class_obj.get_property();
            end