How to use Cell array as block parameter using setBlockParameter in Simulink?

조회 수: 33 (최근 30일)
I apologize if this has be answered before, but I couldn't find anything. I could be using the wrong phrasing to search.
I have a version of the EV example model that comes with the 2022b version of MATLAB. I have my own drive cycles that I would like to run in it. I have those drive cycles in a cell array in the workspace. If I run each cycle one at a time using button simulation commands it works, but if I use the sim commands in a for loop I get an error.
Here is how I currently am doing it:
load_system('EVModel');
param1 = CycleCell{1};
set_param('EVModel/Drive Cycle Source', 'cycleVar', 'Workspace variable');
set_param('EVModel/Drive Cycle Source', 'wsVar', 'param1');
simOut = sim("EVModel");
That code works fine, but the problem is that I have a few hundred cycles to run so I would like to do it in a loop.
Here is what I am trying:
model = 'EVModel';
load_system(model);
simIn(1:length(CycleCell)) = Simulink.SimulationInput(model);
for i = 1:length(CycleCell)
param = CycleCell{i};
simIn(i) = simIn(i).setBlockParameter('EVModel/Drive Cycle Source', 'cycleVar', 'Workspace variable');
simIn(i) = simIn(i).setBlockParameter('EVModel/Drive Cycle Source', 'wsVar', 'param');
end
simOut = parsim(simIn);
For this code I keep getting the error: "Warning: One or more simulations completed with errors. For more information, inspect the
SimulationOutput objects at these indices:".
and in the SimulationOutput object it has: "Error in '<a href="matlab:open_and_hilite_hyperlink ('EVModel/Drive Cycle Source','error')">EVModel/Drive Cycle Source</a>': Failed to evaluate mask initialization commands.Caused by: Dot indexing is not supported for variables of this type."
I cannot find what I am doing wrong. If this is possible, there must be something that I am missing. Also, I do have the Parallel Computing Toolbox.
Any ideas what is wrong?

채택된 답변

Paul
Paul 2023년 3월 17일
편집: Paul 2023년 3월 17일
Hi David-ucr,
I don't have 2022b and can't find EVModel in 2022a, so can't test. I also couldn't find it on the 2022b Simulink examples page, maybe it comes with a specific blockset?
I think the problem is that parsim basically runs each instance of the simulation in its own little world on each worker, and there is no variable named 'param' in the workspace of the little world. In contrast, when you run the single simulation code, the variable param1 is found by Simulink in the base workspace.
For the workflow you've defined, and assuming that each element of CycleCell is scalar number (again, I can't check because I don't have EVModel), the solution, I think, is to change the second simin assignment to:
simIn(i) = simIn(i).setBlockParameter('EVModel/Drive Cycle Source', 'wsVar', num2str(CycleCell{ii}));
which basically hard-codes the value of each parameter.
Or, use setVariable
param = CycleCell{i};
simIn(i) = simIn(i).setBlockParameter('EVModel/Drive Cycle Source', 'cycleVar', 'Workspace variable');
simIn(i) = simIn(i).setBlockParameter('EVModel/Drive Cycle Source', 'wsVar', 'param');
simIn(i) = simIn(i).setVariable('param',param,'Workspace',model);
Or, if each element of CycleCell is not a scalar number, then maybe this will work
simIn(i) = simIn(i).setBlockParameter('EVModel/Drive Cycle Source', 'wsVar', ['CycleCell{',int2str(ii),'}']);
The parsim command would then be
simOut = parsim(simIn,'TransferBaseWorkspaceVariables','on');
This will transfer CycleCell, and every other variable in the base workspace!, to the little world of each worker, so that the block parameter CycleCell{1}, etc. can be evaluated in each simulation.
If none of these are acceptable, please provide more insight into what's contained in CycleCell, and also a link to the 2022b doc page for EVModel.
  댓글 수: 6
Paul
Paul 2023년 3월 18일
편집: Paul 2023년 3월 18일
If I'm following, it seems to me the only way that your results would happen is if, as you say, param was hanging around in the base workspace after the for loop completed, and you either used sim or you used parsim and but parsim couldn't connect to a parallel pool and ran serially in the base workspace. I just don't see how you'd get that result if not connected to the base workspace, as would be the case if actually using a parpool. However, when I ran with a parpool, I ran into different problems (the simulation wouldn't even run), which lead me to ....
The block Drive Cycle Source is a masked subsystem. It appears the either mask parameters or mask initialization code or both don't play nicely with simIn.Variables. It seems like a similar issue discussed in this thread where Rahual Kumar (who I can't find with an @) stated: "Variables specified on the SimulationInput object are not available in model or block callbacks." Seems like a similar issue is happening here with a mask where simIn.Variables are not available when the mask is first initialized. Needless to say, the documentation is nonexistent on this issue as far as I can tell.
As discussed in the linked thread, the (or a) solution is to use the PreSimFcn to define the variable param in the base workspace of the worker (or in the Matlab base workspace if using sim). This code worked for me
CycleCell{1} = [0:10; 0:10].';
CycleCell{2} = [0:10; (0:10)*2].';
CycleCell{3} = [0:10; (0:10)*3].';
% mysim1 is Drive Cycle Source connected to a To Workspace
model = "mysim1";
load_system(model);
blockname = "Drive Cycle Source";
blk = model + "/" + blockname;
% here I retrieved the mask paramters to make sure they were the default
% values, which should be 'FTP75' anda 0x0 empty char array
get_param(blk,'cycleVar')
get_param(blk,'wsVar')
simIn(1:3) = Simulink.SimulationInput(model);
for ii = 1:3
param = CycleCell{ii};
% I tried different ways to setBlockParameter. They all worked.
% simIn(ii) = simIn(ii).setBlockParameter(blk, 'cycleVar', 'Workspace variable');
% simIn(ii) = simIn(ii).setBlockParameter(blk, 'wsVar', 'param');
% simIn(ii) = simIn(ii).setBlockParameter(blk, 'wsVar', 'param');
% simIn(ii) = simIn(ii).setBlockParameter(blk, 'cycleVar', 'Workspace variable');
simIn(ii) = simIn(ii).setBlockParameter(blk, 'cycleVar', 'Workspace variable', blk, 'wsVar','param');
simIn(ii) = simIn(ii).setVariable('param',param,'Workspace',model);
% Here I define the PreSimFcn. See doc for details. I think this
% function runs before anything else, including loading mysim1 into
% the worker. At a minimum, I think it must run before the Drive Cycle Source mask is
% initialized for the first time.
% simIn is automatically passed as the input to the function. All this function
% does is take the value of the first
% variable in simIn.Variables, which has the value of param from the loop, and
% assign that value to a variable named param in the base workspace of the
% worker. It will also assing in the Matlab base workspace if using sim
% instead of parsim.
simIn(ii) = simIn(ii).setPreSimFcn(@(in) assignin('base','param',in.Variables(1).Value));
end
% Here I cleared param to make sure it couldn't affect anything.
clear param
simout = parsim(simIn);
simout had my expected output from each of the three simulations.
David-ucr
David-ucr 2023년 3월 18일
@Paul This is the answer! It worked! Thank you! Everything I could think to check to make sure it is working checked out.

댓글을 달려면 로그인하십시오.

추가 답변 (0개)

카테고리

Help CenterFile Exchange에서 Simulink Functions에 대해 자세히 알아보기

제품


릴리스

R2022b

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!

Translated by