Only the first if-statement block executes,
6 次查看(过去 30 天)
显示 更早的评论
Hi there!
I wrote an if-statement, followed by an if-else statement, followed by another if-else statement, followed by the end keyword.
The goal is to use different formulas for different values of alpha, something like the below.
However, it seems that only the first if-statement block executes -- for all possible values of alpha, even when alpha already exceeds that interval.
Where is my mistake? Thanks in advance.
alpha = linspace(0,3*pi/2,1000)
if 0 <= alpha <= pi/2
vx = ...;
vy = ...;
elseif pi/2 < alpha <= pi
vx = ...;
vy = ...;
elseif pi < alpha <= 3*pi/2
vx = ...;
vy = ...;
end
采纳的回答
Walter Roberson
2024-10-3
编辑:Walter Roberson
2024-10-3
if 0 <= alpha <= pi/2
MATLAB interprets that as
if ((0 <= alpha) <= pi/2)
the first part, 0 <= alpha, produces a logical value, 0 or 1.
The second part compares that 0 or 1 to pi/2 and finds that 0 or 1 is always less than pi/2 so the overall test always succeeds.
MATLAB is not defined as chaining operations. In practice, chaining operations like you show is permitted in Symbolic Mathematics contexts, especially involving the piecewise() operator.
It is safest to always write the expanded version,
if 0 <= alpha && alpha <= pi/2
32 个评论
Steven Lord
2024-10-4
Also note that Code Analyzer will warn you about this construct in sufficiently recent release of MATLAB. If you look at the attached myfun.m:
dbtype myfun.m
1 function y = myfun(x)
2 if 0 <= x <= 2
3 y = 1;
4 else
5 y = 2;
6 end
7 end
issues = codeIssues("myfun.m");
myfun.m has only one Code Analyzer message. You'll have to scroll to the right to see the whole thing.
disp(issues.Issues.Description)
Expressions like a <= b <= c are interpreted as (a <= b) <= c. Typically, to test a <= b <= c mathematically, if all arguments are numeric scalars, use (a <= b) && (b <= c), otherwise use (a <= b) & (b <= c).
Noob
2024-10-4
编辑:Noob
2024-10-4
Hi Steve! I've seen that warning message, but basically ignored it, because other errors were ocurring: It turns out I can't use the && symbol for vectors, since I have alpha = linspace ( ... ), so I used the single & to fix this issue. Then, I applied Walter's answer, which I've known about (Matlab gives the warning message) for a few days but ignored, since I had other errors to fix. Now, I'll all set. Thanks!
Walter Roberson
2024-10-4
When alpha is a vector you need to be careful about
if 0 <= alpha & alpha <= pi/2
This is considered equivalent of
if all(0 <= alpha & alpha <= pi/2)
and only succeeds of all of the alpha are in range.
If you have if/elseif testing vectors, then typically you should be switching to logical indexing:
mask = 0 <= alpha & alpha <= pi/2;
vx(mask) = some computation in alpha(mask)
mask = pi/2 < alpha & alpha <= pi;
vx(mask) = some computation in alpha(mask)
Noob
2024-10-4
编辑:Noob
2024-10-4
Hi Walter,
I'm actually finding that I can only run code for one interval of alpha at a time.
So alpha = linspace(0, pi/2, 100), run code, plot data, hold on, change to alpha = linspace(pi/2 + 1e-10, pi,100), run code, plot data, hold on, etc. works just fine.
However, if I try to run code for the entire alpha = (0, 2*pi, 1001) interval, then the code doesn't run, and I get an error message.
So, I guess I had thought that the role of the else-if statements were to help me not have to manually switch the alpha interval and run my code multiple times.
But it turns out this is not the case.
What do you think the issue is?
In addition to the above attempts, I also tried using a for loop, and a while loop, but neither seems better than just manually changing the alpha interval myself, and running code and plotting code again, which, to me, is a lot faster. But I am guessing there's a way to do this without having to manually switch the intervals.
Thanks!
Walter Roberson
2024-10-4
Pre-allocating:
alpha = linspace(0,3*pi/2,1000);
vx = nan(size(alpha));
vy = nan(size(alpha));
Walter Roberson
2024-10-4
mask is a temporary variable. You can use
mask = 0 <= alpha & alpha <= pi/2;
vx(mask) = some computation involving alpha(mask)
vy(mask) = some computation involving alpha(mask)
or you can instead
vx(0 <= alpha & alpha <= pi/2) = some computation involving alpha(0 <= alpha & alpha <= pi/2)
vy(0 <= alpha & alpha <= pi/2) = some computation involving alpha(0 <= alpha & alpha <= pi/2)
repeating the logical computation each time. It is more efficient to do the logical computation only once and store the result in a tempory variable, but it is up to you whether you do that or not.
Noob
2024-10-4
编辑:Noob
2024-10-4
Hi Walter,
This worked beautifully. But I must admit: I don't totally understand why.
Here's my attempt:
mask will bring back 1s and 0s. For the 1s, the computation will execute for the corresponding values of alpha.. For all the alpha's with corresponding values of 0, the computation won't execute.
That is all there is to it.
And, Matlab is happy, because logical indexing is fast, and Matlab doesn't have much more evaluating to do.
Does that sound about right?
Thanks so much, this is a super neat method.
Noob
2024-10-4
Thanks again Walter, and thanks Torsten!
This method is super neat.
Have a great night!
Noob
2024-10-4
Hi Walter,
Do you purposely want to re-use the variable mask, to have it overwritten by the next set of computations for the next interval of alpha values?
Why not use mask1 for one set of alpha, mask2 for another set of alpha, etc.?
Thanks!
Noob
2024-10-4
Hi Walter,
How come re-using mask doesn't cause the calculations to be overwritten and lost?
Instead, the calculations are all kept, and plotted nicely.
I would guess to use mask1, mask2, etc. but that seems not necessary.
Thanks!
Steven Lord
2024-10-4
Can you dynamically create variables with numbered names like x1, x2, x3, etc.? Yes.
Should you do this? The general consensus is no. That Discussions post explains why this is generally discouraged and offers several alternative approaches.
In the case of your code, you don't need to keep all the masks around after you're finished using them for indexing. Use one, throw it away, pick up a new mask, throw it away, etc. In that case reusing the same variable name isn't a problem. Assigning new values to that name (without using indices) throws away the old values.
Walter Roberson
2024-10-4
How come re-using mask doesn't cause the calculations to be overwritten and lost?
You start out with vx and vy all nan.
Then you step case by case, selecting locations in vx and vy according to alpha, and writing to those selected locations.
If somehow you had multiple logical masks matching a single location, then you would overwrite the results at that location. For example if you accidentally coded
mask = -pi < alpha & alpha <= 3*pi/2;
then you would be overwriting previous calculations. But as long as you do not make mistakes in your logical masks, your masks should be disjoint, and nothing should be overwritten.
Walter Roberson
2024-10-7
Certainly.
alpha = linspace(0,3*pi/2,1000);
mask = 0 <= alpha & alpha < pi;
vx = nan(size(mask));
vx(mask) = alpha(mask).^2;
mask = pi <= alpha & alpha < 3*pi/2;
vx(mask) = -alpha(mask);
plot(alpha, vx)
Noob
2024-10-8
Hi Walter,
If vx is some vector quantity, say, a 3x1 column vector for each alpha, then it doesn't work.
Matlab gives the error:
Unable to perform assignment because the left and right sides have a different number of elements.
Walter Roberson
2024-10-8
alpha = linspace(0,3*pi/2,1000);
mask = 0 <= alpha & alpha < pi;
vx = nan(3,length(mask));
vx(:,mask) = [alpha(mask).^2;
alpha(mask).^3 - alpha(mask).^2;
-alpha(mask)];
plot(alpha, vx)
Noob
2024-10-18
编辑:Noob
2024-10-18
Hi Walter,
Could the above logical indexing technique cause issues for ode45?
ode45 solved my equations tonight, but it returned all NaN values.
I suspect there's an issue with using the logical indexing, like the pre-allocating, and stuff.
Not sure ...
Matlab doesn't throw any more error messages, so I did some decent debugging of my code throughout today.
The solutions are just all NaN ...
Noob
2024-10-18
Hi Walter,
It indeed looks like the logical indexing technique is making ode45 return all NaN solutions. When I use a simpler function, without needing logical indexing, the code runs fine, and I get ode solutions for all time. What do you think the issue could be?
Here's a sample of my logical indexing code, for instance:
mask = 0 <= alpha & alpha <= pi/2;
vrelB = nan(3, length(mask));
vrelBxp = nan(size(mask));
vrelByp = nan(size(mask));
vrelB(:,mask) = vrel(:,mask) + (w/2)*omega*jp*ones(1,length(alpha(mask)));
vrelBxp(:,mask) = dot(vrelB(:,mask), ip*ones(1,length(alpha(mask))));
vrelByp(:,mask) = dot(vrelB(:, mask), jp*ones(1,length(alpha(mask))));
And I write this sort of code until alpha = 2*pi.
I made beautiful figures with this technique.
However, now I want to solve equations, using ode45, and the above technique is now causing issues. I wonder if solutions are just being overwritten or something ...
Noob
2024-10-18
Hi Walter,
The above function, using logical indexing, is in a function file.
Then I use anonymous functions to pass the above function into ode45.
Matlab doesn't throw any errors, but all the solutions returned are NaN.
Walter Roberson
2024-10-19
The mathematics used for all of the ode*() variable-step solvers requires that the implementation is continuous to the second derivative (the functions for internal Jacobians.) If your implementation is not continuous to the second derivative, then if you are lucky ode45() returns an error about not being able to resolve at a particular time. If you are not lucky then ode45() does not notice and silently produces wrong answers.
If you are using logical indexing in your ode45 function implementation, then chances are high that the implementation is not continuous to the second derivative.
Generally speaking, you need to use event functions to detect discontinuities (up to the second derivative) and signal termination; then you restart ode45() at the terminal state of the previous ode45() call.
In the case where the discontinuities are predictable completely by time, instead of using event functions, you can instead control the tspan parameter.
Noob
2024-10-19
编辑:Noob
2024-10-19
Hi Walter,
Would switching to if / elseif statements be a better implementation for ode45?
I tried, but the code doesn't even run; I get an unrecognized variable error message from Matlab.
From the figures I made (using logical indexing), I do notice some corner points at alpha = pi/2 and 3pi/2; this is likely where the function is not differentiable. If my suspicions are true, how could I circumvent this issue of non-differentiability at these two points?
Thanks!
Walter Roberson
2024-10-19
Switching to if/elseif will not help. The implementation is either twice differentiable or it is not.
There are two fundamental strategies to deal with this situation:
- Carefully construct the implementing code so that it is twice differentiable at each boundary condition. This might involve using bridge equations near the boundary conditions to match the second derivative
- Use event functions to detect the discontinuities and terminate ode45() at the boundary conditions, and then resume ode45() from where you left off
When there are boundaries at multiples of then it is common for the equations to discontinuous on the first or second derivative; the cases that are continuous tend not to need conditional logic to express.
Noob
2024-10-19
编辑:Noob
2024-10-19
Hi Walter!
Ok, I guess I have more math modeling work to do now! Let's see what happens. I am guessing I need to learn how to make a sine wave with kinks / corners on it ... smoothed out, so that it is differentiable everywhere. Or, the issue could be a combination of errors. But the non-smooth behavior of my function is very clear, since I plotted many figures first and foremost, before even writing a dynamics code to give to ode45. So, I now need to approximate my non-smooth function with one that is smooth. I'll read up on this, and google around to learn of what techniques are typically used. If you have any advice in this regard, please let me know! I wonder if I can get rid of using conditional logic altogether; at the moment, it seems I am stuck with it.
Thanks so much!
Walter Roberson
2024-10-19
Note that the issue of boundary conditions does not typically itself lead to NaN values being returned. NaN values being returned typically is either due to a mistake in the implementation (such as forgetting the equality test of a boundary condition), or else due to dynamics that "run away" to +/- infinity.
Noob
2024-10-19
编辑:Noob
2024-10-19
What's an equality test?
Do you think my using 0 <= alpha is problematic, and that I should instead use 0 < alpha & alpha == 0?
Also, yes, I found a glaringly obvious error in my equations!
In my equations, I was dividing a vector by another vector; something like 4i + 5j divided by 8i + 10j is nonsensical.
So, I'll work to fix up this issue now.
Walter Roberson
2024-10-19
Suppose that you had
mask = 0 <= alpha & alpha < pi/2;
%some code here
mask = pi/2 < alpha & alpha < pi;
%some code here
then the code would not account for the case of alpha == pi/2 . You need to be careful at the boundaries of your conditions.
更多回答(0 个)
另请参阅
类别
在 Help Center 和 File Exchange 中查找有关 Function Creation 的更多信息
标签
产品
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!发生错误
由于页面发生更改,无法完成操作。请重新加载页面以查看其更新后的状态。
您也可以从以下列表中选择网站:
如何获得最佳网站性能
选择中国网站(中文或英文)以获得最佳网站性能。其他 MathWorks 国家/地区网站并未针对您所在位置的访问进行优化。
美洲
- América Latina (Español)
- Canada (English)
- United States (English)
欧洲
- Belgium (English)
- Denmark (English)
- Deutschland (Deutsch)
- España (Español)
- Finland (English)
- France (Français)
- Ireland (English)
- Italia (Italiano)
- Luxembourg (English)
- Netherlands (English)
- Norway (English)
- Österreich (Deutsch)
- Portugal (English)
- Sweden (English)
- Switzerland
- United Kingdom(English)
亚太
- Australia (English)
- India (English)
- New Zealand (English)
- 中国
- 日本Japanese (日本語)
- 한국Korean (한국어)