Change for loop stepsize

17 次查看(过去 30 天)
Harry Gover
Harry Gover 2020-2-5
编辑: Stephen23 2020-2-5
I am relativley new to programming and only really use MATLAB at university so feel like there is a very simple solution I am missing.
For part of my dissertation I am simulating a phase shift error and measuring the effect this has on a distance measurement model. I am trying to change the increment "stepsize" by a factor of 10 so that it takes ten measurements between each order of magnitude.
Any help would be greatly appreciated, thanks in advance.
limit = 1;
stepsize = 0.00000000001;
for dm = 1:1:32
tic
d = dm/10;
rem = [mod(d,wavelround(1)),mod(d,wavelround(2)),mod(d,wavelround(3))]; %Remainder of wave used to calculate phase shift
phaseshift = [(rem(1)/wavelround(1))*360,(rem(2)/wavelround(2))*360,(rem(3)/wavelround(3))*360]; %Phase shift
for phaseerror = 0:stepsize:limit
phasepluserror = phaseshift+phaseerror;
phaseminuserror = phaseshift-phaseerror;
phasefractionplus = [phasepluserror(1)/360,phasepluserror(2)/360,phasepluserror(3)/360]; %Fraction of wave from phase shift
phasefractionminus = [phaseminuserror(1)/360,phaseminuserror(2)/360,phaseminuserror(3)/360]; %Fraction of wave from phase shift
mplus = [phasefractionplus(1)*P(1),phasefractionplus(2)*P(2),phasefractionplus(3)*P(3)]; %fractional component of distance
mminus = [phasefractionminus(1)*P(1),phasefractionminus(2)*P(2),phasefractionminus(3)*P(3)];
xplus = delta(1)*mplus(1)+delta(2)*mplus(2)+delta(3)*mplus(3); %Dividend for modulo arithmetic
xminus = delta(1)*mminus(1)+delta(2)*mminus(2)+delta(3)*mminus(3);
xmodplus = mod(xplus,M); %Modulo Arithmetic
xmodminus = mod(xminus,M);
distanceplus = xmodplus*u; %Remainder is distance value
distanceminus = xmodminus*u;
if phaseerror == 0
disstruct(dm).ActualDistance = d;
disstruct(dm).Error = phaseerror;
disstruct(dm).DistancePlusError = distanceplus;
disstruct(dm).DistanceMinusError = distanceminus;
else
disstruct(dm).ActualDistance = [disstruct(dm).ActualDistance;d];
disstruct(dm).Error = [disstruct(dm).Error;phaseerror];
disstruct(dm).DistancePlusError = [disstruct(dm).DistancePlusError;distanceplus];
disstruct(dm).DistanceMinusError = [disstruct(dm).DistanceMinusError;distanceminus];
end
if phaseerror == 0.0000000001||0.000000001||0.00000001||0.0000001||0.000001||0.00001||0.0001||0.001||0.01||0.1
stepsize = stepsize*10;
disp(num2str(stepsize));
elseif phaseerror == 1
stepsize = 0.00000000001;
end
end
toc
end

回答(3 个)

Stephen23
Stephen23 2020-2-5
编辑:Stephen23 2020-2-5
This syntax does not do what you think it does:
phaseerror == 0.0000000001||0.000000001||0.00000001||0.0000001||0.000001||0.00001||0.0001||0.001||0.01||0.1
As the documentation explains, logical operators are binary functions. We also know that equal-level operators are evaluated from left to right (just like in mathematics), so what you wrote is equivalent to (I added parentheses to help you):
((...(((phaseerror == 0.0000000001) || 0.000000001) || 0.00000001) ... ) || 0.1
which becase each of the values (except possibly the first comparison) is non-zero, is exactly equivalent to
((...(((phaseerror == 0.0000000001) || true) || true) ... ) || true
which clearly simplfies down to
(phaseerror == 0.0000000001) || true
which is clearly just
true
In any case, testing for equivalence of floating point numbers is not recommended (search this forum for "binary floating point error" to know why). You need to allow for the accumulated floating point error. I don't know what magnitude your data are, but judging by the stepsize you need to pay very careful attention to eps and ensure that your operations are numerically stable (e.g. no subtraction of similar values, etc.).
Note that your code can be simplified by using basic MATLAB indexing and arrays more effectively: everywhere you access one-element-at-a-time followed by concatenation you should simply refer to multiple elements at once. I.e. instead of this
[mod(d,wavelround(1)),mod(d,wavelround(2)),mod(d,wavelround(3))]
you just need
mod(d,wavelround(1:3))
and similarly for all the rest of your code.
To avoid inefficient code and some pointless bugs you should preallocate the output array before the loop:
You might also find this useful:

Jakob B. Nielsen
Jakob B. Nielsen 2020-2-5
编辑:Jakob B. Nielsen 2020-2-5
I think, when you create the for phaseerror = 0:stepsize:limit loop, you have already determined your increment - you cannot change this from inside the loop.
Off the top of my head, I would make a function that does all your bread and butter work, with whatever value you want evalutated.
Then - since you know how many times you want the loop to run in total, you could do it like this? I do
itevalue=0;
stepsize=0.00000000001;
for i=0:100
allyourdata=yourfunction(itevalue) %so you basically place your entire thing contained in your current "for phaseerror = 0:stepsize:limit" loop and place in a subfunction
itevalue=i*stepsize; %increment by stepsize every loop iteration
if i==10 || i == 20 || i == 30 % and so on, up to i=90, so you up your stepsize every 10 runs. (You have to specify the i== condition each time)
stepsize=stepsize*10; %
end
end
Edit: or what Stephen said, it is probably much wiser ;)

Steven Lord
Steven Lord 2020-2-5
Rather than computing the elements yourself by repeated multiplication consider looping over a vector created using the logspace function.
format longg % Change how the vector is displayed, not how the numbers are calculated or stored
x = logspace(0, -5, 6)
for k = x
fprintf('%g is 10^(%d)\n', k, log10(k))
end

类别

Help CenterFile Exchange 中查找有关 Logical 的更多信息

标签

产品


版本

R2019b

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!

Translated by