2011-10-04 17 views
6

मैं एक क्यूबिक स्पलीन इंटरपोलेशन प्रोग्राम लिखने की कोशिश कर रहा हूं। मैंने कार्यक्रम लिखा है, लेकिन ग्राफ सही ढंग से बाहर नहीं आ रहा है। स्पलीन प्राकृतिक सीमा परिस्थितियों का उपयोग करता है (प्रारंभ/अंत नोड पर दूसरा द्वार 0 है)। कोड मैटलैब में है और नीचे दिखाया गया है,घन स्पिन कार्यक्रम

clear all 
%Function to Interpolate 
k = 10;     %Number of Support Nodes-1 
xs(1) = -1; 
for j = 1:k 
    xs(j+1) = -1 +2*j/k; %Support Nodes(Equidistant) 
end; 
fs = 1./(25.*xs.^2+1);  %Support Ordinates 
x = [-0.99:2/(2*k):0.99]; %Places to Evaluate Function 
fx = 1./(25.*x.^2+1);  %Function Evaluated at x 

%Cubic Spline Code(Coefficients to Calculate 2nd Derivatives) 

f(1) = 2*(xs(3)-xs(1)); 
g(1) = xs(3)-xs(2); 
r(1) = (6/(xs(3)-xs(2)))*(fs(3)-fs(2)) + (6/(xs(2)-xs(1)))*(fs(1)-fs(2)); 
e(1) = 0; 

for i = 2:k-2 
    e(i) = xs(i+1)-xs(i); 
    f(i) = 2*(xs(i+2)-xs(i)); 
    g(i) = xs(i+2)-xs(i+1); 
    r(i) = (6/(xs(i+2)-xs(i+1)))*(fs(i+2)-fs(i+1)) + ... 
      (6/(xs(i+1)-xs(i)))*(fs(i)-fs(i+1)); 
end 
e(k-1) = xs(k)-xs(k-1); 
f(k-1) = 2*(xs(k+1)-xs(k-1)); 
r(k-1) = (6/(xs(k+1)-xs(k)))*(fs(k+1)-fs(k)) + ... 
     (6/(xs(k)-xs(k-1)))*(fs(k-1)-fs(k)); 

%Tridiagonal System 

i = 1; 
A = zeros(k-1,k-1); 
while i < size(A)+1; 
    A(i,i) = f(i); 
    if i < size(A); 
     A(i,i+1) = g(i); 
     A(i+1,i) = e(i); 
    end 
    i = i+1; 
end 

for i = 2:k-1        %Decomposition 
    e(i) = e(i)/f(i-1); 
    f(i) = f(i)-e(i)*g(i-1); 
end 

for i = 2:k-1        %Forward Substitution 
    r(i) = r(i)-e(i)*r(i-1); 
end 

xn(k-1)= r(k-1)/f(k-1); 
for i = k-2:-1:1       %Back Substitution 
    xn(i) = (r(i)-g(i)*xn(i+1))/f(i); 
end 

%Interpolation 

if (max(xs) <= max(x)) 
    error('Outside Range'); 
end 

if (min(xs) >= min(x)) 
    error('Outside Range'); 
end 


P = zeros(size(length(x),length(x))); 
i = 1; 
for Counter = 1:length(x) 
    for j = 1:k-1 
     a(j) = x(Counter)- xs(j); 
    end 
    i = find(a == min(a(a>=0))); 
    if i == 1 
     c1 = 0; 
     c2 = xn(1)/6/(xs(2)-xs(1)); 
     c3 = fs(1)/(xs(2)-xs(1)); 
     c4 = fs(2)/(xs(2)-xs(1))-xn(1)*(xs(2)-xs(1))/6; 
     t1 = c1*(xs(2)-x(Counter))^3; 
     t2 = c2*(x(Counter)-xs(1))^3; 
     t3 = c3*(xs(2)-x(Counter)); 
     t4 = c4*(x(Counter)-xs(1)); 
     P(Counter) = t1 +t2 +t3 +t4; 
    else 
     if i < k-1 
     c1 = xn(i-1+1)/6/(xs(i+1)-xs(i-1+1)); 
     c2 = xn(i+1)/6/(xs(i+1)-xs(i-1+1)); 
     c3 = fs(i-1+1)/(xs(i+1)-xs(i-1+1))-xn(i-1+1)*(xs(i+1)-xs(i-1+1))/6; 
     c4 = fs(i+1)/(xs(i+1)-xs(i-1+1))-xn(i+1)*(xs(i+1)-xs(i-1+1))/6; 
     t1 = c1*(xs(i+1)-x(Counter))^3; 
     t2 = c2*(x(Counter)-xs(i-1+1))^3; 
     t3 = c3*(xs(i+1)-x(Counter)); 
     t4 = c4*(x(Counter)-xs(i-1+1)); 
     P(Counter) = t1 +t2 +t3 +t4; 
     else 
     c1 = xn(i-1+1)/6/(xs(i+1)-xs(i-1+1)); 
     c2 = 0; 
     c3 = fs(i-1+1)/(xs(i+1)-xs(i-1+1))-xn(i-1+1)*(xs(i+1)-xs(i-1+1))/6; 
     c4 = fs(i+1)/(xs(i+1)-xs(i-1+1)); 
     t1 = c1*(xs(i+1)-x(Counter))^3; 
     t2 = c2*(x(Counter)-xs(i-1+1))^3; 
     t3 = c3*(xs(i+1)-x(Counter)); 
     t4 = c4*(x(Counter)-xs(i-1+1)); 
     P(Counter) = t1 +t2 +t3 +t4; 
     end  
    end 
