Avoiding drift while creating angular rotation with variable degree increments

Hello,
With the following code, I am trying to create a variable "deg" which should have small degree increments (ddeg_min) for deg<=angle and large increments (ddeg_max) for rest of a complete revolution. I want to repeat the same increments after completion of each revolution. For example, the increment should be 0.1 for 0<=deg<=16.0 and it should repeat the same thing after 360 degrees i.e. incr should be 0.1 for 360.1<=deg<=316.0. But, I am getting a drift in values e.g. 16.1 for first revolution and 366.1 for next revolution and so on.
It was hard to explain but I tried to make it as comprehendible as possible. Waiting for your kind suggestions, Thx.
close all
clear all
clc
phi=90;
angle=16;
ddeg_min=0.1;
ddeg_max=10;
deg(1)=0;
d_deg(1)=ddeg_min;
i=1;
while (1)
i=i+1;
revol_n=floor(deg(i-1)/360);
kkk=deg(i-1)-revol_n*360;
if (kkk >= 0 && kkk < angle)
d_deg(i)=ddeg_min;
deg(i)=deg(i-1)+d_deg(i);
else
d_deg(i)=ddeg_max;
deg(i)=deg(i-1)+d_deg(i);
end
if deg(i)>=1070
break
end
end

 Accepted Answer

Let's start with a simplification of the code:
phi = 90;
angle = 16;
ddeg_min = 0.1;
ddeg_max = 10;
deg(1) = 0;
d_deg(1) = ddeg_min;
i = 1;
while deg(i) < 1070
kkk = rem(deg(i), 360);
if kkk < angle
deg(i + 1) = deg(i) + ddeg_min;
else
deg(i + 1) = deg(i) + ddeg_max;
end
i = i + 1;
end
Or:
phi = 90;
angle = 16;
ddeg = [0.1, 10];
deg = 0;
i = 1;
while deg(i) < 1070
deg(i + 1) = deg(i) + ddeg(1 + rem(deg(i), 360) < angle);
i = i + 1;
end
What is the problem now?
"the increment should be 0.1 for 0<=deg<=16.0"
"I am getting a drift in values e.g. 16.1"
Yes, of course. Welcome to the world of numerical maths.
0.1 + 0.1 + 0.1 == 0.3 % FALSE !!!
0.1 + 0.1 + 0.1 - 0.3 % This is 5.551115123125783e-17
Most floating point values cannot be represented accurately as binary numbers. Therefore you have to consider a rounding effekt. Your loop does not stop at the wanted value, because it does not reach 16, but 15.99999999999996. This must be considered either by using a specific range:
if abs(kkk - angle) < 100 * eps(angle)
But in ypour case it is easier to create the output by a constructive apporach:
deg = [0:0.1:16, 26:10:360];
deg = [deg, deg + 360, deg + 720];
deg = deg(deg < 1070);

1 Comment

@Jan Thank you for your reply. I think you got to the root of the problem!
The constructive appraoch you gave seems simple and better. I am trying to implement it for the real case in which I have four 90 degree intervals of small increments in each revoltion i.e. 0:0.1:16, 90:0.1:106, 180:0.1:196 and 270:0.1:286
At the same time, I would love to know how this problem can be addressed the other way i.e. by controling the numerical variations (as you highlighted). It would be great if you could correct my code. tbh I'm not a computational expert, I would like to learn handling such situations.
Thank you once again!

Sign in to comment.

More Answers (1)

hello
why make things so complicated ?
this way you can generate the pattern for the first revolution . if you want to have it for multiple revolutions simply add 360 for each rev
close all
clear all
clc
phi=90;
angle=16;
ddeg_min=0.1;
ddeg_max=10;
% one revolution pattern
deg1 = (0:ddeg_min:angle);
deg2 = (angle+ddeg_max:ddeg_max:360);
deg = [deg1 deg2];

6 Comments

@Mathieu NOE Thanks for your answer.
In actual, there would be more than 1 intervals of small increments in each revolution e.g. 4 at 0,90,180 and 270. I am looking for a generalized approach, I'm not sure if it can be better than this one.
Thanks once again!
hello
you mean in the 0 - 360 range there would be 4 sectors with low increment and 4 sectors with large increment ?
this can be easily adapted using my code example
Yes exactly. Also, I want to keep it generalized i.e. the code should accept the number of sectors as an input.
Thank you.
as simple as this :
ddeg_min=0.1;
ddeg_max=10;
start_points = [0 90 180 270];
angle=16; % angular amplitude for refined resolution
deg = [];
% one revolution pattern
sectors = length(start_points);
for ci = 1:sectors
deg_fine = (start_points(ci):ddeg_min:start_points(ci)+angle);
if ci <= sectors-1
deg_coarse = (start_points(ci)+angle:ddeg_max:start_points(ci+1));
else % last sector (xx to 360)
deg_coarse = (start_points(ci)+angle:ddeg_max:360);
end
tmp = unique([deg_fine deg_coarse]); % remove duplicates
deg = [deg tmp]; % concatenate results for all sectors
end
plot(deg)

Sign in to comment.

Categories

Find more on Mathematics in Help Center and File Exchange

Products

Release

R2021b

Asked:

on 24 Nov 2021

Commented:

on 26 Nov 2021

Community Treasure Hunt

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

Start Hunting!