Matlab: Getting the Coefficients of Piecewise Cubic Hermite Interpolating Polynomial - matlab

I want to fit a curve to some data. I used a PCHIP interpolation because of getting the best results. Moreover, I want to get the coefficients for the 6 intervals with the ppval-function. But there pops up an error like these:
Error using unmkpp (line 18)
The input array does not seem to describe a pp function.
Error in ppval (line 62)
[b,c,l,k,dd]=unmkpp(pp);
Error in SA (line 8)
v = ppval(p,xdata)
This is my code:
clear all
xdata = [0; 3.5; 6.8; 7.6; 8.2; 30; 34.2];
ydata = [0; 50; 400000; 2000000; 25000000; 100000000;100000000]
xq1 = 0:0.01:35;
p = pchip(xdata,ydata, xq1);
s = spline(xdata,ydata,xq1);
v = ppval(p,xdata)
plot(xdata,ydata,'o',xq1,p,'-',xq1,s,'-.');
legend('Datenpunkte','pchip','spline','Location','SouthEast');
Can you help me?
Best regards
Dominik

pchip has two working modes:
Calculating the piecewise polynomial coefficients: pp = pchip(x,y):
returns a piecewise polynomial structure for use with ppval
Interpolating at specified points: p = pchip(x,y,xq):
is the same as p = ppval(pchip(x,y),xq)
returns a vector of interpolated values p corresponding to the query
points in xq
So, you are using the second mode, which is not suited for use with ppval.

Related

Why matlab gives fminsearch optimisation error?

