legendre 球諧函數的正交性與系數
物理大地測量的各項球諧函數滿足正交性, 因此可以用多階球諧函數的和擬合地球重力位, 將各階球諧函數視作是總合函數的基底。 由於其正交性質,使用內積,(對函數也就是積分。) 就能由總合中分離出各項系數。 本次作業練習由 legendre 函數定義出各階球諧函數, 再以任意系數組合出一組重力位, 最後再嘗試從合成的重力位裡分離出各項系數。
legendre 函數
legendre 函數是一系列的遞迴函數, 總合稱為 legendre 級數。 用遞迴的定義方法, 可以由第一二階定義出任意階數, 而第 n 階的第 m 次,則需要以微分計算, 這裡使用數值微分。
global p0
global p1
p0 = @(t) ones(1,columns(t));
p1 = @(t) t;
function pn = p_nth(n)
  global p0
  global p1
  if (n == 0)
    pn = p0;
  elseif (n == 1)
    pn = p1;
  else
    pn_m1 = p_nth(n-1);
    pn_m2 = p_nth(n-2);
    pn = @(t) -(n-1)/n .* pn_m2(t) + (2*n-1) / n .* t .* pn_m1(t);
  end
end
function dydx = derive_at (f, x, dx = 0.005)
  dydx = ( f(x.+dx) .- f(x.-dx) ) / (dx*2);
end
function dfdx = derive (f, dx = 0.005)
  dfdx = @(x) derive_at(f, x, dx);
end
function pnm = p_nmth(n,m)
  dpnm = p_nth(n);
  i = 0;
  while (i < m)
    dpnm = derive(dpnm);
    i++;
  end
  pnm = @(t) (1-t.^2).^(m/2) .* dpnm(t);
end
呼叫 p_nth 可以取得第 n 階的 legendre 函數,
呼叫 p_nmth 則可以取得第 n 階第 m 次的 legendre 函數,
其返回值都是函數,而且各次呼叫間獨立;
如果要計算高階項效率會很差,
但本次作業最高階只用到 6,所以還能接受。
球諧函數
球諧函數就是將 legendre 函數
輸入定義在 cos(ψ) ,再乘上正弦或餘弦函數。
這裡也用高階函數的型式,重新包裝前面定義的 p_nmth ,
使其接受 ψ 作為輸入,再分別定義 rnm snm
為原函數乘上正弦或餘弦的結果。
p_nmth_cos = @(n,m) @(r) p_nmth(n,m)(cos(r));
global rnm
rnm = @(n,m) @(th,l) p_nmth_cos(n,m)(th) * cos(m*l);
global snm
snm = @(n,m) @(th,l) p_nmth_cos(n,m)(th) * sin(m*l);
各階各次球諧函數圖型
在繪圖時,發現如果用 180 * 360 的球去畫, 我的程式會 buffer overflow, 所以就簡化成 45 * 45 的球, 每 8° 經度 4° 緯度取樣一次。 網格會變比較粗糙,但色階大致正確。
q1_rnm = [2 0
          3 1
          4 0
          4 4
          5 0
          6 0];
q1_snm = [2 1
          3 3
          4 2
          4 2
          5 1
          6 1];
global x_degree_range = 0:359;
global x_radian_range = x_degree_range /180 *pi;
global y_degree_range = 0:179;
global y_radian_range = y_degree_range /180 *pi;
function hdl = plot_earth_grid_180x360(grid)
  % grid (latitude, longitude) = (1:180, 1:360)
  grid_square = grid(1:4:end,1:8:end);
  [x y z] = sphere(44);
  hdl = surf(x,y,z, 'cdata', grid_square);
  colorbar;
  shading interp;
end
function plot_grid_180x360_tofile(grid, name)
  fig = figure('visible', 'off');
  plot_earth_grid_180x360(grid);
  print('-dpng', [name '-sphere.png']);
  close(fig);
