I've been running a variation of the doseResponse function downloaded from here to generate dose-response sigmoid curves. However, I've had trouble with one of my datasets that keeps generating a small EC50 value that visually doesn't appear to be correct. By running the following code, I get an EC50 value of .0014, but I feel that it should be much higher. I uploaded the data here. Does anyone know what I can do to fix this? Thanks.
Code to generate graph
% Plotting Dose-Response Curve
% Deal with 0 dosage by using it to normalise the results.
normalised=0;
if (sum(dose(:)==0)>0)
%compute mean control response
controlResponse=mean(response(dose==0));
%remove controls from dose/response curve
response=response(dose~=0)/controlResponse;
dose=dose(dose~=0);
normalised=1;
end
%hill equation sigmoid
sigmoid=#(beta,x)beta(1)+(beta(2)-beta(1))./(1+(x/beta(3)).^beta(4));
%calculate some rough guesses for initial parameters
minResponse=min(response);
maxResponse=max(response);
midResponse=mean([minResponse maxResponse]);
minDose=min(dose);
maxDose=max(dose);
% options=optimset('disp','iter','LargeScale','off','TolFun',.001,'MaxIter',1e10,'MaxFunEvals',1e10);
%fit the curve and compute the values
beta_new = lsqcurvefit(sigmoid,[minResponse maxResponse midResponse 1.5],dose,response);
[coeffs,r,J]=nlinfit(dose,response,sigmoid,beta_new);
ec50=coeffs(3);
hillCoeff=coeffs(4);
%plot the fitted sigmoid
xpoints=logspace(log10(minDose),log10(maxDose),1000);
semilogx(xpoints,sigmoid(coeffs,xpoints),'Color',[0 0 0],'LineWidth',2)
ax = gca;
ax.FontSize = 22.5;
hold on
%notate the EC50
text(ec50,mean([coeffs(1) coeffs(2)]),[' \leftarrow ' sprintf('EC_{50}=%0.2g',ec50)],'FontSize',22.5,'Color',[0 0 0]);
%plot mean response for each dose with standard error
doses=unique(dose);
meanResponse=zeros(1,length(doses));
stdErrResponse=zeros(1,length(doses));
for i=1:length(doses)
responses=response(dose==doses(i));
meanResponse(i)=mean(responses);
stdErrResponse(i)=std(responses)/sqrt(length(responses));
%stdErrResponse(i)=std(responses);
end
errorbar(doses,meanResponse,stdErrResponse,'o','Color',[0 0 0],'LineWidth',2,'MarkerSize',12)
Picture of Graph
Related
In my project, I used a generic cosine function to fit my data:
cos_fun = #(p, theta) p(1) + p(2) * cos(theta - p(3))
p = nlinfit(x,y,cos_fun,[1 1 0])
As a result, p has three values, which are y-offset, amplitude and phase.
Can I draw a smooth cosine curve using these three parameters?
TL;DR: It is possible to both fit and plot the curve, with and without requiring toolboxes. All cases presented below.
Plotting
Plotting the function follows directly from the function used to obtain your parameters using plot(). Notice that you control the smoothness of the plotted function based on the step size for the domain (see step below).
In the figure, the results obtained from the nlinfit() (Toolbox required) are the same as "SSE" obtained without a toolbox using fminsearch().
% Plot (No toolbox Required)
step = 0.01; % smaller is smoother
Xrng = 0:step:12;
figure, hold on, box on
plot(Xdata,Ydata,'b.','DisplayName','Data')
plot(Xrng,cos_fun(p_SSE,Xrng),'r--','DisplayName','SSE')
plot(Xrng,cos_fun(p_SAE,Xrng),'k--','DisplayName','SAE')
legend('show')
As pointed out in the comment by #Daniel, you can also make the plot with nlintool() but this requires the Statistics Toolbox.
nlintool(Xdata,Ydata,cos_fun,[1 1 0]) % toolbox required
Fitting
Using nlinfit(): (Statistics Toolbox Required)
pNL = nlinfit(Xdata,Ydata,cos_fun,[1 1 0]) % same as SSE approach below
A Toolbox Free Approach:
You can construct a convex error function to minimize and return the global optimum using fminsearch() as a down and dirty approach. For example, the sum of squared error or the sum of absolute error will be convex.
% MATLAB R2019a
% Generate Example Data
sigma = 0.5; % increase this for more variable data (more noise)
Xdata = [repmat(1:10,1,4)].';
Ydata = cos(Xdata)+sigma*randn(length(Xdata),1);
% Function Evaluation
cos_fun=#(p,x) p(1) + p(2).*cos(x-p(3));
% Error Functions
SSEh =#(p) sum((cos_fun(p,Xdata)-Ydata).^2); % sum of squared error
SAEh =#(p) sum(abs(cos_fun(p,Xdata)-Ydata)); % sum of absolute error
Of course, these will give you different errors for the same parameter.
% Test
SSEh([1 1 0])
SAEh([1 1 0])
But you then call fminsearch() given an initial guess for the parameters, p0, to obtain the parameters that minimize your chosen error function. Since SSEh and SAEh are both convex with respect to p, there's no need to do this multiple times and save the best one since for every p0, you'll get the same answer.
p0 = [1 1 0.25]; % Initial starting point
[p_SSE, SSE] = fminsearch(SSEh,p0)
[p_SAE, SAE] = fminsearch(SAEh,p0)
You fit slightly different curves depending on the error function.
Notice that SSEh(pNL) and SSEh(p_SSE) are the same since pNL equals p_SSE since nlinfit() estimates the coefficients "using iterative least squares estimation."
I am trying to fit a distribution curve to the histogram of some data. (I have used some model data here instead because it is difficult to upload the actual data. I have included the complete code after my question.)
Because the histogram looks normally distributed when I plotted the x-axis in logscale, I transform the data first before fitting a normal distribution to it and I got the following results:
>>pdn=fitdist(log(data),'Normal')
pdn =
Normal distribution
mu = -0.334458 [-0.34704, -0.321876]
sigma = 0.351478 [0.342804, 0.360605]
When I plotted out the pdf with the histogram, I got this:
The result seems reasonable to me. Then I discovered that in the Matlab fitdist(), it already has a 'Lognormal' option and I don't really need the transform my data first and this is what I got:
>>pdln = fitdist(data,'Lognormal')
pdln =
Lognormal distribution
mu = -0.334458 [-0.34704, -0.321876]
sigma = 0.351478 [0.342804, 0.360605]
Exactly the same mean and standard deviation as I have got before. However, when I plotted it out with the histogram, I got a different curve:
This curve fits better to the data but the positions of the mean and the mean+/-std points are not as I have expected (i.e. mean at the peak and the mean+/-std at the same levels).
Which come to my question, why would fitdist(data,'Lognormal') give the same result as fitdist(log(data),'Normal') but a different plot? I have looked through the Matlab help pages and I still could not understand why, or where are my mistakes, please help.
My aim for all this is to get some numerical parameters about the distributions of my data under different conditions and compare them to see if there is any difference. At the moment, I am not certain which way would give me reliable estimates of the means and standard deviations.
The code for the graphs is below:
%random data in lognormal distribution
mu=-0.335742;
sigma=0.35228;
data=lognrnd(mu,sigma,[3000 1]);
%make histogram
interval=0.1;
svalue=sort(data);
bx(1)=interval/2;
i=2;
while bx(i-1)<=max(svalue)
bx(i)=bx(i-1)+interval;
i=i+1;
end
by=hist(svalue,bx);
subplot(211)
h = bar(bx,by,'hist');
set(h,'FaceColor',[.9 .9 .9]);
set(gca,'xlim',[0.05 10]);
xticks=[0.05 0.1 0.2 0.5 1 2 5 10];
set(gca,'xscale','log','xminortick','on')
set(gca,'xtick',xticks)
ylabel('counts')
subplot(212)
h = bar(bx,by,'hist');
set(h,'FaceColor',[.9 .9 .9]);
set(gca,'xlim',[0.05 10]);
xticks=[0.05 0.1 0.2 0.5 1 2 5 10];
set(gca,'xscale','log','xminortick','on')
set(gca,'xtick',xticks)
ylabel('counts')
% fit distribution curves
pdf_x = 0:0.01:max(data);
max_by=max(by); % for scaling the pdf to the histogram
% case 1 - PDF fitted using fitdist(log(data),'Normal')
subplot(211)
hold on
pdn = fitdist(log(data),'Normal')
pdf_y = pdf(pdn,log(pdf_x));
h1=plot(pdf_x,pdf_y./max(pdf_y).*max_by,'-k');
range=[exp(pdn.mu-pdn.sigma) exp(pdn.mu+pdn.sigma)];
h2=plot(exp(pdn.mu),pdf(pdn,(pdn.mu))./max(pdf_y).*max_by,'sk') ;
h3=plot(range,pdf(pdn,log(range))./max(pdf_y).*max_by,'ok') ;
title('PDF fitted using fitdist(log(data),''Normal'')');
legend([h1 h2 h3],'pdf','mean','meam+/-std');
% case 2 - PDF fitted using fitdist(data,'Lognormal')
subplot(212)
hold on
pdln = fitdist(data,'Lognormal')
pdf_y = pdf(pdln,pdf_x);
h1=plot(pdf_x,pdf_y./max(pdf_y).*max_by,'-b');
range=[exp(pdln.mu-pdln.sigma) exp(pdln.mu+pdln.sigma)];
h2=plot(exp(pdln.mu),pdf(pdln,exp(pdln.mu))./max(pdf_y).*max_by,'sb');
h3=plot(range,pdf(pdln,range)./max(pdf_y).*max_by,'ob') ;
title('PDF fitted using fitdist(data,''Lognormal'')');
legend([h1 h2 h3],'pdf','mean','meam+/-std');
I am trying to plot step responses in MATLAB and cannot figure it out for anything, I have graphed a Bode plot for 3 different k values for the following differential equation in time domain:
d^2y(t)/dt + (v/m)dy(t)/dt + (k/m)y(t) = (k/m)x(t)
in frequency the equation is:
H(jw)=((k/m))/((〖jw)〗^2+(v/m)(jw)+(k/m) )=k/(m(〖jw)〗^2+v(jw)+k)
the values of k are 1, 0.09, 4
The equations to solve for v is as follows:
v=sqrt(2)*sqrt(k*m) where m=1
I now must do the same for step, but am trying to no avail. Can anyone provide any suggestions?
Here is the code for my Bode plot and my attempted but failed step plots:
w=logspace(-2,2,100);
%Creating different vectors based upon K value
%then calculating the frequencey response based upon
%these values
b1=[1];
a1=[1 2^(.5) 1];
H1=freqs(b1,a1,w);
b2=[.09];
a2=[1 (2^.5)*(.09^.5) .09];
H2=freqs(b2,a2,w);
b3=[4];
a3=[1 2*(2^.5) 4];
H3=freqs(b3,a3,w);
%Ploting frequency response on top plot
%with loglog scale
subplot(2,1,1)
loglog(H1,w,'r')
axis([.04 10 .01 10])
hold on
loglog(H2,w,'g')
loglog(H3,w,'c')
xlabel('Omega')
ylabel('Frequency Response')
title('Bode plot with various K values')
legend('H1, K=1','H2, K=.09','H3, K=4')
hold off
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%creating transfer function, how the functions
%respond in time
h1=tf(b1,a1);
h2=tf(b2,a2);
h3=tf(b3,a3);
t=linspace(0,30);
[y1,t1]=step(h1,t);
[y2,t2]=step(h2,t);
[y3,t3]=step(h3,t);
%Ploting step response on bottom plot
%with respect to time
subplot(2,1,2)
plot(t1,abs(y1),'r')
hold on
plot(t2,abs(y2),'g')
plot(t3,abs(y3),'c')
legend('h1, K=1','h2, K=.09','h3, K=4')
xlabel('time(s)')
ylabel('Amplitude')
title('Step response with various K values')
Have you tried using the step function? You already have the coefficients defined in your code above for each of the TFs. step takes in a TF object and gives you the step response in the time domain.
First, take those coefficients and create TF objects. After, run a step response. Using the code you already provided above, do something like this:
b=[1];
a=[1 2^(.5) 1];
% I would personally do: a = [1 sqrt(2) 1];
H1=tf(b, a); % Transfer Function #1
b=[.09];
a=[1 (2^.5)*(.09^.5) .09];
% I would personally do a = [1 sqrt(2*0.09) 0.09];
H2=tf(b, a); % Transfer Function #2
b=[4];
a=[1 2*(2^.5) 4];
% I would personally do a = [1 2*sqrt(2) 4];
H3=tf(b, a); % Transfer Function #3
% Plot the step responses for all three
% Going from 0 to 5 seconds in intervals of 0.01
[y1,t1] = step(H1, 0:0.01:5);
[y2,t2] = step(H2, 0:0.01:5);
[y3,t3] = step(H3, 0:0.01:5);
% Plot the responses
plot(t1, y1, t1, y2, t3, y3)
legend('H1(s)', 'H2(s)', 'H3(s)');
xlabel('Time (s)');
ylabel('Amplitude');
This is the figure I get:
FYI, powering anything to the half is the same as sqrt(). You should consider using that instead to make your code less obfuscated. Judging from your code, it looks like you are trying to modify the frequency of natural oscillations in each second-order underdamped model you are trying to generate while keeping the damping ratio the same. As you increase k, the system should get faster and the steady-state value should also become larger and closer towards 1 - ensuring that you compensate for the DC gain of course. (I'm a former instructor on automatic control systems).
I'm using the Matlab function "hist" to estimate the probability density function of a realization of a random process I have.
I'm actually:
1) taking the histogram of h0
2) normalizing its area in order to get 1
3) plotting the normalized curve.
The problem is that, no matter how many bins I use, the histogram never start from 0 and never go back to 0 whereas I would really like that kind of behavior.
The code I use is the following:
Nbin = 36;
[n,x0] = hist(h0,Nbin);
edge = find(n~=0,1,'last');
Step = x0(edge)/Nbin;
Scale_factor = sum(Step*n);
PDF_h0 = n/Scale_factor;
hist(h0 ,Nbin) %plot the histogram
figure;
plot(a1,p_rice); %plot the theoretical curve in blue
hold on;
plot(x0, PDF_h0,'red'); %plot the normalized curve obtained from the histogram
And the plots I get are:
If your problem is that the plotted red curve does not go to zero: you can solve that adding initial and final points with y-axis value 0. It seems from your code that the x-axis separation is Step, so it would be:
plot([x0(1)-Step x0 x0(end)+Step], [0 PDF_h0 0], 'red')
The function called DicePlot simulates rolling 10 dice 5000 times.
The function calculates the sum of values of the 10 dice of each roll, which will be a 1 ⇥ 5000 vector, and plot relative frequency histogram with edges of bins being selected in where each bin in the histogram represents a possible value of for the sum of the dice.
The mean and standard deviation of the 1 ⇥ 5000 sums of dice values will be computed, and the probability density function of normal distribution (with the mean and standard deviation computed) on top of the relative frequency histogram will be plotted.
Below is my code so far - What am I doing wrong? The graph shows up but not the extra red line on top? I looked at answers like this, and I don't think I'll be plotting anything like the Gaussian function.
% function[]= DicePlot()
for roll=1:5000
diceValues = randi(6,[1, 10]);
SumDice(roll) = sum(diceValues);
end
distr=zeros(1,6*10);
for i = 10:60
distr(i)=histc(SumDice,i);
end
bar(distr,1)
Y = normpdf(X)
xlabel('sum of dice values')
ylabel('relative frequency')
title(['NumDice = ',num2str(NumDice),' , NumRolls = ',num2str(NumRolls)]);
end
It is supposed to look like
But it looks like
The red line is not there because you aren't plotting it. Look at the documentation for normpdf. It computes the pdf, it doesn't plot it. So you problem is how do you add this line to the plot. The answer to that problem is to google "matlab hold on".
Here's some code to get you going in the right direction:
% Normalize your distribution
normalizedDist = distr/sum(distr);
bar(normalizedDist ,1);
hold on
% Setup your density function using the mean and std of your sample data
mu = mean(SumDice);
stdv = std(SumDice);
yy = normpdf(xx,mu,stdv);
xx = linspace(0,60);
% Plot pdf
h = plot(xx,yy,'r'); set(h,'linewidth',1.5);