My MATLAB psgnifit code is calculating the wrong values from the plot and I am unable to resolve it. Please help.

13 views (last 30 days)
I am plotting a psychometric curve using psignifit toolbox in MATLAB, and need to calculate the values for DL25 (value of X when Y=0.25) andDL75(value of X when Y=0.75) from the plotted curve. I have defined a function getDL for the same.However, it is returning negative values (X ranges from 0-700 only) for DL25 and incorrect values for DL75 as evident from the plot. I have also defined a function PSE for calculating X when Y=0.5, with a similar function, and is called similarly, but that is functioning smoothly. I am attaching both codes as well as calls here for reference.
Any help in resolving this is greatly appreciated.
Thanks in advance
-Adithi Anil
function DL = getDL(result, targetY, verbose)
% getDL - Find the X value corresponding to a specified Y value from the fitted curve
% Syntax:DL = getPSE(result, targetY, verbose)
% Inputs:
% result - struct containing the results from psignifit
% targetY - the Y value for which to find the corresponding X
% verbose - optional flag for additional output (default is false)
% Outputs:
% DL - the X value corresponding to the targetY value
if nargin < 3
verbose = false; % default verbose flag
end
% Extract the fit parameters
params = result.Fit; % Fit parameters
threshold = 0; % Starting at the lowest point
width = params(2); % Width
lambda = params(3); % Upper asymptote
gamma = params(4); % Lower asymptote (guess rate)
% Define the logistic sigmoid function
sigmoidFunc = @(x) lambda + (1 - lambda - gamma) ./ (1 + exp(-(x - threshold) / width));
% Use fzero to find the X value for which sigmoidFunc(X) = targetY
DL = fzero(@(x) sigmoidFunc(x) - targetY, threshold); % Starting guess at threshold
if verbose
fprintf('DL (X value for Y=%.2f) = %.4f\n', targetY, DL);
end
end
It is called as:
[DL75] = getDL(result, 0.7500, false); % DL75 = Difference Limen at .75 value of p(Long)
[DL25] = getDL(result, 0.2500, false); % DL25 = Difference Limen at .25 value of p(Long)
For reference, this is the similar function for finding X when Y=0.5, that is working smoothly
function PSE = getPSE(result, targetY, verbose)
% getPSE - Find the X value corresponding to a specified Y value from the fitted curve
% Syntax: PSE = getPSE(result, targetY, verbose)
% Inputs:
% result - struct containing the results from psignifit
% targetY - the Y value for which to find the corresponding X (default is 0.5)
% verbose - optional flag for additional output (default is false)
% Outputs:
% PSE - the X value corresponding to the targetY value
if nargin < 2
targetY = 0.5; % default target Y value
end
if nargin < 3
verbose = false; % default verbose flag
end
% Extract the fit parameters
params = result.Fit; % Fit parameters
threshold = params(1); % PSE (threshold)
width = params(2); % Width
lambda = params(3); % Upper asymptote
gamma = params(4); % Lower asymptote (guess rate)
% Define the logistic sigmoid function
sigmoidFunc = @(x) lambda + (1 - lambda - gamma) ./ (1 + exp(-(x - threshold) / width));
% Use fzero to find the X value for which sigmoidFunc(X) = targetY
PSE = fzero(@(x) sigmoidFunc(x) - targetY, threshold); % Starting guess at threshold
if verbose
fprintf('PSE (X value for Y=%.2f) = %.4f\n', targetY, PSE);
end
end
Which is called as:
[PSE] = getPSE(result, 0.5000, false); % PSE= Point of Subjective Equality

Answers (1)

William Rose
William Rose on 30 Oct 2024
@Adithi Anil, I have not tried running your code. I notice that
gamma=0; % lower symptote, supposedly
lambda=10; % upper symptote, supposedly
threshold=0; width=1;
%Define the logistic sigmoid function
sigmoidFunc = @(x) lambda + (1 - lambda - gamma) ./ (1 + exp(-(x - threshold) / width));
You say in the code comments that gamma and lambda are the lower and upper asymptotes, respectively. But your sigmoidFunc does not behave the way you want. See plot below.
A logistic function that DOES have gamma and lambda as the lower and upper symptotes, respectively, is defined as follows:
%Define another logistic sigmoid function
sigmoidFunc2 = @(x) gamma + (lambda - gamma) ./ (1 + exp(-(x - threshold) / width));
Plot both sigmoid functions:
x=-5:.2:5;
y1=sigmoidFunc(x);
y2=sigmoidFunc2(x);
figure; plot(x,y1,'-r.',x,y2,'-b.');
grid on; xlabel('X'); ylabel('Y')
legend('sigFunc','sigFunc2')
The plot shows that sigmoidFunction2() has the desired asymptotes, and your original sigmoidFunction() does not.
Does that fix your problem?
  9 Comments
