在 Matlab 或 Octave 中使用 fzero,避免循环和复杂的解决方案

Using fzero in Matlab or Octave, avoiding for loop and complex solutions

我正在使用 fzero 函数根据一个参数求解非线性方程 我对我的方法不满意。我有这些问题:

1) 是否可以避免参数的for循环?

2) 为了避免复杂的解决方案,我首先必须预先计算 fzero 的有效间隔。 这里有更好的解决方案吗?

如果我减小参数步长,执行时间就会变慢。如果我不预先计算 我收到错误的时间间隔 "Function values at interval endpoints must be finite and real." 在 Matlab 中,"fzero: not a valid initial bracketing" 在 Octave 中。

这是代码

% solve y = 90-asind(n*(sind(90-asind(sind(a0)/n)-y)))

% set the equation paramaters
n=1.48; a0=0:0.1:60;

% loop over a0
for i = 1:size(a0,2)

  % for each a0 find where the argument of outer asind() 
  % will not give complex solutions, i.e. argument is between 1 and -1 

  fun1 = @(y) n*(sind(90-asind(sind(a0(i))/n)-y))-0.999;
  y1 = fzero(fun1,[0 90]);  
  fun2 = @(y) n*(sind(90-asind(sind(a0(i))/n)-y))+0.999;
  y2 = fzero(fun2,[0 90]);


  % use y1, y2 as limits in fzero interval

  fun3 = @(y) 90-asind(n*(sind(90-asind(sind(a0(i))/n)-y)))-y;
  y(i) = fzero(fun3, [y1 y2]);

end

% plot the result
figure; plot(y); grid minor;
xlabel('Incident ray angle [Deg]');
ylabel('Lens surface tangent angle');

使用 Matlab,我通过以下简化循环获得了下图。

for i = 1:size(a0,2)
  fun3 = @(y) sind(90-y) - n*(sind(90-asind(sind(a0(i))/n)-y));
  y(i) = fzero(fun3, [0,90]);
end

区别在于方程的形式:我用 sin(90-y) = something 替换了 90-y = asind(something)。当"something"的绝对值大于1时,旧版本会因为asind为复数而报错。后者正常进行,认识到这不是解决方案(sin(90-y) 不能等于大于 1 的值)。

不需要预先计算括号,[0,90] 就可以了。我所做的另一个更改是在情节中:plot(a0,y) 而不是 plot(y),以获得正确的水平轴。

并且您无法避免 for 循环,您也不用为此担心。向量化意味着消除循环,其中内容是可以通过对某些 C 数组进行操作来 大量 完成的低级操作。但是 fzero 完全不是那样。如果代码需要很长时间才能达到 运行,那是因为求解一堆方程需要很长时间,而不是因为有一个 for 循环。