9

I have a Simulink model that is currently being run from a script (i.e. not a function). The script writes variable values to the MATLAB workspace, runs the model simulation (which uses these values), and then the model writes additional values to the workspace. If I try to convert the script into a function (i.e. by placing function [output] = runSim() at the top of the file) then Simulink complains that it doesn't know about the variables, presumably because they are not in the MATLAB workspace, but rather they are in the function scope.

Is there an elegant way to provide a Simulink model with inputs and take outputs from a Simulink model other than sticking them into the workspace?

Peter Mortensen
  • 28,342
  • 21
  • 95
  • 123
JnBrymn
  • 21,527
  • 26
  • 95
  • 140

4 Answers4

10

It's not obvious, but you can input/output data from the sim() command and a calling function's workspace. I've done it before & have an example at work but can't get there until Monday to verify. However, try the solution listed on Mathworks's site:

Solution:

When using variable mask parameters in Simulink, the base workspace is the default source workspace of Simulink. However, by using the SIMSET command, this workspace can be changed. SIM is then used with this options structure created by SIMSET. The following is an example on how to do this.

  options = simset('SrcWorkspace','current');
  sim('modelname',[],options)

...although apparently this got deprecated in R2009b due to incompatibility with the Parallel Computing Toolbox >:( Looks like the correct solution is to explicitly push variables into the simulation's model workspace (different than the base workspace), using assignin().

http://www.mathworks.com/matlabcentral/newsreader/view_thread/292544

You have 2 options:

  1. For releases before R2009b, look at the SIMSET documentation. It allows you to set the "SrcWorkspace" property to "current" to use the data from your function.

http://www.mathworks.com/support/solutions/en/data/1-1BWDA/?solution=1-1BWDA

  1. In newer releases, this option is deprecated because it is not compliant with the Parallel Computing Toolbox and PARFOR. What I recommend is:

http://www.mathworks.com/support/solutions/en/data/1-ASPEIV/?solution=1-ASPEIV

Jason S
  • 171,795
  • 155
  • 551
  • 900
2

You can use the evalin() function to execute from your own function a MATLAB expression (as a string) in a specific workspace, in your case the 'base' for SIMULINK to find them. However, if you do not want to use the workspace directly then you can load and save the signals or variables from/to MAT files using the From/To File blocks.

0

Well I don't know how to do it from a simple function, but it's really handy to do it from inside a class function (method). It works fine with version 2009b.

Place the code in file Test.m:

classdef Test < handle
    properties
        mdl
        % Default input signal
        t = [0 1 1 2]'
        u = [0 0 1 1]'
    end

    methods
        function this = Test(mdl)   % Constructor
            this.mdl = mdl;
        end

        function sim(this)
            % Load model
            load_system(this.mdl);
            % Prepare model configuration
            conf = getActiveConfigSet(this.mdl);
            cs = conf.copy();
            set_param(cs, 'StopTime', '4');
            set_param(cs, 'LoadExternalInput', 'on');
            set_param(cs, 'ExternalInput', '[test.t test.u]');  % <-- 1
            % Run simulation
            simout = sim(this.mdl, cs);
            % Plot results
            tout = simout.find('tout');
            yout = simout.find('yout');
            plot(tout, yout(:,1), 'b--');
        end
    end
end

Then just:

>> test = Test('TestSim');
>> test.sim();

What happens? You create object test, that has defined fields t and u. Then in method sim() You say to Simulink to look for input '[test.t test.u]'. Both Simulink and the method sim() has access to this variables (I believe this is the most important thing).

OK it still has a big drawback that is marked with number 1. You have to know explicitly how a reference to class instance will be named in the workspace ('test' in this case). You can work it around by passing the name in a constructor, or you can use static variables and methods, but this way won't allow you to change input signal dynamically.

Golmar
  • 276
  • 2
  • 3
  • Hmm, this appears elegant at first but I'm pretty sure that the Test object would still have to be in the base workspace - so this just changes the location of the OP's problem. Also, a tip: Be careful naming things "XXXXtest" or "textXXXX" - you'll run into problems with the unittest framework, which will pick up class files named in this fashion as unit test cases. – thclark Aug 20 '16 at 13:53
0

Short answer: No.

I could be wrong, but let me give you some background. I work on a Simulink model that is very large, we have been working on it for years. To this day we still load all necessary variables in through the workspace. This has been a complaint of mine for a long time, so much that MathWorks has even addressed the issue by providing the Simulink.save_vars function. It sounds like you are already setting up variables with a script/function, so Simulink.save_vars won't be much use to you.

You can clean up the workspace by using structures for some of the variables, most Simulink blocks don't support structures, but some do. Also, avoid putting anything in the workspace other than variables that your model needs.

Peter Mortensen
  • 28,342
  • 21
  • 95
  • 123
Miebster
  • 2,265
  • 4
  • 20
  • 26