William Rose
William Rose on 4 Nov 2024
This is turning into a long set of functions that call other (long) functions. I will not install someone else's toolbox of functions. I can't run psignifit() because it calls psignifitCore(). And so on.
Is this a good summary:
You use psignifit() to fit a signmoid to response data. psignifit() returns a struture variable, response, which has the fitted parameters and a bunch of other info about the fit. Functions getDL() and getPSE() return the x value of the sigmoid that corresponds to a given y value. The only difference between getDL and getPSE is that getPSE defaults to a y value of 0.5, if no y-value is supplied as an argument. You say getPSE() works fine. You say getDL() returns incorect results when y=0.25 and when y=0.75.
Why write getPSE()? Why not just call getDL(), with y=0.5?
You have two definitions of PSE. Your function getPSE() includes the line
threshold = params(1); % PSE (threshold)
Exanmnation of the logistic function shows that "threshold", labelled PSE in the comment in the code, is the x-value at which y is halfway between the lower and upper asymptotes. However, you say in your explanation above that PSE is the x-value where the y-value=0.5. These are two different definitions. They are only the same if the upper and lower ansymptotes are symmetric about 0.5, which is not guaranteed. Which definition of PSE is right: "x value when y=0.5" or "x value when y is halfway between lower and upper asymptote"?
In the example data you provide,
data =[100, 1,15; 200, 0,15;...
300, 3,15; 400,10,15;...
500, 7,15; 600,13,15; 700,12,15];
frac=data(:,2)./data(:,3);
plot(data(:,1),frac,'-r.')
grid on; xlabel('x'); ylabel('Frac. Correct');
Have you checked the fitted parameters to make sure the upper fitted asymptote exceeds 0.75? If the upper fitted asymptote is less than 0.75, then of course it will be an error when you try to obtain the x vaue corresponding to y=0.75.
You are using 7 data points to fit a curve (a logistic function) with 4 parameters. (The parameters are upper and lower asymptotes, theshold (=x-value of PSE), and width. (the x-value corresponding to perceived subjective equality) I am confident that the uncertainties in the 4 fitted parameters of the logistic function will be very large, for the example data above. You need more data points in order to have reaosnable confidence in the fitted values. Talk to a statistician about how to obtain confidence intervals for fited parameters. Or read the Matlab help for model fitting functions. .
Finally: Use psignifit() to compute result. Save result as a .mat file. Upload the .mat file to this chat using the paper clip icon. Then others will be able to access result and use it as input to your functions, getDL() and getPSE(). PLease provide the data set used by psignifit(), so we can confirm that the fitted values are reasonable.
William Rose
William Rose on 4 Nov 2024
@Adithi Anil, I just noticed another difference between getDL() and getPSE().
fragment of getDL()
% Extract the fit parameters
params = result.Fit; % Fit parameters
threshold = 0; % Starting at the lowest point
width = params(2); % Width
lambda = params(3); % Upper asymptote
gamma = params(4); % Lower asymptote (guess rate)
fragment of getPSE()
% Extract the fit parameters
params = result.Fit; % Fit parameters
threshold = params(1); % PSE (threshold)
width = params(2); % Width
lambda = params(3); % Upper asymptote
gamma = params(4); % Lower asymptote (guess rate)
The line "threshold=0" in getDL() is wrong. Change it to the line in getPSE(). Maybe that will solve your problems with getDL().
You could still get negative x-values back for DL25, depending on the data set and the fit, because there's nothing obvious that prevents the possibility of a fitted logistic funciton that has the value y=0.25 when x is <0.
You can still expect a weird value, or NaN, for DL75, if the upper asymptote is <0.75.

Sign in to comment.

Products


Release

R2023b

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!