Matlab interp2() gives 'monotonically increasing' error - matlab

I have many lines that represent a "z" value and want to interpolate at a specific value between them, at a specific x-axis location, to get the y-value. I'm trying interp2() but it throws a 'monotonically increasing' error.
The dataset below is a subset. I broke it out into xyz-1 and xyz-2 just for easy plotting in this question (i.e., making a repeatable example). How can I fix my interp2() or the inputs?
x1 = [0.02, 0.048, 0.108, 0.196, 0.279, 0.401];
y1 = [0.583, 0.43, 0.32, 0.279, 0.262, 0.259];
z1 = [50, 50, 50, 50, 50, 50];
x2 = [0.02, 0.048, 0.108, 0.196, 0.279, 0.401];
y2 = [0.747, 0.591, 0.435, 0.357, 0.326, 0.305];
z2 = [35, 35, 35, 35, 35, 35];
x_all = [x1, x2];
y_all = [y1, y2];
z_all = [z1, z2];
plot(x1, y1, 'blue', 'DisplayName', 'z1')
hold on
plot(x2, y2, 'magenta', 'DisplayName', 'z2')
xlabel('x')
ylabel('y')
legend
want_x = 0.2;
want_z = 40;
need_y = interp2(x_all, y_all, z_all, want_x, want_z, 'linear')
Error:
Error using griddedInterpolant
The grid vectors must be strictly monotonically increasing.
Error in interp2>makegriddedinterp (line 228)
F = griddedInterpolant(varargin{:});
Error in interp2 (line 128)
F = makegriddedinterp({X, Y}, V, method,extrap);

