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)')
Related
I am trying to plot the magnitude ratio of a first order system using cftool, I'm aware there are other ways to do that but I need to get to the solution through this method.
I have simulated an RC circuit and, after having applied a sine input at several frequencies, I have measured the output of the system;
Here are the vectors I have created in MATLAB with the data I have measured:
f = [1 10 100 120 130 150 160 170 1000 2000 3000 10000];
Vi = zeros(1,12);
Vi(1,:) = 1; %amplitude
Vo = [0.99 0.99 0.85 0.79 0.77 0.73 0.7 0.68 0.16 0.08 0.05 0.02]; %amplitudes
Vdb = 20*log10(Vo./Vi); %Vo converted to dB
Now, given that an RC circuit is a first order system, I know that the relationship beetween magnitude ratio and frequency can be written as:
M(omega) = 1/(sqrt(1 + (omega * tau)^2))
So, opening cftool in MATLAB, I have set:
X data: f
Y data: Vdb
Custom Equation: 1/sqrt(1 + (2*pi*a*x)^2) %omega = 2*pi*f
Using these settings, however, cftool doesn't plot what I expected to see, so I would like to figure out where my mistakes are.
I believe the Y-data should be V0, not Vdb.
If you want the curvefit for the relationship between the voltage gain in dB and the frequency, then you need to alter the custom equation.
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!
I am trying to fit a distribution to a discrete dataset.
The possible outcomes are A = [1 3 4 5 9 10] with a respective probability of prob
prob = [0.2 0.15 0.1 0.05 0.35 0.15];
I have used makedist to find the distribution
pd = makedist('Multinomial','probabilities', prob);
I wonder if there is a way to include the outcomes 1 to 10 from A in the distribution, such that I can calculate the mean and the variance of the possible outcomes with var(pd), mean(pd). Up till now the mean is 3.65, but my aim is it to have mean(pd) = 5.95, which is the weighted sum of the possible outcomes . Thanks in advance.
The solution is pretty easy. The possible outcomes of a multinomial distrubution are defined by a sequence of values starting at 1 and ending at numel(prob). From this official documentation page:
Create a multinomial distribution object for a distribution with three
possible outcomes. Outcome 1 has a probability of 1/2, outcome 2 has a
probability of 1/3, and outcome 3 has a probability of 1/6.
pd = makedist('Multinomial','probabilities',[1/2 1/3 1/6])
Basically, your vector of possible outcomes includes a few values associated to a null (signally 0) probability. Thus, define your distribution as follows in order to obtain the expected result:
p = [0.20 0.00 0.15 0.10 0.05 0.00 0.00 0.00 0.35 0.15];
pd = makedist('Multinomial','probabilities',p);
mean(pd) % 5.95
var(pd) % 12.35
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) ;
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);