I have such an question, And I will do it in matlab. But, I get some errors:
Find the value of x ∈ [0, 1] that minimizes the largest eigenvalue of the matrix A(x) = xM +(1−x)P, where M is a 5×5 magic square and P is a 5 × 5 Pascal matrix.
My matlab code:
%Define Matrices
M = magic(5);
P = pascal (5);
% Define the variable x
syms x
%Define the given matrix A
>> A = x*M + (1-x)*P;
%Define the eigenvalue lambda as y;
syms y
%Find determinant of |A - lambda * I|
D = det (A - y*eye(5))
%Define Objective function
objective = #(y) y
%And Define the constraint
constraint = #(x,y) (-1)*D
%initial value x0 = (0:0.001:1);
%Minimization problem solving
x = fmincon(objective, constraint, x0)
I get this error;
Error using fmincon (line 221)
FMINCON requires the following inputs to be of data type double: 'X0'.
Or If I use another function: fminsearch
x = fminsearch(objective, constraint, x0)
In this case I get the following error:
Error using fminsearch (line 96)
FMINSEARCH accepts inputs only of data type double.
How can I deal with these errors ? Where is my mistake? How can I correct them?
I guess what you are looking for might be fminbnd, which helps to
Find minimum of single-variable function on fixed interval
n = 5;
M = magic(n);
P = pascal(n);
x = fminbnd(#(x) max(eig(x*M + (1-x)*P)),0,1);
such that
>> x
x = 0.79603
I suspect you did not show us the proper code, as you have sums there. I suspect you mean syms.
fmincon only works for numeric data, not symbolic data.

Interpolation using chebyshev points

Interpolate the Runge function of Example 10.6 at Chebyshev points for n from 10 to 170
in increments of 10. Calculate the maximum interpolation error on the uniform evaluation
mesh x = -1:.001:1 and plot the error vs. polynomial degree as in Figure 10.8 using
semilogy. Observe spectral accuracy.
The runge function is given by: f(x) = 1 / (1 + 25x^2)
My code so far:
x = -1:0.001:1;
n = 170;
i = 10:10:170;
cx = cos(((2*i + 1)/(2*(n+1)))*pi); %chebyshev pts
y = 1 ./ (1 + 25*x.^2); %true fct
%chebyshev polynomial, don't know how to construct using matlab
yc = polyval(c, x); %graph of approx polynomial fct
plot(x, yc);
mErr = (1 / ((2.^n).*(n+1)!))*%n+1 derivative of f evaluated at max x in [-1,1], not sure how to do this
%plotting stuff
I know very little matlab, so I am struggling on creating the interpolating polynomial. I did some google work, but I was confused with the current functions as I didn't find one that just simply took in points and the polynomial to be interpolated. I am also a bit confused in this case of whether I should be doing i = 0:1:n and n=10:10:170 or if n is fixed here. Any help is appreciated, thank you
Since you know very little about MATLAB, I will try explain everything step by step:
First, to visualize the Runge function, you can type:
f = #(x) 1./(1+25*x.^2); % Runge function
% plot Runge function over [-1,1];
x = -1:1e-3:1;
y = f(x);
figure;
plot(x,y); title('Runge function)'); xlabel('x');ylabel('y');
The #(x) part of the code is a function handle, a very useful feature of MATLAB. Notice the function is properly vecotrized, so it can receive as an argument a variable or an array. The plot function is straightforward.
To understand the Runge phenomenon, consider a linearly spaced vector of [-1,1] of 10 elements and use these points to obtain the interpolating (Lagrange) polynomial. You get the following:
% 10 linearly spaced points
xc = linspace(-1,1,10);
yc = f(xc);
p = polyfit(xc,yc,9); % gives the coefficients of the polynomial of degree 10
hold on; plot(xc,yc,'o',x,polyval(p,x));
The polyfit function does a polynomial curve fitting - it obtains the coefficients of the interpolating polynomial, given the poins x,y and the degree of the polynomial n. You can easily evaluate the polynomial at other points with the polyval function.
Obseve that, close to the end domains, you get an oscilatting polynomial and the interpolation is not a good approximation of the function. As a matter of fact, you can plot the absolute error, comparing the value of the function f(x) and the interpolating polynomial p(x):
plot(x,abs(y-polyval(p,x))); xlabel('x');ylabel('|f(x)-p(x)|');title('Error');
This error can be reduced if, instead of using a linearly space vector, you use other points to do the interpolation. A good choice is to use the Chebyshev nodes, which should reduce the error. As a matter of fact, notice that:
% find 10 Chebyshev nodes and mark them on the plot
n = 10;
k = 1:10; % iterator
xc = cos((2*k-1)/2/n*pi); % Chebyshev nodes
yc = f(xc); % function evaluated at Chebyshev nodes
hold on;
plot(xc,yc,'o')
% find polynomial to interpolate data using the Chebyshev nodes
p = polyfit(xc,yc,n-1); % gives the coefficients of the polynomial of degree 10
plot(x,polyval(p,x),'--'); % plot polynomial
legend('Runge function','Chebyshev nodes','interpolating polynomial','location','best')
Notice how the error is reduced close to the end domains. You don't get now that high oscillatory behaviour of the interpolating polynomial. If you plot the error, you will observe:
plot(x,abs(y-polyval(p,x))); xlabel('x');ylabel('|f(x)-p(x)|');title('Error');
If, now, you change the number of Chebyshev nodes, you will get an even better approximation. A little modification on the code lets you run it again for different numbers of nodes. You can store the maximum error and plot it as a function of the number of nodes:
n=1:20; % number of nodes
% pre-allocation for speed
e_ln = zeros(1,length(n)); % error for the linearly spaced interpolation
e_cn = zeros(1,length(n)); % error for the chebyshev nodes interpolation
for ii=1:length(n)
% linearly spaced vector
x_ln = linspace(-1,1,n(ii)); y_ln = f(x_ln);
p_ln = polyfit(x_ln,y_ln,n(ii)-1);
e_ln(ii) = max( abs( y-polyval(p_ln,x) ) );
% Chebyshev nodes
k = 1:n(ii); x_cn = cos((2*k-1)/2/n(ii)*pi); y_cn = f(x_cn);
p_cn = polyfit(x_cn,y_cn,n(ii)-1);
e_cn(ii) = max( abs( y-polyval(p_cn,x) ) );
end
figure
plot(n,e_ln,n,e_cn);
xlabel('no of points'); ylabel('maximum absolute error');
legend('linearly space','chebyshev nodes','location','best')

How to smooth a stairstep-like graph in Matlab

The stairstep-look of the graph is unintentional. When I plot the same-sized vectors Arb and V (plot (Arb, V, 'r')) I get the following graph:
enter image description here
To make it smoother, I tried using 1-D data interpolation, interp1, as follows:
xq = 0:0.001:max(Arb);
Vq = interp1 (Arb, V, xq);
plot (xq, Vq);
However, I get this error message:
Error using interp1>reshapeAndSortXandV (line 416)
X must be a vector.
Error in interp1 (line 92)
[X,V,orig_size_v] = reshapeAndSortXandV(varargin{1},varargin{2})
interp1 will use linear interpolation on your data so it won't help you much. One thing you can try is to use a cubic spline with interp1 but again given the nature of the data I don't think it will help much. e.g.
Alternative 1. Cubic Spline
xq = 0:0.001:max(Arb);
Vq = interp1 (Arb, V, xq, 'spline');
plot (xq, Vq);
Alternative 2. Polynomial fit
Another alternative you can try is, polynomial interpolation using polyfit. e.g.
p = polifit(Arb, V, 2); % I think a 2nd order polynomial should do
xq = 0:0.001:max(Arb);
Vq = polyval(p, xq);
plot (xq, Vq);
Alternative 3. Alpha-beta filter
Last but not least, another thing to try is to use an smoothing alpha-beta filter on your V data. One possible implementation can be:
% x is the input data
% a is the "smoothing" factor from [0, 1]
% a = 0 full smoothing
% a = 1 no smoothing
function xflt = alphaBeta(x, a)
xflt = zeros(1,length(x));
xflt(1) = x(1);
a = max(min(a, 1), 0); % Bound coefficient between 0 and 1;
for n = 2:1:length(x);
xflt(n) = a * x(n) + (1 - a) * xflt(n-1);
end
end
Usage:
plot (Arb, alphaBeta(V, 0.65), 'r')

how to integrate this Function in matlab

I'm new on matlab.
How can I integrate this line of code ? ?
p2= polyfit(x,y,length(x));
from= x(1);
to= x(length(x));
I need the integration of p2.
I tried a lot with the Integration function:
value = integral(p2,from,to);
but I got
Error using integral (line 82) First input argument must be a function
handle.
Error in poly_integral (line 5)
value = integral(p2,from,to);
That is because p2, in your code, is not a function. It is just a vector of coefficients. The first argument for integral needs to be handle to the function that you want to integrate.
Judging from your code, it seems that you would want to define a function that evaluates the polynomial p2. If so, you could do something like the following example:
% take an example set of x and y
x = linspace(0, pi, 1000); % uniform samples between 0 to pi
y = sin(x); % assume, for sake of example, output is sine function of input
% polynomial fit
p2 = polyfit(x,y,4); % 4th order polynomial
% Note that, in general, the order should be much smaller than length(x).
% So you probably should review this part of your code as well.
% define a function to evaluate the polynomial
fn = #(x) polyval(p2, x);
% this means: fn(x0) is same as polyval(p2, x0)
% compute integral
value = integral(fn,x(1),x(end));
You can use the polyint function to get the polynomial coefficients for exact integration of the polynomial:
p2 = polyfit(x,y,length(x));
int = diff(polyval(polyint(p2),x([1 end])));

Plot symbolic equation using standard plot function in Matlab

In order to obtain a graphical representation of the behaviour of a fluid it is common practice to plot its streamlines.
For a given two-dimensional fluid with speed components u = Kx and v = -Ky (where K is a constant, for example: K = 5), the streamline equation can be obtained integrating the flow velocity field components as follows:
Streamline equation: ∫dx/u = ∫dy/v
The solved equation looks like this: A = B + C (where A is the solution of the first integral, B is the solution of the second integral and C is an integration constant).
Once we have achieved this, we can start plotting a streamline by simply assigning a value to C, for example: C = 1, and plotting the resulting equation. That would generate a single streamline, so in order to get more of them you need to iterate this last step assigning a different value of C each time.
I have successfully plotted the streamlines of this particular flow by letting matlab integrate the equation symbolically and using ezplot to produce a graphic as follows:
syms x y
K = 5; %Constant.
u = K*x; %Velocity component in x direction.
v = -K*y; %Velocity component in y direction.
A = int(1/u,x); %First integral.
B = int(1/v,y); %Second integral.
for C = -10:0.1:10; %Loop. C is assigned a different value in each iteration.
eqn = A == B + C; %Solved streamline equation.
ezplot(eqn,[-1,1]); %Plot streamline.
hold on;
end
axis equal;
axis([-1 1 -1 1]);
This is the result:
The problem is that for some particular regions of the flow ezplot is not accurate enough and doesn't handle singularities very well (asymptotes, etc.). That's why a standard "numeric" plot seems desirable, in order to obtain a better visual output.
The challenge here is to convert the symbolic streamline solution into an explicit expression that would be compatible with the standard plot function.
I have tried to do it like this, using subs and solve with no success at all (Matlab throws an error).
syms x y
K = 5; %Constant.
u = K*x; %Velocity component in x direction.
v = -K*y; %Velocity component in y direction.
A = int(1/u,x); %First integral.
B = int(1/v,y); %Second integral.
X = -1:0.1:1; %Array of x values for plotting.
for C = -10:0.1:10; %Loop. C is assigned a different value in each iteration.
eqn = A == B + C; %Solved streamline equation.
Y = subs(solve(eqn,y),x,X); %Explicit streamline expression for Y.
plot(X,Y); %Standard plot call.
hold on;
end
This is the error that is displayed on the command window:
Error using mupadmex
Error in MuPAD command: Division by zero.
[_power]
Evaluating: symobj::trysubs
Error in sym/subs>mupadsubs (line 139)
G =
mupadmex('symobj::fullsubs',F.s,X2,Y2);
Error in sym/subs (line 124)
G = mupadsubs(F,X,Y);
Error in Flow_Streamlines (line 18)
Y = subs(solve(eqn,y),x,X); %Explicit
streamline expression for Y.
So, how should this be done?
Since you are using subs many times, matlabFunction is more efficient. You can use C as a parameter, and solve for y in terms of both x and C. Then the for loop is very much faster:
syms x y
K = 5; %Constant.
u = K*x; %Velocity component in x direction.
v = -K*y; %Velocity component in y direction.
A = int(1/u,x); %First integral.
B = int(1/v,y); %Second integral.
X = -1:0.1:1; %Array of x values for plotting.
syms C % C is treated as a parameter
eqn = A == B + C; %Solved streamline equation.
% Now solve the eqn for y, and make it into a function of `x` and `C`
Y=matlabFunction(solve(eqn,y),'vars',{'x','C'})
for C = -10:0.1:10; %Loop. C is assigned a different value in each iteration.
plot(X,Y(X,C)); %Standard plot call, but using the function for `Y`
hold on;
end