空間二次曲面數據擬合算法推導及仿真分析

在上一篇的博客球面數據擬合算法簡介中,筆者詳細介紹了關於空間球面數據擬合的算法公式推導並給出了相應的Matlab代碼及其仿真分析。本次筆者將上面這一情況進行更一般的推廣,即取消了球面數據這一限制,數據可以是橢球面形式的,也就是說是任意的空間二次曲面形式的,可見球面的數據是它的一個特例。下面給出的是空間二次曲面的標準表達式:


一共有6個未知的參數,x0, y0, z0, A, B, C。寫成一般式如下所示:


其中


    對於有N個三維橢球面樣本對其進行橢球面擬合,我們只需要對參數a,b,c,d,e,f進行估計,從而就可以得到x0, y0, z0, A, B, C。那麼怎麼利用樣本去估計這些參數呢?這實際上就是模型參數估計的內容,模型參數估計有很多種方法,其中最基本的方法就是最小二乘法(Least Squares Method),這個在上一篇《球面數據擬合算法簡介》博客中有用到。由於它的原理直觀,算法簡單,收斂性能好,且不要求先驗的統計知識,因而被廣泛應用。最小二乘法是在1795年由大數學家高斯(C.F.Gauss)研究天體運動軌道問題提出的,它的基本原理是實際觀測值與模型計算值的誤差的平方和最小原理,由此而得名“最小二乘”法。應該注意的是最小二乘法是一種思想,由它衍生出來的公式可以有很多種。本次的空間二次數據擬合算法的推導利用的也是最小二乘法,不同的是本次是先估計參數a,b,c,d,e,f,然後間接的得到參數x0, y0, z0, A, B, C,這樣做給公式推導帶來了很大的方便,而且結果與直接推導的完全一樣。

基於最小二乘的擬合方法公式推導

下面來利用最小二乘的思想進行推導,首先對於每個樣本點(x_i,y_i,z_i),其誤差可表示爲:


則誤差平方和爲:


我們令E對於a,b,c,d,e,f的各一階偏導數等於0,則有:


令:



帶入化簡得:


寫成矩陣的形式有:


求解該六元一次方程組即可得到a,b,c,d,e,f的估計值。進而得到x0, y0, z0, A, B, C。

Matlab代碼分析與仿真

代碼主要有兩個部分,第一部分是生成帶噪聲的橢球面數據,第二部分是利用上述推導的算法來估計相關的參數,下面給出相關的代碼

clear all;
close all
clc;
A = 300;     % x方向上的軸半徑
B = 400;     % y方向上的軸半徑
C = 500;     % z方向上的軸半徑
x0 = -120;   %橢球球心x座標
y0 = -67;    %橢球球心y座標
z0 = 406;    %橢球球心z座標
SNR = 30;    %信噪比

%********************************生成隨機橢球球面數據************************************
%利用在球座標系下的參數方程來生成各個橢球的樣本點
num_alfa = 100;
num_sita = 50;
alfa = (0:num_alfa-1)*1*pi/num_alfa;
sita = (0:num_sita-1)*2*pi/num_sita;
x = zeros(num_alfa,num_sita);
y = zeros(num_alfa,num_sita);
z = zeros(num_alfa,num_sita);
for i = 1:num_alfa
    for j = 1:num_sita
        x(i,j) = x0 + A*sin(alfa(i))*cos(sita(j));
        y(i,j) = y0 + B*sin(alfa(i))*sin(sita(j));
        z(i,j) = z0 + C*cos(alfa(i));
    end
end

