14 views (last 30 days)

Hi,

I am really stuck trying to figure out how to fit a circle to some data points. I have watched plenty of videos on the topic but do not really understand. Could you please explain to me in the most simple way how to plot some random data points, for example x = [2; 3; -2; 1]; and y = [3; 2; 4; -1];, in matlab?

I have only come up with the following but do not know how to proceed:

x = [2; 3; -2; 1];

y = [3; 2; 4; -1];

N = length(x);

% circle's equation x^2+y^2 = 2xc1+2yc2+c3

X = [ones(N,3),x];

Y=y;

phi = inv(X'*X)*X'*Y

plot(x,y,'*')

Thanks alot in advance!

Adam Danz
on 9 Dec 2019

Edited: Adam Danz
on 9 Dec 2019

Create noisy circular data

This section creates the noisy data we're fitting.

% Create randome points along a circle

r = 22.52; % radius

cnt = [9.923, -2.42]; % (x,y) center

theta = rand(1,1000)*2*pi; % Theta

xData = r*cos(theta)+cnt(1); % x coordinates

yData = r*sin(theta)+cnt(2); % y coordinates

% Add noise to coordinates

xData = xData + (rand(size(xData))*10-5);

yData = yData + (rand(size(yData))*10-5);

Plot the input data

The only inputs are xData and yData. The rest of the variables above are unknowns.

% Plot the data with noise

clf()

plot(xData, yData, 'ko')

axis equal

grid on

Fit the xData,yData coordinates to a circle

This section uses nonlinear least squares fitting x = lsqnonlin(fun,x0). The first line defines the function to fit and is the equation for a circle. The second line are estimated starting points. See the link for more info on this function. The output circFit is a 1x3 vector defining the [x_center, y_center, radius] of the fitted circle.

f = @(a) (xData-a(1)).^2 + (yData-a(2)).^2 - a(3).^2;

a0 = [mean(xData),mean(yData),max(xData)-mean(xData)];

circFit = lsqnonlin(f,a0);

Add the fitted circle to the noisy data

% use the circFit parameters to create the fitted circle

theta = linspace(0,2*pi,100); % arbitrary spacing

xFit = circFit(3)*cos(theta) + circFit(1);

yFit = circFit(3)*sin(theta) + circFit(2);

hold on

plot(xFit,yFit,'r-','LineWidth',3)

Compare the fitted values to the actual (noisy) values

Of course these values may differ when this code is repeated due to random noise.

This creates a table comparing the known and fitted results.

T = array2table([[cnt,r];circFit],'VariableNames',{'xCnt','yCnt','radius'},...

'RowNames',{'Real values','FitValues'})

T =

2×3 table

xCnt yCnt radius

______ ______ ______

Real values 9.923 -2.42 22.52

FitValues 9.8052 -2.548 22.926

Adam Danz
on 9 Dec 2019

Thanks, @Matt J. I meant to mention alternative approaches to the special case when fitting a circle but by the time I finished typing out the answer, I had forgotten.

- https://www.mathworks.com/matlabcentral/fileexchange/5557-circle-fit explained in https://blogs.mathworks.com/pick/2008/03/14/fitting-a-circle-easily/
- https://www.mathworks.com/matlabcentral/fileexchange/36361-circle_fit
- https://www.mathworks.com/matlabcentral/fileexchange/44219-fast-circle-fitting-using-landau-method
- https://www.mathworks.com/matlabcentral/fileexchange/22678-circle-fit-taubin-method

But Matt J's answer is even better since you won't need to use a function external to what Matlab already provides.

Matt J
on 9 Dec 2019

Edited: Matt J
on 9 Dec 2019

Ok. Could you possibly show me the analytical alternatives to Adam's solution?

See attached. Note that my method does not minimize the same fitting error metric as Adam's. If you prefer his, though (and maybe you should), it might be worth mentioning that I do observe somewhat better convergence when initialized with mine. Notice the smaller final "Norm of step" and "First-order optimality" when the iterations terminate.

f = @(a) (xData-a(1)).^2 + (yData-a(2)).^2 - a(3).^2;

opts=optimoptions('lsqnonlin','Display','iter');

a0 = [mean(xData),mean(yData),max(xData)-mean(xData)];

lsqnonlin(f,a0,[],[],opts);

Norm of First-order

Iteration Func-count f(x) step optimality

0 4 6.04793e+07 1.13e+07

1 8 1.69499e+07 3.881 6.82e+05

2 12 1.67336e+07 0.317084 4.6e+03

3 16 1.67336e+07 0.00219778 0.221

[c,R]=circfitAlgebraic([xData;yData]);

lsqnonlin(f,[c,R],[],[],opts);

Norm of First-order

Iteration Func-count f(x) step optimality

0 4 1.74094e+07 1.22e+06

1 8 1.67337e+07 0.555282 1.41e+04

2 12 1.67336e+07 0.00672023 2.07

3 16 1.67336e+07 9.87177e-07 0.00653

Opportunities for recent engineering grads.

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

Start Hunting!
## 4 Comments

## Direct link to this comment

https://ww2.mathworks.cn/matlabcentral/answers/495767-non-linear-least-square-fitting#comment_776260

⋮## Direct link to this comment

https://ww2.mathworks.cn/matlabcentral/answers/495767-non-linear-least-square-fitting#comment_776260

## Direct link to this comment

https://ww2.mathworks.cn/matlabcentral/answers/495767-non-linear-least-square-fitting#comment_776266

⋮## Direct link to this comment

https://ww2.mathworks.cn/matlabcentral/answers/495767-non-linear-least-square-fitting#comment_776266

## Direct link to this comment

https://ww2.mathworks.cn/matlabcentral/answers/495767-non-linear-least-square-fitting#comment_776308

⋮## Direct link to this comment

https://ww2.mathworks.cn/matlabcentral/answers/495767-non-linear-least-square-fitting#comment_776308

## Direct link to this comment

https://ww2.mathworks.cn/matlabcentral/answers/495767-non-linear-least-square-fitting#comment_776321

⋮## Direct link to this comment

https://ww2.mathworks.cn/matlabcentral/answers/495767-non-linear-least-square-fitting#comment_776321

Sign in to comment.