The function griddata is your friend for these tasks, It uses scatteredInterpolant under the hood, but in my opinion is more user friendly.
Keeping the same example code you gave, replacing the last line with:
>> need_y = griddata(x_all,z_all,y_all,want_x, want_z)
need_y =
0.329506024096386
The function can take vector inputs for want_x and want_z and return a vector output of need_y if you need to query more than one point.
You can also specify the interpolation method (linear, cubic, etc ...).
And just to make sure it worked as desired:
>> F = scatteredInterpolant(x_all.', z_all.', y_all.', 'linear'); %NOT y_all, z_all
need_y = F(want_x, want_z)
need_y =
0.329506024096386 % same result, yay!
For more details about using griddata, you can have a look at my answer to this question extremely similar to yours (just worded a bit differently): Interpolation between two curves (matlab)

You can interpolate the value with:
x1 = [0.02, 0.04, 0.09, 0.184, 0.309, 0.667];
y1 = [0.586, 0.447, 0.34, 0.279, 0.256, 0.256];
z1 = [50, 50, 50, 50, 50, 50];
x2 = [0.022, 0.044, 0.076, 0.125, 0.184, 0.293, 0.509, 0.667];
y2 = [0.747, 0.6, 0.49, 0.41, 0.363, 0.326, 0.303, 0.3];
z2 = [35, 35, 35, 35, 35, 35, 35, 35];
want_x = 0.2;
want_z = 40;
y1_ = interp1(x1, y1, want_x);
y2_ = interp1(x2, y2, want_x);
want_y = interp1([50 35], [y1_ y2_], want_z);

This question was answered here:
https://www.mathworks.com/matlabcentral/answers/637955-interp2-monotonically-increasing-error
quoting from that answer, in case the link breaks in the future:
interp2() is only for two-dimensional interpretation over a grid, not for interpolation of vectors. You need something like
F = scatteredInterpolatn(x_all, z_all, y_all, 'linear'); %NOT y_all, z_all
need_y = F(want_x, want_z);

Related

How do I use code to generate a graph where the line crosses the origin in Matlab?

I am trying to use Matlab to generate a line graph, but the line terminates at the last point, and doesn't go all the way to the origin. Is there any way to make it so that the line goes beyond the points in code?
I've attached the code that I'm currently using, along with pictures of what the graph looks like right now and how I want it to look.
%Enter Data
fnet = [0.465, 0.560, 0.670, 0.763, 0.870, 0.971, 1.063];
faccel = [0.434, 0.514, 0.612, 0.684, 0.776, 0.850, 0.915];
asys = [0.4963, 0.6034, 0.7074, 0.8088, 0.9210, 1.030, 1.138]
mh = [0.050, 0.06, 0.07, 0.08, 0.09, 0.1, 0.11]
x = fnet;
y = asys;
%Model Equation
model = 'm*x'
%the model can be changed, ex. m*x^2
IV = 'x'
DV = 'y'
%Create and perform curve fit
newfit = fittype(model, 'Independent', IV, 'Dependent', DV);
%result and goodness of fit, prime symbol converys rows to columns
[result, gof] = fit(x', y', newfit, 'StartPoint', 1)
%plot fits and data points, create plot object for formatting
p = plot(result, x, y);
%style the data points
p(1).MarkerSize = 10;
p(1).Marker = '.';
p(1).MarkerFaceColor = 'blue';
%p(1).MarkerEdgeColor = 'green';
%style the line of best fit
p(2).LineWidth = 1;
p(2).Color = 'black';
%Create graph object, set formatting to latex
graph = gca;
set(graph, 'defaultTextInterpreter', 'latex');
set(legend, 'visible', 'off');
%format title and subtitle
graph.Title.String = {'System Acceleration vs. Net Force on System', 'in Modified Atwood Machine'};
graph.Title.FontSize = 16;
%subtitle, where we will place our equation and statistics
%specifically, the equation w/ units, r squared, slope with plusminus %
graph.Subtitle.Interpreter = 'latex';
graph.Subtitle.String = '$a_{sys} = 1.064 m^{-1}F_{net}, \, r^2=0.9994, m=1.064 \pm 0.007$';
graph.Subtitle.FontSize = 13;
%format x and y axes
graph.XLabel.Interpreter = 'latex';
graph.XLabel.String = '$F_{net} \: (N)$';
graph.XLabel.FontSize = 15;
graph.XLim = [0,1.5];
graph.XGrid = 'on';
graph.XMinorGrid = 'on';
graph.XMinorTick = 'on';
graph.YLabel.Interpreter = 'latex';
graph.YLabel.String = '$a_{sys} \: (\frac{m}{s^2})$';
graph.YLabel.FontSize = 15;
graph.YLim = [0,1.5];
graph.YGrid = 'on';
graph.YMinorGrid = 'on';
graph.YMinorTick = 'on';
Instead of using plot directly on the fit result object, you can call plot with a bit more control and evaluate the result directly for the line
Replace this:
p = plot(result, x, y);
with this:
hold on
p(1) = plot( x, y );
p(2) = plot( [0,2.2], feval(result, [0,2.2]) );
Note you could add the marker and line options during the plot calls now if you wanted, instead of updating p(1) and p(2) in retrospect.

Get Y value of line from X pixel value in ChartJS 2

I have a line graph in chartjs, and I want to find the Y value for an arbitrary point on the line given the pixel value from the x axis.
My Graph
Currently I'm hooking into the afterDatasetsDraw event to add that shaded region to the graph, but I also want to find out the values of the black line (Axis B) at the start and end of the shaded region, which don't necessarily line up with my data points.
afterDatasetsDraw: function (chart) {
var options = chart.config.options.plugins.shader;
if (!options.hasOwnProperty('points')) {
return;
}
if (options.points.length < 2) {
return;
}
var ctx = chart.chart.ctx;
var x1, y1, x2, y2, x3, y3, x4, y4, x0, xf;
console.log(chart);
x0 = chart.scales['x-axis-0'].left;
xf = chart.scales['x-axis-0'].right;
x1 = ((xf - x0) * 0.12) + x0; // start shading at 12% in for example
y1 = chart.scales['A'].bottom;
x2 = x1;
y2 = chart.scales['A'].top;
x3 = ((xf - x0) * 0.66) + x0; // end shading at 66% for example
y3 = y2;
x4 = x3;
y4 = y1;
// console.log(chart.scales['B'].getValueForPixel(x1));
// console.log(chart.scales['B'].getValueForPixel(x3));
// console.log(chart.scales['A'].getValueForPixel(x1));
// console.log(chart.scales['A'].getValueForPixel(x3));
// console.log(chart.scales['x-axis-0'].getValueForPixel(x1));
// console.log(chart.scales['x-axis-0'].getValueForPixel(x3));
ctx.fillStyle = 'rgba(127, 127, 127, 0.3)';
ctx.beginPath();
ctx.moveTo(x1,y1);
ctx.lineTo(x2, y2);
ctx.lineTo(x3, y3);
ctx.lineTo(x4, y4);
ctx.lineTo(x1,y1);
ctx.closePath();
ctx.fill();
}
});
I would assume from the docs that I could use the scales getValueForPixel() method (as is shown commented out) but those are returning strange values. The X-axis values are coming back as 1 and 3 which as far as I can tell are the indexes of the closest data point. The Y scales are returning numbers that don't correspond with anything in the dataset or the rendered graph.