x = reshape(x,num_alfa*num_sita,1);    %轉換成一維的數組便於後續的處理
y = reshape(y,num_alfa*num_sita,1);
z = reshape(z,num_alfa*num_sita,1);
figure;
plot3(x,y,z,'*');
title('生成的沒有噪聲的橢球面數據');
%加入均值爲0的高斯分佈噪聲 
amp = 10^(-SNR/20)*A;
x = x + amp*rand(num_alfa*num_sita,1);
y = y + amp*B/A*rand(num_alfa*num_sita,1);
z = z + amp*C/A*rand(num_alfa*num_sita,1);
figure;
plot3(x,y,z,'*');
string = ['加入噪聲的橢球面數據,SNR=',num2str(SNR),'dB'];
title(string);
%*******************************************************************************************
%空間二次曲面擬合算法
num_points = length(x);
%一次項統計平均
x_avr = sum(x)/num_points;
y_avr = sum(y)/num_points;
z_avr = sum(z)/num_points;
%二次項統計平均
xx_avr = sum(x.*x)/num_points;
yy_avr = sum(y.*y)/num_points;
zz_avr = sum(z.*z)/num_points;
xy_avr = sum(x.*y)/num_points;
xz_avr = sum(x.*z)/num_points;
yz_avr = sum(y.*z)/num_points;
%三次項統計平均
xxx_avr = sum(x.*x.*x)/num_points;
xxy_avr = sum(x.*x.*y)/num_points;
xxz_avr = sum(x.*x.*z)/num_points;
xyy_avr = sum(x.*y.*y)/num_points;
xzz_avr = sum(x.*z.*z)/num_points;
yyy_avr = sum(y.*y.*y)/num_points;
yyz_avr = sum(y.*y.*z)/num_points;
yzz_avr = sum(y.*z.*z)/num_points;
zzz_avr = sum(z.*z.*z)/num_points;
%四次項統計平均
yyyy_avr = sum(y.*y.*y.*y)/num_points;
zzzz_avr = sum(z.*z.*z.*z)/num_points;
xxyy_avr = sum(x.*x.*y.*y)/num_points;
xxzz_avr = sum(x.*x.*z.*z)/num_points;
yyzz_avr = sum(y.*y.*z.*z)/num_points;


%計算求解線性方程的係數矩陣
A0 = [yyyy_avr yyzz_avr xyy_avr yyy_avr yyz_avr yy_avr;
     yyzz_avr zzzz_avr xzz_avr yzz_avr zzz_avr zz_avr;
     xyy_avr  xzz_avr  xx_avr  xy_avr  xz_avr  x_avr;
     yyy_avr  yzz_avr  xy_avr  yy_avr  yz_avr  y_avr;
     yyz_avr  zzz_avr  xz_avr  yz_avr  zz_avr  z_avr;
     yy_avr   zz_avr   x_avr   y_avr   z_avr   1;];
%計算非齊次項
b = [-xxyy_avr;
     -xxzz_avr;
     -xxx_avr;
     -xxy_avr;
     -xxz_avr;
     -xx_avr];

resoult = inv(A0)*b;
%resoult = solution_equations_n_yuan(A0,b);

x00 = -resoult(3)/2;                  %擬合出的x座標
y00 = -resoult(4)/(2*resoult(1));     %擬合出的y座標
z00 = -resoult(5)/(2*resoult(2));     %擬合出的z座標

AA = sqrt(x00*x00 + resoult(1)*y00*y00 + resoult(2)*z00*z00 - resoult(6));   % 擬合出的x方向上的軸半徑
BB = AA/sqrt(resoult(1));                                                    % 擬合出的y方向上的軸半徑
CC = AA/sqrt(resoult(2));                                                    % 擬合出的z方向上的軸半徑

fprintf('擬合結果\n');
fprintf('a = %f, b = %f, c = %f, d = %f, e = %f, f = %f\n',resoult);
fprintf('x0 = %f, 相對誤差%f\n',x00,abs((x00-x0)/x0));
fprintf('y0 = %f, 相對誤差%f\n',y00,abs((y00-y0)/y0));
fprintf('z0 = %f, 相對誤差%f\n',z00,abs((z00-z0)/z0));
fprintf('A = %f,  相對誤差%f\n',AA,abs((A-AA)/A));
fprintf('B = %f,  相對誤差%f\n',BB,abs((B-BB)/B));
fprintf('C = %f,  相對誤差%f\n',CC,abs((C-CC)/C));
運行該程序得到如下結果:

可以看到擬合的誤差很小,同時我們也可以看到擬合後的參數A,B,C的相對誤差比x0,y0,z0要小。


結束語

    從matlab的仿真分析驗證了前面的公式推導的正確性,關於空間二次曲面擬合的運用,一個最典型的應用就是對地磁計靜態校準的應用,地磁計在沒有校準的情況下如果讓其在空間的各個卦限旋轉一遍得到輸出數據的軌跡就是個橢球面,利用該算法就可以有效的估計出靜態干擾以及每個軸的相對靈敏度。還有就是在圖像處理、機器人等領域,需要對運動圖像中的橢圓曲線進行快速檢測,實際上這個時候擬合的是一個橢圓曲線,可以使用上述類似的方法來進行擬合,它的參數要少一些,更爲簡單,有興趣的讀者可以自己嘗試推導並用matlab仿真驗證一下。







發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章