Matlab - second derivative of data - matlab

Let's say we have
[x]=[0.1 0.2 0.3 0.4]
[y]=[0.25 0.30 0.40 0.55]
y1=diff(y)./diff(x)
y2=diff(y1)./diff(x)
And the result I get is
Matrix dimensions must agree
How do I solve this problem?

I redirect you towards this documentation. When you use the diff function, it will actually return you a vector with m-1 (m being its length), since what it does is output this:
diff(y1) = [y1(2)-y1(1) y1(3)-y1(2) ... y1(m)-y(m-1)]
As you can see, you will loose one value, and thus explaining your error. When you do your last line, it cannot divide diff(y1) by diff(x) since diff(y1) is equal to a vector of length 2 and diff(x) is equal to a vector of length 3.
Depending on what you want to do, you can change the code to the following :
[x]=[0.1 0.2 0.3 0.4]
[y]=[0.25 0.30 0.40 0.55]
y1=diff(y)./diff(x)
y2=diff(y1)./diff(x(1:end-1))
If you want to approximate the derivate of y, I really suggest you to take a look at the example in the page I linked. The matlab documentation always gives examples on how to use their functions, so go take a look. According to the documentation, if you want to calculate the partial derivate of the vector y, you need the step of your x vector.
x=[0.1 0.2 0.3 0.4]
y=[0.25 0.30 0.40 0.55]
x_step = 0.1
y1=diff(y)./x_step
y2=diff(y1)./x_step

x=[0.1 0.2 0.3 0.4] ;
y=[0.25 0.30 0.40 0.55] ;
dy = gradient(y)./gradient(x) ;
d2y = gradient(dy)./gradient(x) ;

Related

How do I stack matrices in KDB?

I'm trying to insert a new row at the beginning of a matrix, but the result is inserting my row vector rotated:
a: (.7 .3; .1 .2)
b: (.5 .5)
b, a
0.5
0.5
0.7 0.3
0.1 0.2
Intended result:
0.5 0.5
0.7 0.3
0.1 0.2
What am I doing wrong?
(enlist b), a gives the result you want. It helps to think of a as being made from nested lists, hence any new rows should be of this form as well.
Or you can make b a matrix. Join on matrices works the way you expect.
q)(1 2#b),a
0.5 0.5
0.7 0.3
0.1 0.2

decay rate of data in matlab

I want to know how quickly some data returns to baseline after an initial peak (here at ca x=5);
The quadratic fit looks about right (from the figures option of matlab, shown below) - but I'm looking for a concise quantification of this curve, therefore I presume the 'decay rate' of the exponential function would be one very straightforward.
Is this assumption correct?
If yes, I looked at the formula on wiki for this, and attempted shamelessly to find a solve for the time constant (but unsuccessfully so). Can someone help me out, or is this actually a not so trivial problem?
edit: I was planning to find the peak using MathWorks' findpeaks() function, and the lowest point of the curve using the 'inverse' findpeaks() (as in: -y)
%approx data values of the curves below
y= [0 0.07 0.08 0.08 0.08 0.06 0.06 0.05 0.04 0.05 0.04 0.02 0.01 0.02 0.01 0.01 0.03 0.02 0.02 0.02 0.03 0.01 0.02 0.01 0.01 0.03 0.02 0.01 0.02 0.01];
x=1:numel(y);
plot(x,y);
These are the two options I was looking for, maybe someone can elaborate / improve this answer about the differences for these approaches - for me this is good enough, thanks for the comments. Before this step, using the data provided in the example of the question, the local maximum and minimum has to be extracted, this can be done easily using findpeaks()
approach 1) requires the curve toolbox from Matlab [Source]
%Fit a Single-Term Exponential Model, copy from Mathworks documentation, all credits go there
x = (0:0.2:5)';
y = 2*exp(-0.2*x) + 0.1*randn(size(x));
f = fit(x,y,'exp1')
f =
General model Exp1:
f(x) = a*exp(b*x)
Coefficients (with 95% confidence bounds):
a = 2.021 (1.89, 2.151)
b = -0.1812 (-0.2104, -0.152)
plot(f,x,y)
or approach 2) requires the optimizaion toolbox from Matlab [Source]
%copy from Mathworks documentation, all credits go there
rng default % for reproducibility
d = linspace(0,3);
y = exp(-1.3*d) + 0.05*randn(size(d));
fun = #(r)exp(-d*r)-y;
x0 = 4;
x = lsqnonlin(fun,x0)
plot(d,y,'ko',d,exp(-x*d),'b-')
legend('Data','Best fit')
xlabel('t')
ylabel('exp(-tx)')