Looping through points in the unit triangle

I have a problem where I have two choice variables x1 and x2 which then pin down a third x3 = 1 - x1 - x2. I would like to loop through various values of [x1, x2, x3]. This code works:
w1 = perms([0.1, 0.1, 0.8]);
w2 = perms([0.1, 0.2, 0.7]);
w3 = perms([0.1, 0.3, 0.6]);
w4 = perms([0.1, 0.4, 0.5]);
w5 = perms([0.2, 0.2, 0.6]);
w6 = perms([0.2, 0.3, 0.5]);
w7 = perms([0.2, 0.4, 0.4]);
w8 = perms([0.3, 0.3, 0.4]);
w = [w1; w2; w3; w4; w5; w6; w7; w8];
w = unique(w,'rows');
% loop
for ii = 1:size(w, 1)
... do some stuff with w(ii, :)
but I am wondering if there is a more elegant way to do this.
This is a classical case for ndgrid
[x1,x2]=ndgrid(0.1:0.1:0.8,0.1:0.1:0.8);
x3 = 1-x1-x2;
%I assume from your example that we want x1,x2,x3 in (0,1) OPEN interval, then:
valid_points = x3>0 & x3 <1
w_prime = [x1(valid_points),x2(valid_points),x3(valid_points)];

Fminsearch Matlab (Non Linear Regression )

