I'll post this as a separate answer, since I did not use a spline at all to build the model, and so it does not get lost in the comments to my other answer.
As I said, the result will be hundreds of coefficients if you built this as a spline model. So nothing at all you can write down. I've attached your data as a .mat file to this comment.
plot3(xyz(:,1),xyz(:,2),xyz(:,3),'-o')
So we see a simple circular looking curve. But in fact, the points seem to lie exactly in a plane, although they are not in fact in a perfect circle in that plane. The curve is a bit egg shaped. That is, if I transform that 3-d set of points into a 2-d plane, we would see they lie almost perfectly in a palne, but not exactly so. The failure to lie exactly in a plane probably arises because you have written down the points with only 5 significant digits, and that is roughly the amount of error I see as a deviation from the plane.
So the smallest singular value there is roughly 5 powers of 10 smaller than the largest singular value. Again, that is good evidence the deviation from a perfect plane lies in having rounded off the 5th decimal place in your numbers.
Anyway, we can now try to build a model for your data that will be roughly as accurate as your data. I could transform the problem into a 2-dimensional one. Or, simpler yet to follow, we can just work in cylindrical coordinates. Since you wanted points that were at a set of uniform angles, that may be best.
I notice that your first and last points were the same. That was done to fit the spline as a periodic function, I presume.
x = xyz(2:end,1); xbar = mean(x);
y = xyz(2:end,2); ybar = mean(y);
[theta,R] = cart2pol(x-xbar,y-ybar);
xlabel 'Polar angle theta (in radians)'
Simplest now might be to just build a simple fourier series model for each of x, y, and z. Alternatively, I could have continurd to work in cylindrical coordinates, but the simple Fourier model for x(theta), y(theta), z(theta) will work nicely, and the added layer of complexity of working in cylindrical coordinates is not worth the effort.
mdl = fittype('b0+a1*sin(t)+b1*cos(t)+a2*sin(2*t)+b2*cos(2*t)+a3*sin(3*t)+b3*cos(3*t)+a4*sin(4*t)+b4*cos(4*t)+a5*sin(5*t)+b5*cos(5*t)+a6*sin(6*t)+b6*cos(6*t)','indep','t')
mdl =
General model:
mdl(a1,a2,a3,a4,a5,a6,b0,b1,b2,b3,b4,b5,b6,t) = b0+a1*sin(t)+b1*cos(t)+a2*sin(2*t)
+b2*cos(2*t)+a3*sin(3*t)+b3*cos(3*t)+a4*sin(4*t)+b4*cos(4*t)
+a5*sin(5*t)+b5*cos(5*t)+a6*sin(6*t)+b6*cos(6*t)
[mdlx,goodnessx] = fit(theta,x,mdl)
Warning: Start point not provided, choosing random start point.
mdlx =
General model:
mdlx(t) = b0+a1*sin(t)+b1*cos(t)+a2*sin(2*t)+b2*cos(2*t)+a3*sin(3*t)+b3*cos(3*t)
+a4*sin(4*t)+b4*cos(4*t)+a5*sin(5*t)+b5*cos(5*t)+a6*sin(6*t)
+b6*cos(6*t)
Coefficients (with 95% confidence bounds):
a1 = -2.003 (-2.034, -1.972)
a2 = 0.3862 (0.3543, 0.4181)
a3 = -2.032 (-2.064, -2.001)
a4 = 0.2025 (0.1708, 0.2343)
a5 = 0.01458 (-0.01682, 0.04598)
a6 = -0.1871 (-0.2185, -0.1558)
b0 = 20.76 (20.73, 20.78)
b1 = 26.99 (26.96, 27.03)
b2 = 0.2533 (0.2217, 0.285)
b3 = -0.7179 (-0.7497, -0.6861)
b4 = 0.3542 (0.3224, 0.3859)
b5 = -0.2083 (-0.2397, -0.1769)
b6 = 0.1204 (0.08905, 0.1518)
goodnessx =
sse: 0.2606
rsquare: 1.0000
dfe: 41
adjrsquare: 1.0000
rmse: 0.0797
The model has an RMSE of 0.0797, which is not quite as small as the noise in your data due to rounding. An extra trm or two in the model would decrease that error considerably. I'm not sure it is warranted. That would be your choice. The noise in your data due to rounding was on the oder of 10% or less of that number. Still it is probably adequate.
As you can see, the model fits quite nicely. As such, it gives you a nice function you can write down. As well, you can evaluate that model at a list of points in polar angle.
Next, build similar models for y and z.
mdly = fit(theta,y,mdl);
Warning: Start point not provided, choosing random start point.
mdlz = fit(theta,z,mdl);
Warning: Start point not provided, choosing random start point.
Again, the y and z models seem entirely adequate for this data. Or you could add an extra pair of terms if you wanted more.
Each of these models are now easily written down, since they only required 13 terms to fit as Fourier series. And, we can now evaluate them easily enough.
table(T,mdlx(Trad),mdly(Trad),mdlz(Trad))
ans =
T Var2 Var3 Var4
___ _______ _______ _______
0 47.551 -50.113 -34.851
30 41.626 -38.113 -38.914
60 33.095 -28.523 -39.762
90 20.781 -22.634 -35.811
120 4.5568 -22.372 -25.73
150 -6.5076 -34.321 -10.964
180 -4.5821 -50.234 -1.828
210 0.56545 -61.678 2.3641
240 8.3695 -71.553 3.8563
270 20.693 -79.351 1.142
300 36.272 -77.142 -10.139
330 46.66 -65.124 -24.522
Finally, we can now return and plot the three curves in 3-d.
fplot3(@(t) mdlx(t),@(t) mdly(t),@(t) mdlz(t))
Warning: Function behaves unexpectedly on array inputs. To improve performance, properly vectorize your function to return an output with the same size and shape as the input arguments.
Warning: Function behaves unexpectedly on array inputs. To improve performance, properly vectorize your function to return an output with the same size and shape as the input arguments.
Warning: Function behaves unexpectedly on array inputs. To improve performance, properly vectorize your function to return an output with the same size and shape as the input arguments.