避免在 matlab 函数中求值
Avoiding eval in matlab function
我使用matlab中的符号工具箱来生成一些很长的符号表达式。然后我使用 matlabFunction 生成一个函数文件。
假设有三个参数:p1、p2 和 p3。
我有一个包含字符串 {'p1'、'p2'、'p3'} 的单元格。
在模型的推导中,我在循环中使用 eval 从中生成符号变量 p1、p2 和 p3,并将它们堆叠在向量 par 中。
然后在 matlabFunction 中,我指定 par 作为输入。
此外,我将单元格字符串保存在 .mat 文件中。
然后当我想模拟这个模型时,我可以使用 .mat 文件中的 30 个可用参数及其值中的那个字符串单元格构造这个参数数组。
优点:如果我将一个参数添加到 .我可以改变顺序,乱七八糟,但旧型号仍然有效。
坏处:
把东西转成函数文件导致这个错误(psi是参数之一):
错误:文件:f_derive_model.m 行:96 列:5
"psi" 以前似乎用作函数或
命令,与它在这里作为一个名称的使用相冲突
多变的。
此错误的可能原因是您忘记了
初始化变量,或者你已经初始化了它
隐式使用 load 或 eval.
显然正在进行一些不必要的检查,因为变量将在 eval 语句中初始化。
问题:如何避免 eval 但保持参数列表独立于模型内容。
推导长方程的代码:
% Model parameters
mdl.parameters = {'mp','mb','lp','lb','g','d','mP','mM','k','kt'};
par = [];
for i=1:length(mdl.parameters)
eval(strcat(mdl.parameters{i}, '=sym(''', mdl.parameters{i}, "');"));
eval(sprintf(['par = [par;' mdl.parameters{i} '];']));
end
%% Calculate stuff
matlabFunction(MM,'file',[modelName '_mass'],'vars',{par},'outputs',{'M'});
使用生成文件的代码:
getparams
load('m3d_1')
par = [];
for i=1:length(mdl.parameters)
eval(sprintf(['par = [par;params.' mdl.parameters{i} '];']));
end
看看如何,只要我指定正确的值,例如 params.mp,它总是被分配给与 par 向量中的符号变量 mp 对应的输入。我不想丢失它并且必须跟踪顺序等等,我也不想用所有参数一个一个地调用我的函数。
实际上,即使 "public opinion" 确认最好避免使用 eval
函数,我也认为您的方法没有任何问题。另一种方法是使用 assignin 函数,如下所示:
% use 'caller' instead of 'base' if this code runs within a function
for i = 1:numel(mdl.parameters)
var_name = mdl.parameters{i};
assignin('base',var_name,sym(var_name));
end
在第二种情况下(关于 par
变量的情况)我会改用 getfield 函数:
par_len = numel(mdl.parameters);
par = cell(par_len,1);
for i = 1:par_len
par{i} = getfield(params,mdl.parameters{i});
end
或者,或者,这种方法:
par_len = numel(mdl.parameters);
par = cell(par_len,1);
for i = 1:par_len
par{i} = params.(mdl.parameters{i});
end
我使用matlab中的符号工具箱来生成一些很长的符号表达式。然后我使用 matlabFunction 生成一个函数文件。 假设有三个参数:p1、p2 和 p3。 我有一个包含字符串 {'p1'、'p2'、'p3'} 的单元格。 在模型的推导中,我在循环中使用 eval 从中生成符号变量 p1、p2 和 p3,并将它们堆叠在向量 par 中。 然后在 matlabFunction 中,我指定 par 作为输入。 此外,我将单元格字符串保存在 .mat 文件中。
然后当我想模拟这个模型时,我可以使用 .mat 文件中的 30 个可用参数及其值中的那个字符串单元格构造这个参数数组。
优点:如果我将一个参数添加到 .我可以改变顺序,乱七八糟,但旧型号仍然有效。 坏处: 把东西转成函数文件导致这个错误(psi是参数之一):
错误:文件:f_derive_model.m 行:96 列:5 "psi" 以前似乎用作函数或 命令,与它在这里作为一个名称的使用相冲突 多变的。 此错误的可能原因是您忘记了 初始化变量,或者你已经初始化了它 隐式使用 load 或 eval.
显然正在进行一些不必要的检查,因为变量将在 eval 语句中初始化。
问题:如何避免 eval 但保持参数列表独立于模型内容。
推导长方程的代码:
% Model parameters
mdl.parameters = {'mp','mb','lp','lb','g','d','mP','mM','k','kt'};
par = [];
for i=1:length(mdl.parameters)
eval(strcat(mdl.parameters{i}, '=sym(''', mdl.parameters{i}, "');"));
eval(sprintf(['par = [par;' mdl.parameters{i} '];']));
end
%% Calculate stuff
matlabFunction(MM,'file',[modelName '_mass'],'vars',{par},'outputs',{'M'});
使用生成文件的代码:
getparams
load('m3d_1')
par = [];
for i=1:length(mdl.parameters)
eval(sprintf(['par = [par;params.' mdl.parameters{i} '];']));
end
看看如何,只要我指定正确的值,例如 params.mp,它总是被分配给与 par 向量中的符号变量 mp 对应的输入。我不想丢失它并且必须跟踪顺序等等,我也不想用所有参数一个一个地调用我的函数。
实际上,即使 "public opinion" 确认最好避免使用 eval
函数,我也认为您的方法没有任何问题。另一种方法是使用 assignin 函数,如下所示:
% use 'caller' instead of 'base' if this code runs within a function
for i = 1:numel(mdl.parameters)
var_name = mdl.parameters{i};
assignin('base',var_name,sym(var_name));
end
在第二种情况下(关于 par
变量的情况)我会改用 getfield 函数:
par_len = numel(mdl.parameters);
par = cell(par_len,1);
for i = 1:par_len
par{i} = getfield(params,mdl.parameters{i});
end
或者,或者,这种方法:
par_len = numel(mdl.parameters);
par = cell(par_len,1);
for i = 1:par_len
par{i} = params.(mdl.parameters{i});
end