Change for loop stepsize

12 views (last 30 days)
Harry Gover
Harry Gover on 5 Feb 2020
Edited: Stephen23 on 5 Feb 2020
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

Answers (3)

Stephen23
Stephen23 on 5 Feb 2020
Edited: Stephen23 on 5 Feb 2020
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 on 5 Feb 2020
Edited: Jakob B. Nielsen on 5 Feb 2020
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 on 5 Feb 2020
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

Categories

Find more on Loops and Conditional Statements in Help Center and File Exchange

Tags

Products


Release

R2019b

Community Treasure Hunt

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

Start Hunting!