【问题标题】:Matlab: find specific variable from symbolic expression and/or systemMatlab:从符号表达式和/或系统中查找特定变量
【发布时间】:2013-11-19 12:09:56
【问题描述】:

我有一个由三个符号方程组成的系统:

(1) Ua  = (Un*Ga -ia -(U2 -Ug2)*G3)/Ga;
(2) U2  = (Ug2*G3 -(Uc2m - Ua)*Ca*Fs)/(Ca*Fs + G3);
(3) Ug2 = ((Ua -Uc2m)*Ca*Fs* G3 -ig2*(Ca*Fs + G3)) / ((G3 + Gg2)*(Ca*Fs + G3) - G3*G3);

在 (2) 和 (1) 中替换 (3),然后在 (1) 中替换 (2),我有 (1) 如下:

Ua  = (Un*Ga -ia -((((Ua -Uc2m)*Ca*Fs* G3 -ig2*(Ca*Fs + G3)) / ((G3 + Gg2)*(Ca*Fs + G3) - G3*G3)*G3 -(Uc2m - Ua)*Ca*Fs)/(Ca*Fs + G3) -((Ua -Uc2m)*Ca*Fs* G3 -ig2*(Ca*Fs + G3)) / ((G3 + Gg2)*(Ca*Fs + G3) - G3*G3))*G3)/Ga;

Ua 出现在成员的左侧和右侧。有没有办法(使用 Matlab 或任何其他工具):

  1. 简化左侧只有Ua 的表达式
  2. 从三个符号方程的原始系统开始,自动简化所有方程,指定哪些符号构成三个变量(将出现在左侧),并将其余的作为参数留在右侧。

【问题讨论】:

  • 感谢您的建议。我做了替换,得到了长 (1') 表达式,现在我想简化 (1'),这样右边就没有 Ua,只有参数。
  • 不确定是否有帮助,但您检查过doc simplify 吗?没有matlab你能得到你喜欢的结果吗?
  • 谢谢,simplify 很有用,但是给了我另一个扩展的表达方式,和我有的类似,当然更紧凑,但它是另一个 f(Ua)。我要找的是一个获取像“ax + (b +cx)/(d+e)”这样的表达式并得到“x=f(a,b,c,d)”的方法。可以通过手动求解长而简单的方程来完成,而无需 matlab,但我需要使用不同的长表达式多次重复该过程,因此自动化将很有用并防止最终的黑板错误。
  • 你能展示你的代码,包括解决的调用吗?您是否考虑过增加迭代次数并指出方程需要求解的变量?

标签: variables matlab equation symbolic-math


【解决方案1】:

直觉上我会说只是做solve(expr1, expr2, expr3, 'Ua'),但这似乎不起作用,(至少在 R2010a 上)...

所以我被黑客入侵了。现在,我不是一个符号工具箱的人,所以很可能有一种“更好”的方法来做到这一点。不过,以下函数回答了您的两个问题:

function solution = solveFor(exprs, var)

    %// Split the equations up into the RHS and LHS
    C = regexp(expr, '\s*=\s*', 'split');
    C = cat(1, C{:});

    %// The equation we're solving for 
    kk = find(strcmp(C(:,1), var));

    %// Substitute every expression into every other expression
    for ii = 1:size(C,1)
        if ii==kk, continue; end

        for jj = 1:size(C,1)
            if jj==ii, continue; end

            C{jj,2} = regexprep(C{jj,2}, C{ii,1}, C{ii,2});
        end
    end

    %// Solve for the requested variable & simplify
    solution = simplify(solve([C{kk,1} '=' C{kk,2}], C{kk,1}));

end

这样使用:

>> expr{1} = 'Ua  = (Un*Ga -ia -(U2 -Ug2)*G3)/Ga';
>> expr{2} = 'U2  = (Ug2*G3 -(Uc2m - Ua)*Ca*Fs)/(Ca*Fs + G3)';
>> expr{3} = 'Ug2 = ((Ua -Uc2m)*Ca*Fs*G3 - ig2*(Ca*Fs + G3)) / ((G3 + Gg2)*(Ca*Fs + G3) - G3*G3)'; 
>> Ua = solveFor(expr, 'Ua')
Ua = 
    -(G3*Gg2*ia - G3*Ga*Gg2*Un + Ca*Fs*G3*ia + Ca*Fs*G3*ig2 + Ca*Fs*Gg2*ia - Ca*Fs*G3*Gg2*Uc2m - Ca*Fs*G3*Ga*Un - Ca*Fs*Ga*Gg2*Un)/(G3*Ga*Gg2 + Ca*Fs*G3*Ga + Ca*Fs*G3*Gg2 + Ca*Fs*Ga*Gg2)

