function varargout = Numderiv(varargin) % NUMDERIV Application M-file for Numderiv.fig % FIG = NUMDERIV launch Numderiv GUI. % NUMDERIV('callback_name', ...) invoke the named callback. % Last Modified by GUIDE v2.0 03-Mar-2002 18:59:11 if nargin == 0 % LAUNCH GUI fig = openfig(mfilename,'reuse'); hold on; % Use system color scheme for figure: set(fig,'Color',get(0,'defaultUicontrolBackgroundColor')); % Generate a structure of handles to pass to callbacks, and store it. handles = guihandles(fig); guidata(fig, handles); if nargout > 0 varargout{1} = fig; end elseif ischar(varargin{1}) % INVOKE NAMED SUBFUNCTION OR CALLBACK try if (nargout) [varargout{1:nargout}] = feval(varargin{:}); % FEVAL switchyard else feval(varargin{:}); % FEVAL switchyard end catch disp(lasterr); end end %| ABOUT CALLBACKS: %| GUIDE automatically appends subfunction prototypes to this file, and %| sets objects' callback properties to call them through the FEVAL %| switchyard above. This comment describes that mechanism. %| %| Each callback subfunction declaration has the following form: %| (H, EVENTDATA, HANDLES, VARARGIN) %| %| The subfunction name is composed using the object's Tag and the %| callback type separated by '_', e.g. 'slider2_Callback', %| 'figure1_CloseRequestFcn', 'axis1_ButtondownFcn'. %| %| H is the callback object's handle (obtained using GCBO). %| %| EVENTDATA is empty, but reserved for future use. %| %| HANDLES is a structure containing handles of components in GUI using %| tags as fieldnames, e.g. handles.figure1, handles.slider2. This %| structure is created at GUI startup using GUIHANDLES and stored in %| the figure's application data using GUIDATA. A copy of the structure %| is passed to each callback. You can store additional information in %| this structure at GUI startup, and you can change the structure %| during callbacks. Call guidata(h, handles) after changing your %| copy to replace the stored original so that subsequent callbacks see %| the updates. Type "help guihandles" and "help guidata" for more %| information. %| %| VARARGIN contains any extra arguments you have passed to the %| callback. Specify the extra arguments by editing the callback %| property in the inspector. By default, GUIDE sets the property to: %| ('', gcbo, [], guidata(gcbo)) %| Add any extra arguments after the last argument, before the final %| closing parenthesis. % -------------------------------------------------------------------- function varargout = leftendpt_Callback(h, eventdata, handles, varargin) try disp(get(h,'Value')); set(h,'Value',eval(get(h,'String'))); catch set(h,'String','0.0'); set(h,'Value',0.0); end % -------------------------------------------------------------------- function varargout = rightendpt_Callback(h, eventdata, handles, varargin) try set(h,'Value',eval(get(h,'String'))); catch set(h,'String','1.0'); set(h,'Value',1.0); end % -------------------------------------------------------------------- function varargout = dfnfx_Callback(h, eventdata, handles, varargin) try testfcn = inline(get(h,'String')); testfcn(eval(get(handles.leftendpt,'String'))); catch set(h,'String','sin(pi*x)'); end % -------------------------------------------------------------------- function varargout = nodes_Callback(h, eventdata, handles, varargin) try set(h,'Value',max(4,round(eval(get(h,'String'))))); set(h,'String',num2str(get(h,'Value'))); catch set(h,'String','4'); set(h,'Value',4); end % -------------------------------------------------------------------- function varargout = noiselevel_Callback(h, eventdata, handles, varargin) try set(h,'Value',max(0,min(100,eval(get(h,'String'))))); set(h,'String',num2str(get(h,'Value'))); catch set(h,'String','0.0'); set(h,'Value',0.0); end % ---------------------------------------------------------- function varargout = cleargraphbutton_Callback(h, eventdata, handles, varargin) set(handles.noderr,'String','Max Node Error: 0'); set(handles.alpha,'String',''); cla; % -------------------------------------------------------------------- function varargout = drawgraphbutton_Callback(h, eventdata, handles, varargin) leftendpoint = get(handles.leftendpt,'Value'); rightendpoint = get(handles.rightendpt,'Value'); nodes = get(handles.nodes,'Value'); noiselevel = get(handles.noiselevel,'Value'); if (leftendpoint >= rightendpoint) disp('Endpoints are reversed. Fix this.'); return; end xnodes = linspace(leftendpoint,rightendpoint,nodes); ynodes = xnodes; rfcn = inline('40*(x+1/4)*(x-1/3)*(x-2/3)'); ufcn = inline('exp(x*(x*(x*(x*10-10)-5/9)+20/9))'); fcn = inline(get(handles.dfnfx,'String')); for ii = (1:nodes) ynodes(ii) = fcn(xnodes(ii)); end rand('state',nodes); % initial seed depends only on node size % now the problem of how to specify error...1st is % of val, 2nd % of max %rndynodes = ynodes.*(1+(noiselevel/100)*(2*rand(size(ynodes))-1)); rndynodes = ynodes+norm(ynodes,inf)*noiselevel/100*(2*rand(size(ynodes))-1); mnodes = 10*(nodes - 1)+1; % densify existing nodes by factor of 10 mxnodes = linspace(leftendpoint,rightendpoint,mnodes); mynodes = mxnodes; for ii = (1:mnodes) mynodes(ii) = fcn(mxnodes(ii)); % calculate fcn value end % calculate derivative of fcn value reasonable accurately mynodesp = [-3*mynodes(1)+4*mynodes(2)-mynodes(3),... (mynodes(3:mnodes)-mynodes(1:mnodes-2)),... mynodes(mnodes-2)-4*mynodes(mnodes-1)+3*mynodes(mnodes)]... /(2*(mxnodes(2)-mxnodes(1))); set(handles.alpha,'String',''); switch get(handles.graphlistbox,'Value') case 1 % graph function plot(mxnodes,mynodes,'r-'); set(handles.noderr,'String','Max Node Error: 0'); set(handles.alpha,'String',''); case 2 % graph function with noise plot(xnodes,rndynodes,'b-'); set(handles.noderr,'String',strcat('Max Node Error: ',... num2str(norm(rndynodes-mynodes(1:10:mnodes),inf)))); set(handles.alpha,'String',''); case 3 % graph natural cubic spline through function with noise pp = NCSpp(xnodes,rndynodes); pynodes = PPeval(pp,mxnodes); plot(mxnodes,pynodes,'m-'); set(handles.noderr,'String',strcat('Max Node Error: ',... num2str(norm(pynodes -mynodes,inf)))); set(handles.alpha,'String',''); case 4 % graph function derivative plot(mxnodes,mynodesp,'r-'); set(handles.noderr,'String','Max Node Error: 0'); set(handles.alpha,'String',''); case 5 % graph forward difference approximate derivative with noise tmpnodes = [(rndynodes(2:nodes)-rndynodes(1:nodes-1)),... rndynodes(nodes)-rndynodes(nodes-1)]/(xnodes(2)-xnodes(1)); plot(xnodes,tmpnodes,'b-'); set(handles.noderr,'String',strcat('Max Node Error: ',... num2str(norm(tmpnodes -mynodesp(1:10:mnodes),inf)))); set(handles.alpha,'String',''); case 6 % graph centered difference approximate derivative with noise tmpnodes = [-3*rndynodes(1)+4*rndynodes(2)-rndynodes(3),... (rndynodes(3:nodes)-rndynodes(1:nodes-2)),... rndynodes(nodes-2)-4*rndynodes(nodes-1)+3*rndynodes(nodes)]... /(2*(xnodes(2)-xnodes(1))); plot(xnodes,tmpnodes,'g-'); set(handles.noderr,'String',strcat('Max Node Error: ',... num2str(norm(tmpnodes - mynodesp(1:10:mnodes),inf)))); set(handles.alpha,'String',''); case 7 % graph cubic spline approximate derivative with noise pp = NCSpp(xnodes,rndynodes); ppp = PPder(pp); mynodes = PPeval(ppp,mxnodes); plot(mxnodes,mynodes,'m-'); set(handles.noderr,'String',strcat('Max Node Error: ',... num2str(norm(mynodes -mynodesp,inf)))); set(handles.alpha,'String',''); case 8 % regularized cubic spline approximate derivative with noise alp = inputdlg('Input regularization parameter: ',... 'Regularized Natural Cubic Spline'); alp = str2num(alp{1}); pp = RNCSpp(xnodes,rndynodes,alp); ppp = PPder(pp); mynodes = PPeval(ppp,mxnodes); plot(mxnodes,mynodes,'m-'); set(handles.noderr,'String',strcat('Max Node Error: ',... num2str(norm(mynodes -mynodesp,inf)))); set(handles.alpha,'String',strcat('alpha= ',... num2str(alp))); case 9 % least squares polynomial fit dgr = inputdlg('Input degree of polynomial fit: ',... 'Polynomial Fitting of Data'); dgr = max(1,str2num(dgr{1})); pp = polyfit(xnodes,rndynodes,dgr); ppp = polyder(pp); mynodes = polyval(ppp,mxnodes); plot(mxnodes,mynodes,'c-'); set(handles.noderr,'String',strcat('Max Node Error: ',... num2str(norm(mynodes -mynodesp,inf)))); set(handles.alpha,'String',strcat('degree= ',... num2str(dgr))); case 10 % population u(t) with noise for ii = (1:nodes) ynodes(ii) = ufcn(xnodes(ii)); end rndynodes = ynodes+norm(ynodes,inf)*noiselevel/100*(2*rand(size(ynodes))-1); plot(xnodes,rndynodes,'b-'); set(handles.noderr,'String','Noisy u(t)'); set(handles.alpha,'String',''); case 11 % estimate rate r(t)=u'/u, approx by reg spline alp = inputdlg('Input regularization parameter: ',... 'Regularized Natural Cubic Spline'); alp = str2num(alp{1}); for ii = (1:nodes) ynodes(ii) = ufcn(xnodes(ii)); end rndynodes = ynodes+norm(ynodes,inf)*noiselevel/100*(2*rand(size(ynodes))-1); pp = RNCSpp(xnodes,rndynodes,alp); ppp = PPder(pp); mynodes = PPeval(ppp,mxnodes)./PPeval(pp,mxnodes); plot(mxnodes,mynodes,'m-'); set(handles.noderr,'String','(du/dt)/u by regularized NCS for u'); set(handles.alpha,'String',strcat('alpha= ',... num2str(alp))); case 12 % graph centered difference approximate derivative with noise for ii = (1:nodes) ynodes(ii) = ufcn(xnodes(ii)); end rndynodes = ynodes+norm(ynodes,inf)*noiselevel/100*(2*rand(size(ynodes))-1); tmpnodes = [-3*rndynodes(1)+4*rndynodes(2)-rndynodes(3),... (rndynodes(3:nodes)-rndynodes(1:nodes-2)),... rndynodes(nodes-2)-4*rndynodes(nodes-1)+3*rndynodes(nodes)]... /(2*(xnodes(2)-xnodes(1))); tmpnodes = tmpnodes./rndynodes; plot(xnodes,tmpnodes,'g-'); set(handles.noderr,'String','(du/dt)/u by centered diffs for u'); set(handles.alpha,'String',''); case 13 % least squares poly fit dgr = inputdlg('Input degree of polynomial fit: ',... 'Polynomial Fitting of Data'); dgr = max(1,str2num(dgr{1})); for ii = (1:nodes) ynodes(ii) = ufcn(xnodes(ii)); end rndynodes = ynodes+norm(ynodes,inf)*noiselevel/100*(2*rand(size(ynodes))-1); pp = polyfit(xnodes,rndynodes,dgr); ppp = polyder(pp); mynodes = polyval(ppp,mxnodes); plot(mxnodes,mynodes,'c-'); set(handles.noderr,'String','(du/dt)/u by LS poly fit for u'); set(handles.alpha,'String',strcat('degree= ',... num2str(dgr))); otherwise ; end % -------------------------------------------------------------------- function varargout = graphlistbox_Callback(h, eventdata, handles, varargin) % -------------------------------------------------------------------- function varargout = figurenumderiv_CloseRequestFcn(h, eventdata, handles, varargin) closereq; function pp = PP(order,knum,knots,coefs) % usage: pp = PP(order,knum,knots,coefs) % description: given input of at least positive integers order and % knum, this function constructs a PP object with this order and % knum knots. Last two arguments are optional, but if entered, % user must define knots before coefs. If these are not supplied, % the the coef matrix is initialized to zeros and knots to 0:knum-1. % local variables: % j: loop variable if (nargin < 2 | nargin >4) disp('Incorrect paramater list') return; end; pp.order = order; pp.knum = knum; pp.knots = 0:(knum-1); pp.coefs = zeros(knum-1,order); if (nargin >= 3) if (sum([1,knum] ~=size(knots))) disp('Incorrect knots vector') clear pp; return; end; for j = 2:knum if (knots(j) <= knots(j-1)) disp('Knots vector is not strictly increasing') clear pp; return; end; end; pp.knots = knots; end; if (nargin == 4) if (sum([knum-1,order] ~=size(coefs))) disp('Incorrect coefs matrix') clear pp; return; end; pp.coefs = coefs; end; % function y = PPeval(pp,x) % usage: y = PPeval(pp,x) % description: given input pp a PP structure and x a vector of % absicssas, this routine returns the vector of values of the PP % structure pp at the coordinates of x. % local variables: % j,k,m: index variables % n: size of node array % klim: number of knots % ord: order of pp % xtmp: temporary variable n = length(x); y = zeros(size(x)); klim = pp.knum; ord = pp.order; for j = 1:n % loop over entries of x xtmp = x(j); % find index of interval containing entry for k = 1:klim-1 if (xtmp < pp.knots(k+1)) break; end; end; dx = xtmp - pp.knots(k); % use Horner's method to evaluate the polynomial y(j) = pp.coefs(k,1); for m = 2:ord y(j) = dx*y(j)+pp.coefs(k,m); end; end; % function dd = PPder(pp) % usage: dd = PPder(pp) % description: given input pp a PP structure, this function % returns the PP structure representing the derivative of the p.p. % function represented by pp. % local variables: % j,k: index variables % klim: number of knots % ord: order of pp dd.knum = pp.knum; dd.knots = pp.knots; dd.order =pp.order -1; dd.coefs = zeros(dd.knum -1, dd.order); deg = pp.order - 1; for j = 1:dd.knum-1 for k = 1:dd.order dd.coefs(j,k) = (deg-k+1)*pp.coefs(j,k); end; end; % function pp = HCpp(x,f,fp) % usage: pp = HCpp(x,f,fp) % description: this function returns a PP structure representing % the Hermite cubic p.p. with node row vector x, corresponding % function values in the row vector f and derivative values in the % row vector fp. % local variables: % n,m: size of node and value arrays % j: index variable % h: stepsize n = length(x); m= size(f); m = m(1)+m(2)-1; if (m ~= n) % error check for size and order disp('Size mismatch of abscissa and function ordinate'); return; end; m = length(fp); if (m ~= n) % error check for size and order disp('Size mismatch of abscissa and derivative ordinate'); return; end; pp = PP(4, n, x); % determine the poly coefs in each knot subinterval for j = 1:(n-1) % set up and solve the system on this subinterval h = x(j+1) - x(j); pp.coefs(j,:) = ([0, 0, 0, 1; h^3, h^2, h, 1; 0 0 1 0; 3*h^2, 2*h, 1, 0] \ [f(j); f(j+1); fp(j); fp(j+1)] )'; end; % function pp = NKCSpp(xx,ff) % usage: pp = NKCSpp(x,f) % description: this function returns the not-a-knot cubic spline % with nodes at the entries of the row vector of abscissas x and % corresponding ordinates in the row vector f, excluding the % second and penultimate entries of each. % local variables: % x,f: vectors with not-a-knot entries removed % nn,m,n: size of node and value arrays % j: index variable % h: stepsize vector % d: divided difference vector % Coef: coefficient matrix for the system % Rhs: right hand side vector % h0, h1, hnm2, hnm1: extra step sizes % M: vector of second derivative values % coefs: coefficient matrix of PP structure to be returned nn = length(xx); m= length(ff); if (m ~= nn | nn<4) % error check for size and order disp('Size mismatch of abscissa and function ordinate or size problem'); return; end; x = [xx(1), xx(3:nn-2), xx(nn)]; f = [ff(1), ff(3:nn-2), ff(nn)]; n = nn - 2; % adjust size to reflect size of x % construct the stepsize and divided difference vectors h = x(2:n) - x(1:n-1); d = (f(2:n) - f(1:n-1))./h; hh = xx(2:nn) - xx(1:nn-1); % now set up the system as in Atkinson, p. 169, row by row Coef = zeros(n,n); Rhs = zeros(n,1); % first row (use equation of exercise 3.34) Coef(1, 1:2) = [hh(1)+2*hh(2), 2*hh(1)+hh(2)]; Rhs(1) = 6*(ff(1)/hh(1) - h(1)*ff(2)/(hh(1)*hh(2)) + ff(3)/hh(2)); for j = 2:(n-1) % interior rows Coef(j, (j-1):(j+1)) = [h(j-1)/6, (h(j-1)+h(j))/3, h(j)/6]; Rhs(j) = d(j) - d(j-1); end; % last row (use equation of exercise 3.34) Coef(n, (n-1):n) = [hh(nn-2)+2*hh(nn-1), 2*hh(nn-2)+hh(nn-1)]; Rhs(n) = 6*(ff(nn-2)/hh(nn-2) - h(n-1)*ff(nn-1)/(hh(nn-2)*hh(nn-1)) + ff(nn)/hh(nn-1)); % solve for M M = Coef\Rhs; % finally construct the PP structure to be returned coefs = zeros(n-1,4); % given si(x)=ai*(x-xi)^3+bi*(x-xi)^2+ci*(x-xi)+di % we deduce from si''(x)=6*ai*(x-xi)+2*bi that % bi = Mi/2 and ai = (M(i+1)-Mi)/(6*hi) coefs(:,2) = M(1:n-1)/2; coefs(:,1) = (M(2:n) - M(1:n-1))./(6*h'); % evaulation gives di = yi and ci = (y(i+1) - ai*hi^3-bi*hi^2-di)/hi coefs(:,4) = f(1:n-1)'; coefs(:,3) = (f(2:n)' - coefs(:,1).*h'.^3 - coefs(:,2).*h'.^2 - coefs(:,4)) ./ h'; pp = PP(4,n,x,coefs); % function pp = NCSpp(x,f) % usage: pp = NCSpp(x,f) % description: this function returns the natural cubic spline % with nodes at the entries of the row vector of abscissas x and % corresponding ordinates in the row vector f. % local variables: % n,m: size of node and value arrays % j: index variable % h: stepsize vector % d: divided difference vector % Coef: coefficient matrix for the system % Rhs: right hand side vector % M: vector of second derivative values % coefs: coefficient matrix of PP structure to be returned n = length(x); m= length(f); if (m ~= n) % error check for size and order disp('Size mismatch of abscissa and function ordinate'); return; end; % construct the stepsize and divided difference vectors h = x(2:n) - x(1:n-1); d = (f(2:n) - f(1:n-1))./h; % now set up the system as in Atkinson, p. 169, row by row Coef = zeros(n,n); Rhs = zeros(n,1); % first row Coef(1, 1) = 1; Rhs(1) = 0; for j = 2:(n-1) % interior rows Coef(j, (j-1):(j+1)) = [h(j-1)/6, (h(j-1)+h(j))/3, h(j)/6]; Rhs(j) = d(j) - d(j-1); end; % last row Coef(n, n) = 1; Rhs(n) = 0; % solve for M M = Coef\Rhs; % finally construct the PP structure to be returned coefs = zeros(n-1,4); % given si(x)=ai*(x-xi)^3+bi*(x-xi)^2+ci*(x-xi)+di % we deduce from si''(x)=6*ai*(x-xi)+2*bi that % bi = Mi/2 and ai = (M(i+1)-Mi)/(6*hi) coefs(:,2) = M(1:n-1)/2; coefs(:,1) = (M(2:n) - M(1:n-1))./(6*h'); % evaulation gives di = yi and ci = (y(i+1) - ai*hi^3-bi*hi^2-di)/hi coefs(:,4) = f(1:n-1)'; coefs(:,3) = (f(2:n)' - coefs(:,1).*h'.^3 - coefs(:,2).*h'.^2 - coefs(:,4)) ./ h'; pp = PP(4,n,x,coefs); function pp = RNCSpp(x,a,alp) % usage: pp = RNCSpp(x,a,alp) % description: this function returns the regularized natural % cubic spline with nodes at the entries of the vector % of abscissas x and corresponding ordinates in the % vector a. Here alp is the regularization parameter. % Given that the unregularized system is R*c=Q*a, where c is % the column of moments (2nd deriv values), with % both R and Q tridiagonal and diagonally dominant, % the regularized system is % (R + alp*Q*Q^{T}*R^{-1})*c = Q*a % which is equivalent to the interpolating natural cubic % spline when alp=0. % local variables: % n,m: size of node and value arrays % j: index variable % h: stepsize vector % R: coefficient matrix for the system % Q: coefficient matrix for right hand side vector % c: vector of second derivative values % coefs: coefficient matrix of PP structure to be returned % columnize the input data [m,n]=size(x); if (n > 1) x = x'; end; [m,n] = size(a); if (n > 1) a = a'; end; n = length(x); m= length(a); if (m ~= n) % error check for size and order disp('Size mismatch of abscissa and function ordinate'); return; end; % construct the stepsize and divided difference vectors h = x(2:n) - x(1:n-1); % now set up the system as in my notes along lines of de Boor R = zeros(n,n); Q = R; % first row R(1,1) = 1; Q(1,1) = 1; for j = 2:(n-1) % interior rows R(j,(j-1):(j+1)) = [h(j-1), (h(j-1)+h(j))*2, h(j)]; Q(j,(j-1):(j+1)) = [3/h(j-1), -3/h(j-1)-3/h(j), 3/h(j)]; end; % last row R(n,n) = 1; Q(n,n) = 1; % fix R to be symmetric R(2,1) = 0; R(n-1,n) = 0; % solve for c c = (R+alp*Q*Q'*inv(R))\(Q*a); % find new nodes for spline a = Q\(R*c); % fix first and last entries, currently spline values at end nodes c(1) = 0; c(n) = 0; % finally construct the PP structure to be returned coefs = zeros(n-1,4); % given si(x)=ai+bi*(x-xi)+ci*(x-xi)^2+di*(x-xi)^3 % we deduce from si''(x)=6*di*(x-xi)+2*ci that % ai = (ci(+1)-ci)/(3*hi) coefs(:,2) = c(1:n-1); coefs(:,1) = (c(2:n) - c(1:n-1))./(3*h); % evaulation gives ai = yi and bi = (y(i+1) - di*hi^3-ci*hi^2-ai)/hi coefs(:,4) = a(1:n-1); coefs(:,3) = (a(2:n) - coefs(:,1).*h .^3 - coefs(:,2).*h .^2 - ... coefs(:,4)) ./ h; pp = PP(4,n,x',coefs);