end 

P = P'; 
P(length(x)) = NaN; 

plot(x,P,x,fx) 

जब मैं कोड चलाने के लिए, प्रक्षेप समारोह सममित नहीं है और, इसे सही ढंग से अभिसरण नहीं है। क्या कोई मेरे कोड में समस्याओं के बारे में कोई सुझाव दे सकता है? धन्यवाद।

उत्तर

9

मैंने बहुत समय पहले गणित में एक क्यूबिक स्पलीन पैकेज लिखा था। मैटलैब में उस पैकेज का मेरा अनुवाद यहां दिया गया है। ध्यान दें कि मैंने लगभग 7 वर्षों में क्यूबिक स्प्लिंस नहीं देखा है, इसलिए मैं इसे अपने स्वयं के दस्तावेज़ीकरण से दूर कर रहा हूं। आपको जो कुछ भी कहना है उसे जांचना चाहिए।

मूल समस्या हमें n डेटा अंक (x(1), y(1)) , ... , (x(n), y(n)) दिया गया है और हम एक टुकड़े की क्यूबिक इंटरपोलेंट की गणना करना चाहते हैं। interpolant

S(x) = { Sk(x) when x(k) <= x <= x(k+1) 
      { 0  otherwise 

यहाँ Sk (एक्स) के रूप में परिभाषित किया गया है प्रपत्र की एक घन बहुपदीय है

Sk(x) = sk0 + sk1*(x-x(k)) + sk2*(x-x(k))^2 + sk3*(x-x(k))^3 

पट्टी के गुण हैं:

  1. डेटा के माध्यम से पट्टी पास बिंदु Sk(x(k)) = y(k)
  2. स्पिन अंत-बिंदुओं पर निरंतर है और इस प्रकार इंटरपोलेशन अंतराल में लगातार हर जगह Sk(x(k+1)) = Sk+1(x(k+1))
  3. पट्टी निरंतर पहले व्युत्पन्न है Sk'(x(k+1)) = Sk+1'(x(k+1))
  4. पट्टी है निरंतर दूसरा व्युत्पन्न Sk''(x(k+1)) = Sk+1''(x(k+1))

डेटा बिंदु का एक सेट हम गुणांक sk0, sk1 के लिए हल करने की जरूरत है से एक घन पट्टी का निर्माण करने के लिए, sk2 और sk3n-1 क्यूबिक बहुपदों में से प्रत्येक के लिए। यह कुल 4*(n-1) = 4*n - 4 अज्ञात है। संपत्ति 1 आपूर्ति n बाधाएं, और संपत्ति 2,3,4 प्रत्येक अतिरिक्त n-2 बाधाओं की आपूर्ति करती है। इस प्रकार हमारे पास n + 3*(n-2) = 4*n - 6 बाधाएं और 4*n - 4 अज्ञात हैं। यह दो डिग्री स्वतंत्रता छोड़ देता है। हम प्रारंभिक और अंत नोड्स पर शून्य के बराबर दूसरे व्युत्पन्न को सेट करके स्वतंत्रता की इन डिग्री को ठीक करते हैं।

m(k) = Sk''(x(k)), h(k) = x(k+1) - x(k) और d(k) = (y(k+1) - y(k))/h(k) दें। निम्नलिखित तीन अवधि के आवर्ती संबंध रखती है

h(k-1)*m(k-1) + 2*(h(k-1) + h(k))*m(k) + h(k)*m(k+1) = 6*(d(k) - d(k-1)) 

मीटर (के) अज्ञात हम के लिए हल करने के लिए चाहते हैं। h(k) और d(k) इनपुट डेटा द्वारा परिभाषित किया गया है। यह तीन-अवधि पुनरावृत्ति संबंध एक त्रिभुज रैखिक प्रणाली को परिभाषित करता है। एक बार जब m(k)Sk के लिए निर्धारित कर रहे हैं गुणांक द्वारा

sk0 = y(k) 
    sk1 = d(k) - h(k)*(2*m(k) + m(k-1))/6 
    sk2 = m(k)/2 
    sk3 = m(k+1) - m(k)/(6*h(k)) 

दिया जाता है ठीक है कि सभी गणित आप पूरी तरह से एल्गोरिथ्म एक घन पट्टी गणना करने के लिए परिभाषित करने के लिए पता करने की जरूरत है।यहाँ यह मैटलैब में है:

function plot_cubic_spline(x,s0,s1,s2,s3) 

n = length(x); 

inner_points = 20; 

for i=1:n-1 
    xx = linspace(x(i),x(i+1),inner_points); 
    xi = repmat(x(i),1,inner_points); 
    yy = s0(i) + s1(i)*(xx-xi) + ... 
    s2(i)*(xx-xi).^2 + s3(i)*(xx - xi).^3; 
    plot(xx,yy,'b') 
    plot(x(i),0,'r'); 
end 

यहाँ एक समारोह है कि प्रसिद्ध Runge समारोह पर में एक घन पट्टी और भूखंडों का निर्माण करती है:

function [s0,s1,s2,s3]=cubic_spline(x,y) 

if any(size(x) ~= size(y)) || size(x,2) ~= 1 
    error('inputs x and y must be column vectors of equal length'); 
end 

n = length(x) 

h = x(2:n) - x(1:n-1); 
d = (y(2:n) - y(1:n-1))./h; 

lower = h(1:end-1); 
main = 2*(h(1:end-1) + h(2:end)); 
upper = h(2:end); 

T = spdiags([lower main upper], [-1 0 1], n-2, n-2); 
rhs = 6*(d(2:end)-d(1:end-1)); 

m = T\rhs; 

% Use natural boundary conditions where second derivative 
% is zero at the endpoints 

m = [ 0; m; 0]; 

s0 = y; 
s1 = d - h.*(2*m(1:end-1) + m(2:end))/6; 
s2 = m/2; 
s3 =(m(2:end)-m(1:end-1))./(6*h); 

यहाँ एक घन पट्टी प्लॉट करने के लिए कुछ कोड है

function cubic_driver(num_points) 

runge = @(x) 1./(1+ 25*x.^2); 

x = linspace(-1,1,num_points); 
y = runge(x); 

[s0,s1,s2,s3] = cubic_spline(x',y'); 

plot_points = 1000; 
xx = linspace(-1,1,plot_points); 
yy = runge(xx); 

plot(xx,yy,'g'); 
hold on; 
plot_cubic_spline(x,s0,s1,s2,s3); 

आप इसे कार्रवाई में देख सकते हैं मैटलैब पर निम्न चलाकर संकेत

>> cubic_driver(5) 
>> clf 
>> cubic_driver(10) 
>> clf 
>> cubic_driver(20) 

जब तक आपके पास बीस नोड्स होते हैं तो आपका इंटरपोलेंट रनगे फ़ंक्शन से दृश्यमान रूप से अलग नहीं होता है।

मैटलैब कोड पर कुछ टिप्पणियां: मैं किसी भी या लूप के दौरान उपयोग नहीं करता हूं। मैं सभी परिचालनों को सदिश बनाने में सक्षम हूं। मैं जल्दी से spdiags के साथ स्पैर त्रिकोणीय मैट्रिक्स बना देता हूं। मैं बैकस्लैश ऑपरेटर का उपयोग कर इसे हल करता हूं। मैं विघटन और आगे और पिछड़े हलकों को संभालने के लिए टिम डेविस के यूएमएफपीएक पर गिन रहा हूं।

उम्मीद है कि मदद करता है। कोड GitHub पर एक सार रूप में उपलब्ध है https://gist.github.com/1269709

संबंधित मुद्दे