1. 程式人生 > >matlab建模遇見的一些問題和解決方法

matlab建模遇見的一些問題和解決方法

工具:MATLAB
警告:Equation is badly conditioned. Remove repeated data points or try centering and scaling.
出現這一警告的一般是因為資料在橫座標方向上跨度太大,在這種跨度很大的多項式擬合裡,為了提高擬合精度,通常希望讓橫座標變得更加集中,因為在一個相對狹窄的小區間上去擬合,要比在一個相對很寬的區間上擬合更容易,且能提高擬合精度。MATLAB推薦的做法是: centering and scaling transformation,即以橫座標的均值為中心、以橫座標的標準差來做歸一化因子,將資料變得相對集中。
比如將這段程式碼:

x=1990:1:2008;
y=[34.1972 38.0773 42.3786 47.1423 52.4127 58.2367 64.6644 71.7483 79.5432 88.1057 97.4938 107.7658 118.9796 131.1914 144.4542 158.8166 174.3208 191.0005 208.8791];
n=2;
p=polyfit(x,y,n);

變成:

x=1990:1:2008;
y=[34.1972 38.0773 42.3786 47.1423 52.4127 58.2367 64.6644 71.7483 79.5432 88.1057 97.4938 107.7658 118.9796 131.1914 144.4542 158.8166 174.3208 191.0005 208.8791];
n
=3; mu = [mean(x); std(x)]; x1 = (x - mu(1))/mu(2); % 手動實現 centering and scaling p1 = polyfit(x1,y,n); plot(x,y,'bo',x,polyval(p1,x1),'r-') legend('data','fitted',2)

警告:
Warning: Duplicate x-y data points detected: using average of the z values.
意思就是,你的(x,y) 座標值出現了重複的點,計算時會取z的平均值來計算。

一個個檢查有沒有重複可不是什麼好辦法。好在看見網上有人出了一個很聰明的方法:先建立一個新的矩陣A,使得A=x+sqrt(-1)*y. 這樣就使得xy座標變成了一個複數。接著藉助unique()函式,這個函式可以判斷出一個矩陣中所有不重複的值。舉個例子,如果A=[1 1 2 3 4 5 5 6], unique(A)=[1 2 3 4 5 6],因為A中出現了1到6. 這樣利用unique(x+sqrt(-1)*y)就可以判斷出陣列中有沒有重複的了。
可是我的資料經過這樣的處理,發現並沒有重複的xy值。這是怎麼回事?
查詢matlab的help檔案,上面有這麼一句話:
“this means that there are two or more data points where the input values (x, y) are the same or very close together.”
這就是說,如果兩個值差得很近,也許也會被當做一樣來處理?關鍵是,這個小,究竟是多小?
griddata()的原始碼是怎麼說。這一段如下:

% Sort x and y so duplicate points can be averaged before passing to delaunay need x,y and z to be column vectors
sz = numel(x);
x = reshape(x,sz,1);y = reshape(y,sz,1);z = reshape(z,sz,1);sxyz = sortrows([x y z],[2 1]);
x = sxyz(:,1);y = sxyz(:,2);z = sxyz(:,3);
myepsx = eps(0.5 * (max(x) - min(x)))^(1/3);
myepsy = eps(0.5 * (max(y) - min(y)))^(1/3);
ind = [0; ((abs(diff(y)) < myepsy) & (abs(diff(x)) < myepsx)); 0];
if sum(ind) > 0
 warning('MATLAB:griddata:DuplicateDataPoints',['Duplicate x-y data points detected: using average of the z values.']);

______

部分如下:
sxyz = sortrows([x y z],[2 1]);
將需要插值的(x,y,z)放到一個大的矩陣中,x,y,z分別一列。然後以y為主導,對y從小到大排列,對應的x和z的值也跟著移動。
myepsx = eps(0.5 * (max(x) - min(x)))^(1/3);
myepsy = eps(0.5 * (max(y) - min(y)))^(1/3);
這兩行程式碼,是分別計算x和y的表示的精度值,也可以理解為在你的具體應用中,x和y的值的最小精度是多少。這裡計算的方法是計算二分之一x的閾值的開三次方的精度值,應該也可以有別的方法。
ind = [0; ((abs(diff(y)) < myepsy) & (abs(diff(x)) < myepsx)); 0];
diff(y)的意思是[y2-y1,y3-y2,……,yn-y(n-1)]形成的一個新的矩陣,如果這個新的矩陣的每一個元素的值小於之前計算的y的最小精度,那麼就認為這個值是0,或者說認為這兩個值相等。如果小於的條件是成立的,就返回1(True);反之則返回0(False)。後面的那個是一樣的,就是x的值的對比。
那麼我們想想,兩個對應的列,如果y的差值還小於精度值(就是認為兩個值相等,結果返回1),如果這時候同時X的差值還小於精度值(就是x的兩個值也相等,結果返回1),那個1&1=1,結果就返回1.
if sum(ind) > 0
只要結果中有一個1,就說明有一對(x,y)是相等的(或者非常接近),那個總和就必定大於1,就會返回這個警告。
比如說,經過整理以後的結果如下
X=[1 3.001 5 8 0 2 3 3.002 7]
Y=[1 1.001 2 3 5 6 7 7.001 8]
假設精度是0.5(我沒有計算,隨手舉的),那麼就意味著在你的計算中最高精度是0.5,低於0.5都可能是沒有意義的誤差。雖然從這上面看X,Y沒有相同的配對,可是如果用上面的計算:
diff(X)=[2.001 1.999 3 -8 2 1 0.002 3.998]
diff(Y)=[0.001 0.999 1 2 1 1 0.001 0.999]
首先看Y,雖然沒有0,但是有兩個0.001,比0.5小,就可以認為是一樣的值,返回兩個真值。再檢查這兩個真值的X的值,其中有一個2.001,大於0.5,說明不同;另外一個,X差值是0.002,小於0.5,說明精度已經低於最小的計算值了,應該認為是相等的。我們回到原來的資料,[3 7]和[3.002 7.001],如果EPS(精度)是大於0.002的,說明後面的尾數很有可能只是超過精度的計算誤差,是沒有意義的,這個時候做插值,就會返回之前的那個錯誤,說你有重複的xy值。
不過,總的來說,這個報錯並不影響你的結果;他都說了會取z的平均值計算。如果你真的覺得平均值不準想要取特定的值,可以用unique函式找到特定的行列(或者用griddata裡面的這個判斷也行),然後更改你的z值達到你的目的。

最後,討論下mathtype公式如何貼上到matlab中,其基本思想是由latex或者tex轉換到matlab裡。
首先MathType公式編輯器裡面的公式。而在MATLAB的命令視窗和Editor中雖然不能將公式顯示的想MathType中那麼漂亮。不過,可以在axes座標軸裡面將公式顯示的和MathType公式編輯器裡面的一樣漂亮。
如果想要將MathType中的公式,拿到Matlab裡面顯示,首先需要將MathType中的公式轉換為Tex格式的命令。這點,可以通過設定MathType來實現。
開啟MathType,“Preferences”-》“Translator”,然後如下面的設定:
然後再MathType裡面輸入一個公式,然後拷貝到一個記事本里,如下:
開啟MATLAB,執行下面的命令:
>>showLatex(f_s^t\left( \alpha \right) = \sum\limits_{k = 1}^n {{s^3}} ‘)$
結果是

showLatex(‘

fts(α)=k=1ns3’)