Can anyone explain to me how I can apply non linear regression to this equation t find out K using the matlab command window.
I = 10^-9(exp(38.68V/k)-1).
Screenshot of Equation
I have data values as follows:
Voltage := [0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0]:
Current:= [0, 0, 0, 0, 0, 0, 0, 0.07, 0.92, 12.02, 158.29]:
Screenshot of Equation
[NEW]: Now I used FminSearch as an alternative another and another error message appeared.
Matrix dimensions must agree.
Error in #(k)sum((I(:)-Imodel(V(:),k)).^2)
Error in fminsearch (line 189)
fv(:,1) = funfcn(x,varargin{:});
I used this fminsearch code:
>> V = [0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0];
>> I = [0, 0, 0, 0, 0, 0, 0.07 ,0.92 ,12.02 ,158.29];
>> Imodel = #(V,k) 1E-9*(exp(38.68*V/k)-1);
>> k0 = 1;
>> kmodel = fminsearch(#(k) sum((I(:)-Imodel(V(:),k)).^2), k0)
>> kmodel = fminsearch(#(k) sum((I(:)-Imodel(V(:),k)).^2), k0);
You want to find the parameter k that will minimize the sum of squared error of your exponential model (BTW, is that a current/voltage characteristic?) given the current data I and voltage data V as vectors:
Imodel = #(V,k) 1E-9*(exp(38.68*V/k)-1);
k0 = 1;
kmodel = fminsearch(#(k) sum((I(:)-Imodel(V(:),k)).^2), k0);
plot(V(:), I(:), 'ok', V(:), Imodel(V(:),kmodel), '-r');
The anonymous function calculates the sum of squared error. The search for the parameter k that will minimize the model error starts with the value 1; please change it to a more appropriate value (if you have a good guess for it).

How to numerically integrate with infinite limit in MATLAB?

I want to numerically integrate an integral with infinite limit. Does anyone have any idea how should I do that?
int(x* exp (v*x + (1-exp(v*x))/v),x, o , inf) does not work.
Note that I will have values for v.
%n=10;
kappa=.5;
delta0=.5;
Vmax=500;
Vdep=2.2;
l=2.2;
kbT=4.1;
%xb=.4;
fb=10;
k=1;
V0=5;
e1=(fb*l/kbT)*(kappa/delta0);
e2=Vmax/V0;
e3=Vdep/V0;
w=zeros(1,25);
for v=1:25
w(:,v)=integral(#(x) x.*exp(v*x+((1-exp(v*x))/v)),0,inf);
end
e12=e2*exp(-e1*(1:25).*w.^2)-e3;
plot(e12);
ylim([0 25]);
hold on;
plot(0:25,0:25);
xlim([0 25]);
%hold off;
The plot is not matching the real data in the article!(for the e12 curve specially)
I need to calculate the intersection of the 2 curves (which is ~13.8 based on the paper) and then in the second part I have to add a term in e12 which contains an independent variable:
v=13.8;
w= integral(#(x) x.*exp(v*x+((1-exp(v*x))/v)),0,inf)
e4 = zeros (1,180);
fl = 1:180;
e4(:,fl)= (fl*l/kbT)*(kappa/n);
e12=e2*exp(-e1*v*w^2-e4)-e3
But again the problem is that running this code I will end with a negative value for e12 which should be just approaching zero in large values of fl (fl>160)
to show how this code is different from the expected curve you can plot these data on the same figure:
fl = [0, 1, 4, 9, 15, 20, 25, 40, 60, 80, 100, 120, 140, 160, 180];
e12 = [66, 60, 50, 40, 30, 25.5, 20, 15.5, 10.5, 8.3, 6.6, 5, 2.25, 1.1, 0.5];
which obviously does not match the curve generated by the code.
Assuming the question is about this full code:
syms x;
v = 1; % For example
int(x*exp(v*x + (1-exp(v*x))/v),x, 0, Inf)
and the issue is that it returns itself (i.e., int doesn't find an analytic solution), one can set the 'IgnoreAnalyticConstraints' option to true (more details) to get a solution:
syms x;
v = 1; % For example
int(x*exp(v*x + (1-exp(v*x))/v),x, 0, Inf, 'IgnoreAnalyticConstraints', true)
returns -ei(-1)*exp(1), where ei is the exponential integral function (see also expint for numerical calculations). For negative values of v the solution will also be in terms of eulergamma, the Euler-Mascheroni constant. And of course the integral is undefined if v is 0.
Using Mathematica 10.0.2's Integrate yields a full solution for symbolic v.
Integrate[x Exp[v x - (Exp[v x] - 1)/v], {x, 0, Infinity}]
returns
ConditionalExpression[(E^(1/v) (EulerGamma + Gamma[0, 1/v] + Log[1/v]))/v, Re[v] < 0]
Applying Assumptions:
Integrate[x Exp[v x - (Exp[v x] - 1)/v], {x, 0, Infinity}, Assumptions -> v > 0]
Integrate[x Exp[v x - (Exp[v x] - 1)/v], {x, 0, Infinity}, Assumptions -> v < 0]
returns
(E^(1/v) Gamma[0, 1/v])/v
and
(E^(1/v) (2 EulerGamma - 2 ExpIntegralEi[-(1/v)] + Log[1/v^2]))/(2 v)
where Gamma is the upper incomplete gamma function. These appear match up with the results from Matlab.
To evaluate these numerically in Matlab:
% For v > 0
v_inv = 1./v;
exp(v_inv).*expint(v_inv).*v_inv
or
% For v < 0
v_inv = 1./v;
exp(v_inv).*(2*double(eulergamma)+2*(expint(v_inv)+pi*1i)+log(v_inv.^2)).*v_inv/2
Numerical integration is performed by summing the function at discrete points with distance dx. The smaller dx you choose, the better approximation you get. For example integrating from x=0 to x=10 is done by:
x = 0:dx:10;
I = sum(x.* exp (v*x + (1-exp(v*x))/v))*dx;
obviously, you can't do that for x=inf. But I believe you function decays rapidly. Therefore, you can assume that x* exp (v*x + (1-exp(v*x))/v) = 0 for large enough x. Otherwise the integral is divergent. So all you have to do is set the limit on x. If you are not sure what the limit should be, you can perform a loop with a stopping condition:
I = 0;
prevI = -1;
x = 0;
while abs(I-prevI)>err
prevI = I;
I = I + x.* exp (v*x + (1-exp(v*x))/v)*dx;
x = x + dx;
end
Now, all you have to do is set the desired dx and err
You must read this:Mathwork Link
perhaps you are making a mistake in the function that you use. Also note that MATLAB syntax is case sensitive..