end
for i=1:rows(q1_rnm)
  n = q1_rnm(i,1);
  m = q1_rnm(i,2);
  frnm = rnm(n, m);
  gridi = frnm(y_radian_range', x_radian_range);
  plot_grid_180x360_tofile(gridi, ['r' num2str(n) num2str(m)]);
  n = q1_snm(i,1);
  m = q1_snm(i,2);
  fsnm = snm(n, m);
  gridi = fsnm(y_radian_range', x_radian_range);
  plot_grid_180x360_tofile(gridi, ['s' num2str(n) num2str(m)]);
end
帶諧
扇諧
田諧
合成球諧函數
先隨機產生 n=0:6 m=0:n 的系數,
再將這些系數乘上各球諧函數,
加總得到合成的球諧函數網格。
系數是隨機產生的,在 0 1 之間。
global coefficient_data
coefficient_data = {};
function xnm = coefficient_xnm(type, n, m, set_value = [])
  global coefficient_data
  if (type == 'r')
    type_id = 1;
  else
    type_id = 2;
  end
  if (isempty(set_value))
    xnm = coefficient_data{type_id, n+1, m+1};
  else
    xnm = coefficient_data{type_id, n+1, m+1} = set_value;
  end
end
coefficient_sum_grid = zeros(columns(y_radian_range), columns(x_radian_range));
for n = 0:6
  for m = 0:n
    % cell start from 1
    rnmc = rand(1);
    coefficient_xnm('r', n, m, rnmc);
    coefficient_sum_grid += rnmc * rnm(n, m)(y_radian_range', x_radian_range);
    snmc = rand(1);
    coefficient_xnm('s', n, m, snmc);
    coefficient_sum_grid += snmc * snm(n, m)(y_radian_range', x_radian_range);
  end
end
plot_grid_180x360_tofile(coefficient_sum_grid, 'coefficient-sum');
| 系數名 | 系數值 | 系數名 | 系數值 | 
|---|---|---|---|
| R00 | 0.909636 | S00 | 0.121664 | 
| R10 | 0.109366 | S10 | 0.8308 | 
| R11 | 0.824859 | S11 | 0.214129 | 
| R20 | 0.832324 | S20 | 0.503761 | 
| R21 | 0.117922 | S21 | 0.126986 | 
| R22 | 0.695958 | S22 | 0.684922 | 
| R30 | 0.868858 | S30 | 0.517931 | 
| R31 | 0.638108 | S31 | 0.0319404 | 
| R32 | 0.532819 | S32 | 0.572462 | 
| R33 | 0.145508 | S33 | 0.0404046 | 
| R40 | 0.916369 | S40 | 0.394033 | 
| R41 | 0.199658 | S41 | 0.970572 | 
| R42 | 0.784488 | S42 | 0.242452 | 
| R43 | 0.707329 | S43 | 0.621902 | 
| R44 | 0.766017 | S44 | 0.200479 | 
| R50 | 0.761956 | S50 | 0.158401 | 
| R51 | 0.814694 | S51 | 0.413291 | 
| R52 | 0.759872 | S52 | 0.589732 | 
| R53 | 0.448917 | S53 | 0.839896 | 
| R54 | 0.357891 | S54 | 0.949848 | 
| R55 | 0.89479 | S55 | 0.289316 | 
| R60 | 0.520243 | S60 | 0.98437 | 
| R61 | 0.916618 | S61 | 0.384952 | 
| R62 | 0.107338 | S62 | 0.852719 | 
| R63 | 0.561965 | S63 | 0.202933 | 
| R64 | 0.571826 | S64 | 0.246472 | 
| R65 | 0.0793381 | S65 | 0.0376952 | 
| R66 | 0.707811 | S66 | 0.957893 | 
估計各項球諧系數的振幅
由之後分離系數所使用的積分,其積分結果產生的系數
2*pi/(2*n+1)*factorial(n+m)/factorial(n-m) 可以得知,
雖然各項球諧的系數都介於 0-1 之間,
但 m 的次數越高,其結果的振幅也會越大,
產生的系數也會越大,二者約是階乘的關係。
我選取了 S42 項作實驗,其圖形如上述圖九。 在維持其它系數不變,獨立調整 S42 係數, 繪出 B42 為 500 與 999 的情況如下。 在 500 時就能在原本合成的彩度中看出 S42 的形狀, 到 999 時則是二者混合,再增加就和 S42 的獨立圖形無太大區別了, 也就不畫了。
以正交性質分離系數
因為球諧函數各項間為正交, 故在函數上積分後如同內積, 可以消去其它所有正交的不同次項, 只留下原本的項。 可以運用此一性質從合成的函數結果中, 分離出各項的系數。
function coefficient = coefficient_devide(grid_all, sh_type, n, m)
  global x_radian_range
  global y_radian_range
  global rnm
  global snm
  if (sh_type == 'r')
    fnm = rnm(n,m);
  else % 's'
    fnm = snm(n,m);
  end
  if (m == 0)
    coefficient_integral = 4*pi/(2*n+1);
  else
    coefficient_integral = 2*pi/(2*n+1)*factorial(n+m)/factorial(n-m);
  end
  grid_single = fnm(y_radian_range', x_radian_range);
  grid_sin = sin(y_radian_range' * ones(size(x_radian_range)));
  sum2d = @(grid) sum(sum(grid));
  grid_integral = sum2d(grid_single .* grid_all .* grid_sin) * (
                    pi*2*pi /180/360
                  );
  coefficient = grid_integral / coefficient_integral;
end
for n=0:6
  for m = 0:n
    printf('R%d%d %d\n',
           n, m, coefficient_devide(coefficient_sum_grid, 'r', n,m));
    printf('S%d%d %d\n',
           n, m, coefficient_devide(coefficient_sum_grid, 's', n,m));
  end
end
其中 Snm 中 m=0 的項是 0,
所以該項的系數其實是沒有意義的;
但我在產生系數時沒有特別濾掉,
所以這裡也才會有數值,但分離出來還是 0。
分離出的系數都相當準確,可以準確到小數下第二位。
| 系數名 | 系數真值 | 分離出的系數值 | 系數名 | 系數值 | 分離出的系數值 | 
|---|---|---|---|---|---|
| R00 | 0.909636 | 0.909555 | S00 | 0.121664 | 0 | 
| R10 | 0.109366 | 0.109233 | S10 | 0.8308 | 0 | 
| R11 | 0.824859 | 0.825042 | S11 | 0.214129 | 0.214204 | 
| R20 | 0.832324 | 0.83192 | S20 | 0.503761 | 0 | 
| R21 | 0.117922 | 0.118295 | S21 | 0.126986 | 0.127272 | 
| R22 | 0.695958 | 0.696267 | S22 | 0.684922 | 0.685633 | 
| R30 | 0.868858 | 0.868548 | S30 | 0.517931 | 0 | 
| R31 | 0.638108 | 0.638342 | S31 | 0.0319404 | 0.032054 | 
| R32 | 0.532819 | 0.533218 | S32 | 0.572462 | 0.572772 | 
| R33 | 0.145508 | 0.145862 | S33 | 0.0404046 | 0.041066 | 
| R40 | 0.916369 | 0.915642 | S40 | 0.394033 | 0 | 
| R41 | 0.199658 | 0.200045 | S41 | 0.970572 | 0.970741 | 
| R42 | 0.784488 | 0.784601 | S42 | 0.242452 | 0.243179 | 
| R43 | 0.707329 | 0.708025 | S43 | 0.621902 | 0.622153 | 
| R44 | 0.766017 | 0.766961 | S44 | 0.200479 | 0.200886 | 
| R50 | 0.761956 | 0.761469 | S50 | 0.158401 | 0 | 
| R51 | 0.814694 | 0.814834 | S51 | 0.413291 | 0.413305 | 
| R52 | 0.759872 | 0.759934 | S52 | 0.589732 | 0.589799 | 
| R53 | 0.448917 | 0.448923 | S53 | 0.839896 | 0.839898 | 
| R54 | 0.357891 | 0.357891 | S54 | 0.949848 | 0.949848 | 
| R55 | 0.89479 | 0.89479 | S55 | 0.289316 | 0.289316 | 
| R60 | 0.520243 | 0.519194 | S60 | 0.98437 | 0 | 
| R61 | 0.916618 | 0.916692 | S61 | 0.384952 | 0.385246 | 
| R62 | 0.107338 | 0.107558 | S62 | 0.852719 | 0.852801 | 
| R63 | 0.561965 | 0.56207 | S63 | 0.202933 | 0.203026 | 
| R64 | 0.571826 | 0.571866 | S64 | 0.246472 | 0.246483 | 
| R65 | 0.0793381 | 0.0793381 | S65 | 0.0376952 | 0.037695 | 
| R66 | 0.707811 | 0.707811 | S66 | 0.957893 | 0.957893 | 