明显的限制:

  • 所有方程必须采用上述形式,例如,'single variable = expression'
  • 方程必须以字符串形式给出,因此不能作为其他符号运算的结果(尽管在顶部使用 expr = cellfun(@char, expr, 'UniformOutput', false); 会取消该限制)

编辑

solve 的调用具有以下语法:

S = solve(expr{:}, 'Ua,U2,Ug2');

因此,要自动化该过程,您可以将上面的函数修改为以下更简单的形式:

function solution = solveFor(exprs, var)

    %// Syms or strings?
    if ~iscellstr(exprs) && all(cellfun('isclass', exprs, 'sym'))
        exprs = cellfun(@char, expr, 'UniformOutput', false); 
    else
        error(...);
    end

    %// Split the equations up into the RHS and LHS
    C = regexp(expr, '\s*=\s*', 'split');
    C = cat(1, C{:});

    %// Solve for the requested variables
    vars = cellfun(@(x)[x ','], C(:,1), 'UniformOutput', false);
    vars = [vars{:}];
    solution = solve(expr{:}, vars(1:end-1));

    %// Extract desired solution
    solution = simplify(solution.(var));

end

【讨论】:

  • 太好了!这正是我想要的。第一个实现效果很好,而第二个实现则返回错误“未定义函数 'simplify' 用于 'struct' 类型的输入参数”。非常感谢!
  • @user2374511:是的,我的错。已更正。
  • @horchler:好吧,至少不是这个问题的方程式以及我的答案顶部显示的对solve 的调用。顺便说一句,这在我稍后验证的 R2013a 上也不起作用。指定要解决的 3 个变量,然后稍后在 does 工作(我编辑后的位)选择正确的解决方案。
【解决方案2】:

我不确定在这种情况下是否需要 @RodyOldenhuis 的所有辛勤工作。这只是正确使用solve 的问题。当您提供 N 个方程时,通常最好要求它解决您自己选择的 N 个变量(不指定任何变量名称):

syms Ua Ug2 U2 ia Un Ga G3 Uc2m Ca Fs ig2 Gg2
eqs = [Ua == (Un*Ga -ia -(U2 -Ug2)*G3)/Ga
       U2 == (Ug2*G3 -(Uc2m -Ua)*Ca*Fs)/(Ca*Fs + G3)
       Ug2 == ((Ua -Uc2m)*Ca*Fs*G3 -ig2*(Ca*Fs + G3)) / ((G3 + Gg2)*(Ca*Fs + G3) -G3*G3)];

s = solve(eqs,Ua,U2,Ug2)

然后s.Ua 返回

-(G3*Gg2*ia - G3*Ga*Gg2*Un + Ca*Fs*G3*ia + Ca*Fs*G3*ig2 + Ca*Fs*Gg2*ia - Ca*Fs*G3*Gg2*Uc2m - Ca*Fs*G3*Ga*Un - Ca*Fs*Ga*Gg2*Un)/(G3*Ga*Gg2 + Ca*Fs*G3*Ga + Ca*Fs*G3*Gg2 + Ca*Fs*Ga*Gg2)

不要错误地将UaU2Ug2 作为向量传递给solve(除非您使用的是 R2015a+,我相信)。

这也适用于旧的基于字符串的技术(如果需要,可以用单个字符串输入替换元胞数组):

eqs = {'Ua = (Un*Ga -ia -(U2 -Ug2)*G3)/Ga'
       'U2 = (Ug2*G3 -(Uc2m -Ua)*Ca*Fs)/(Ca*Fs + G3)'
       'Ug2 = ((Ua -Uc2m)*Ca*Fs*G3 -ig2*(Ca*Fs + G3)) / ((G3 + Gg2)*(Ca*Fs + G3) -G3*G3)'};

s = solve(eqs{:},'Ua','U2','Ug2')

这适用于 R2013a 和 R2015a。我不知道旧版本是否可以处理。

【讨论】:

  • 你是对的,我在 R2012a 上测试了你的两个解决方案,它们在没有任何脚本的情况下工作正常。谢谢!
  • @Freakk: ...我以为你想要自动提取变量,所以你只需要指定你感兴趣的变量(在这种情况下是Ua)。在二读时,我不知道我为什么这么认为:)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2019-02-21
  • 2012-02-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-06-16
相关资源
最近更新 更多