任务:有一个分段函数,求解其中一段的反函数,该段对应的公式已知
这段是单增的,原函数:
将原函数编辑入matlab,调用finverse求解:
syms a b r; %定义变量
a=0.25;
b=0.2;
maxv=1.+a;
g(r)=r-(a/(b-a)^2)*((b-sqrt(b^2+(a-b)*(r+b-1)))^2); %函数公式
fplot(g,[0.8,maxv]); %绘制
m = finverse(g, r) %求解反函数
fplot(m,[0.8,maxv]); %绘制
得到反函数公式:
反函数绘制:
就很奇怪啊,单增函数的反函数一定是单增的呀,应该是关于y=x对称的结果。
后来发现原函数在分段函数的这段范围里 虽然是单增的,但其实总体画出来并不是的:(matlab对于求解反函数结果并不唯一的已经不提示了)
所以matlab求解的其实是1.5-2.5的那部分,而不是我想要的前面单增的部分。
我试了设置自变量r的范围,让它只保留单增的部分:
assume(r < 1+a);
assumeAlso(r > 1-b);
但是没有用。
后来解决方法:
一、更改公式
我本身知道这是二次贝塞尔曲线,联想二次函数求解的两个结果,把公式改了一下,也就是图示这里改成了减号。
ok,好运的解决了:
验证:
fg=compose(g,g_inverse);%测试再次带入后是否为线性
fplot(fg,[0.8,maxv]);
反函数再代入原函数,结果是线性图,就表示正确了。
二、solve求解方程
不用finverse求反函数,直接用solve去求解函数,这样适用于逆向得到单值的情况:
syms r;
a=0.25;
b=0.2;
eqn = r-(a/(b-a)^2)*((b-sqrt(b^2+(a-b)*(r+b-1)))^2) == 0.8; %待求解方程式 结果为0.8时r为多少
S = solve(eqn,r)
如果原函数不是单调的,S求出来可能是多值。
如果for调用这个函数,应该也能绘出曲线。
三、反向绘制后拟合
把r代入原函数,求出两列数组:自变量和因变量。
然后交换,用matlab的拟合函数去拟合得到公式。
牺牲精度但应该可以解决复杂公式的问题。
四、查表法和正向逼近法
如果公式复杂,但是函数内变量单一,可以正向调用函数得到一系列结果,都保存下来。需要反向调用的时候去查表就可以了。
如果不考虑速度的话,还可以用正向逼近法,相当于对于每个f(r),依次尝试r直到足够接近:
syms r
a=0.25;
b=0.2;
g(r)=(r-(a/(b-a)^2)*((b-sqrt(b^2+(a-b)*(r+b-1)))^2));
Longitudinal = (1-b):0.00001:(1+a);
lateral = zeros(1,size(Longitudinal ,2));
for i = 1:1:size(Longitudinal ,2)
for temp=(1-b):0.001:(1+a)%一次次尝试
if g(temp) - Longitudinal(i) < 10^-4 %接近目标值时保存
lateral(i) = temp;
end
end
end
fplot(g,[(1-b),(1+a)]);
plot(Longitudinal,lateral);
运行速度贼慢,还可以改成二分法逼近,更快一些。