How can I plot cumulative plots with specific x values?

I was trying to find out, how to plot a cumulative distribution function (cdf) with specific x values but was not successful.
For example, if the dataset is:
x = [2.50 5.21 7.67 8.43 9.15 11.47 14.59 21.45];
y = [0.20 0.09 0.15 0.13 0.17 0.04 0.7 0.15]; % (total 1)
the graph shape definitely looks wrong, when I use y = cdfplot(x).
I also plotted the graph with cumsum(y) and x to check the shape and it looks fine, but I would like to know, if there is any code which plots cumulative distribution plots.
There's the stairs function for creating "stairstep graphs", which should be exactly what you want, incorporating your cumsum(y) idea.
Please see the following code snippet. I added two additional points for the start and end of some interval, here [0 ... 25]. Also, your values in y sum up to something larger than 1, so I modified these values, too.
x = [0 2.50 5.21 7.67 8.43 9.15 11.47 14.59 21.45 25];
y = [0 0.10 0.09 0.05 0.10 0.14 0.04 0.4 0.08 0];
stairs(x, cumsum(y));
xlim([-1 26]);
ylim([-0.2 1.2]);
That'd be the output (Octave 5.1.0, but also tested with MATLAB Online):
Hope that helps!

Find the X value from a graph, created using pchip, given the Y value. MATLAB

I would like to generate the X value using a corresponding random Y value, these random values are within the range of Y, from a graph which i have created using the pchip function, but i want the generated X value to stay within a specific range.
My code:
samples=10
r=rand(samples,1)
Y=[0.93 0.94 0.95 0.96 0.97 0.98 0.99 1];
x=12.5:45:327.5;
angle=pchip(y,x,r);
Output:
angle =
1.0e+03 *
-0.1392
-3.3718
-3.4856
-3.2264
-0.5284
-0.8114
-2.2368
-0.0804
-2.9240
-1.9510
I would like the values to lie between -12.5-360 and I believe I could use something like this:
Y=[0.93 0.94 0.95 0.96 0.97 0.98 0.99 1];
x=12.5:45:327.5;
xi=-12.5:360;
angle=pchip(y,xi,x);
But I cant then get it to generate the required X value from the given Y value.
I have tried the following but it does not work:
samples=10
r=rand(samples,1)
Y=[0.93 0.94 0.95 0.96 0.97 0.98 0.99 1];
xi=-12.5:360;
x=12.5:45:327.5;
angle=pchip(y,xi,x,r);
I have looked at the mathworks pchip article and other mathworks articles but they don't seem to solve my problem and also looked at this stackoverflow article How can I ask matlab to give me the value of y if I input the value of x?, which wasn't the solution needed.
Thanks for your time and help you can offer.
Edit 1 - A little more information
I think what would solve my problem is if I could get the pchip function just to interpolate my data between to set points a max and min. As TryHard pointed out maybe the data is been interpolated outside the data which has been defined causing instabilities.
I know that I can interpolate within a certain range as I demonstrated above but I want to be able to do this and generate the X values given the Y values in the vector r
Try constraining the values of r to the observed range of y:
samples=10;
y=[0.93 0.94 0.95 0.96 0.97 0.98 0.99 1];
x=12.5:45:327.5;
r=rand(samples,1)*(max(y)-min(y)) + min(y);
angle=pchip(y,x,r);

Subscript indices must either be real positive integers or logicals. Using findpeaks in MatLab

I've have been using findpeaks in MatLab to locate the maximum and minimum points of a waveform with no problem, but in the last 20 minutes or so the error:
??? Subscript indices must either be real positive integers or logicals.
Has appeared an I have no idea why. Even trying simple exercises with test data has resulted in the same error. For example if I were to have the dataset:
test = [ 0.1 0.5 0.9 0.5 0.2 0.6 1.0 0.7 0.3 0.1 ]
and used the code:
peaks = test(findpeaks(test));
I would expect the result:
peaks = [0.1 0.9 0.2 1.0 0.1 ]
but for some reason this is no longer the case.
Please advise.
Findpeaks returns the peak values, not their indices. Try this.
peaks=findpeaks(test)
If you want to find the local minima as well,
peaks = [findpeaks(test) -findpeaks(-test)]