1
function T_quantal = ComputeCIEConeFundamentals(S,fieldSizeDegrees,ageInYears,pupilDiameterMM,lambdaMax,whichNomogram,LserWeight)
2
% T_quantal = ComputeCIEConeFundamentals(S,fieldSizeDegrees,ageInYears,pupilDiameterMM,[lambdaMax],[whichNomogram],[LserWeight])
1
function [T_quantalAbsorptionsNormalized,T_quantalAbsorptions,T_quantalIsomerizations] = ComputeCIEConeFundamentals(S,fieldSizeDegrees,ageInYears,pupilDiameterMM,lambdaMax,whichNomogram,LserWeight,DORODS,rodAxialDensity)
2
% [T_quantalAbsorptionsNormalized,T_quantalAbsorptions,T_quantalIsomerizations] = ComputeCIEConeFundamentals(S,fieldSizeDegrees,ageInYears,pupilDiameterMM,[lambdaMax],[whichNomogram],[LserWeight],[DORODS],[rodAxialDensity])
4
4
% Function to compute normalized cone quantal sensitivities
5
5
% from underlying pieces, as specified in CIE 170-1:2006.
13
13
% pupilDiameterMM = 3;
14
14
% and don't pass the rest of the arguments.
16
% Note that this routine returns normalized quantal sensitivities. You
16
% To get the Stockman-Sharpe/CIE 10-deg fundamentals, use
17
% fieldSizeDegrees = 10;
19
% pupilDiameterMM = 3;
20
% and don't pass the rest of the arguments.
22
% Note that this routine returns quantal sensitivities. You
17
23
% may want energy sensitivities. In that case, use EnergyToQuanta to convert
18
24
% T_energy = EnergyToQuanta(S,T_quantal')'
19
25
% and then renormalize. (You call EnergyToQuanta because you're converting
20
26
% sensitivities, which go the opposite directoin from spectra.)
22
% Note from DHB: Although this will compute something over any wavelength
23
% range, I'd recommend not going lower than 390 or above about 780 without
28
% The routine also returns two quantal sensitivity functions. The first gives
29
% the probability that a photon will be absorbed. The second is the probability
30
% that the photon will cause a photopigment isomerization. It is the latter
31
% that is what you want to compute isomerization rates from retinal illuminance.
32
% See note at the end of function FillInPhotoreceptors for some information about
33
% convention. In particular, this routine takes pre-retinal absorption into
34
% account in its computation of probability of absorptions and isomerizations,
35
% so that the relevant retinal illuminant is one computed without accounting for
36
% those factors. This routine does not account for light attenuation due to
37
% the pupil, however. The only use of pupil size here is becuase of its
38
% slight effect on lens density as accounted for in the CIE standard.
40
% Although this routine will compute something over any wavelength
41
% range, I'd (DHB) recommend not going lower than 390 or above about 780 without
24
42
% thinking hard about how various pieces were extrapolated out of the range
25
43
% that they are specified in the standard. Indeed, the lens optical
26
44
% density measurements only go down to 400 nm and these are extropolated
29
% This routine will also compute from absorbance based on a nomogram, where
47
% This routine will compute from tabulated absorbance or absorbance based on a nomogram, where
30
48
% whichNomogram can be any source understood by the routine
31
% PhotopigmentNomogram. To obtain this behavior, pass a lambdaMax vector.
49
% PhotopigmentNomogram. To obtain the nomogram behavior, pass a lambdaMax vector.
32
50
% You can then also optionally pass a nomogram source (default: StockmanSharpe).
34
52
% The nominal values of lambdaMax to fit the CIE 2-degree fundamentals with the
44
62
% If you pass lambaMax and its length is 4, then first two values are treated as
45
63
% the peak wavelengths of the ser/ala variants of the L cone pigment, and these
46
64
% are then weighted according to LserWeight and (1-LserWeight). The default
47
% for LserWeight is 0.56. After travelling it for a distance, I (DHB) do not
48
% particularly recommend going down this road. But if you want to, I recommend
49
% you look at and play with FitConeFundametnalsTest.
65
% for LserWeight is 0.56. After travelling it for a distance to try to get better
66
% agreement between the nomogram based fundamentals and the tabulated fundamentals
67
% I (DHB) gave up and decided that using a single lambdaMax is as good as anything
68
% else I could come up with. If you are interested, see FitConeFundametnalsTest.
70
% This function also has an option to compute rod spectral sensitivities, using
71
% the pre-retinal values that come from the CIE standard. Set DORODS = true on
72
% call. You then need to explicitly pass a single lambdaMax value. You can
73
% also pass an optional rodAxialDensity value. If you don't pass that, the
74
% routine uses the 'Alpern' estimate for 'Human'/'Rod' embodied in routine
75
% PhotopigmentAxialDensity. The default nomogram for the rod spectral
76
% absorbance is 'StockmanSharpe', but you can override with any of the
77
% others available in routine PhotopigmentNomogram. Use of this requires
78
% good choices for lambdaMax, rodAxialDensity, and the nomogram. We are
79
% working on identifying those values more precisely.
51
81
% See also: ComputeRawConeFundamentals, CIEConeFundamentalsTest,
52
82
% FitConeFundamentalsTest, FitConeFundamentalsWithNomogram, StockmanSharpeNomogram.
54
84
% 8/13/11 dhb Wrote it.
55
85
% 8/14/11 dhb Clean up a little.
57
%% Get some basic parameters. The Stockman-Sharpe data
58
% are not provided below 390, and things are cleaner if we
59
% start there rather than default 380.
60
whatCalc = 'LivingHumanFovea';
86
% 12/16/12 dhb, ms Add rod option.
87
% 08/10/13 dhb Test for consistency between what's returned by FillInPhotoreceptors and
88
% what's returned by ComputeRawConeFundamentals.
90
%% Are we doing rods rather than cones?
91
if (nargin < 8 || isempty(DORODS))
95
%% Get some basic parameters.
98
% We start with default CIE parameters in
99
% the photoreceptors structure, and then override
101
% then override to match the CIE standard.
102
if (fieldSizeDegrees <= 4)
103
whatCalc = 'CIE2Deg';
105
whatCalc = 'CIE10Deg';
61
107
photoreceptors = DefaultPhotoreceptors(whatCalc);
63
109
%% Override default values so that FillInPhotoreceptors does
110
% our work for us. The CIE standard uses field size,
111
% age, and pupil diameter to computer other values.
112
% to compute other quantities.
65
113
photoreceptors.nomogram.S = S;
66
114
photoreceptors.fieldSizeDegrees = fieldSizeDegrees;
115
photoreceptors.pupilDiameter.value = pupilDiameterMM;
67
116
photoreceptors.ageInYears = ageInYears;
68
photoreceptors.pupilDiameter.value = pupilDiameterMM;
69
photoreceptors.lensDensity.source = 'CIE';
70
photoreceptors.macularPigmentDensity.source = 'CIE';
71
photoreceptors.axialDensity.source = 'CIE';
73
% Aborbance. Use tabulated CIE values unless a nomogram and
118
% Absorbance. Use tabulated CIE values (which are in the
119
% default CIE photoreceptors structure) unless a nomogram and
74
120
% lambdaMax values are passed.
121
SET_ABSORBANCE = false;
75
122
if (nargin > 4 && ~isempty(lambdaMax))
76
123
if (nargin < 6 || isempty(whichNomogram))
77
124
whichNomogram = 'StockmanSharpe';
126
photoreceptors = rmfield(photoreceptors,'absorbance');
127
photoreceptors.nomogram.source = whichNomogram;
128
photoreceptors.nomogram.lambdaMax = lambdaMax;
129
params.lambdaMax = lambdaMax;
79
130
staticParams.whichNomogram = whichNomogram;
80
params.lambdaMax = lambdaMax;
82
load T_log10coneabsorbance_ss
83
photoreceptors.absorbance = 10.^SplineCmf(S_log10coneabsorbance_ss,T_log10coneabsorbance_ss,photoreceptors.nomogram.S,2);
84
params.absorbance = photoreceptors.absorbance;
132
% Absorbance is going to be specified directly. We get
133
% it after the call to FillInPhotoreceptors below,
134
% which will convert a file containing the absorbance into
135
% the needed data at the needed wavelength spacing.
136
SET_ABSORBANCE = true;
139
%% Are we doing the rods? In that case, a little more
140
% mucking is necessary.
142
if (isempty(lambdaMax) || length(lambdaMax) ~= 1)
143
error('When computing for rods, must specify exactly one lambda max');
145
photoreceptors.types = {'Rod'};
146
photoreceptors.nomogram.lambdaMax = lambdaMax;
147
photoreceptors.OSlength.source = 'None';
148
photoreceptors.specificDensity.source = 'None';
149
photoreceptors.axialDensity.source = 'Alpern';
150
params.DORODS = true;
87
153
%% Do the work. Note that to modify this code, you'll want a good
98
167
staticParams.pupilDiameterMM = photoreceptors.pupilDiameter.value;
99
168
staticParams.lensTransmittance = photoreceptors.lensDensity.transmittance;
100
169
staticParams.macularTransmittance = photoreceptors.macularPigmentDensity.transmittance;
101
if (nargin < 7 || iempty(LserWeight))
170
staticParams.quantalEfficiency = photoreceptors.quantalEfficiency.value;
171
CHECK_FOR_AGREEMENT = true;
172
if (nargin < 7 || isempty(LserWeight))
102
173
staticParams.LserWeight = 0.56;
104
175
staticParams.LserWeight = LserWeight;
106
params.axialDensity = photoreceptors.axialDensity.value;
108
%% Drop into more general routine to cmopute
109
T_quantal = ComputeRawConeFundamentals(params,staticParams);
177
if (DORODS && nargin >= 9 && ~isempty(rodAxialDensity))
178
params.axialDensity = rodAxialDensity;
179
CHECK_FOR_AGREEMENT = false;
181
params.axialDensity = photoreceptors.axialDensity.value;
184
if (~isfield(params,'absorbance'))
185
if (length(params.lambdaMax) ~= 3 & length(params.lambdaMax) ~= 1)
186
CHECK_FOR_AGREEMENT = false;
190
%% Drop into more general routine to compute
191
[T_quantalAbsorptionsNormalized,T_quantalAbsorptions,T_quantalIsomerizations] = ComputeRawConeFundamentals(params,staticParams);
193
%% A little reality check.
195
% The call to FillInPhotoreceptors also computes what here is called
196
% T_quantal. It is in the field effectiveAbsorbtance. For cases where
197
% we aren't playing games with the parameters after the call to
198
% FillInPhotoreceptors, we can check for agreement.
199
if (CHECK_FOR_AGREEMENT)
200
diffs = abs(T_quantalAbsorptions(:)-photoreceptors.effectiveAbsorbtance(:));
201
if (max(diffs(:)) > 1e-7)
202
error('Two ways of computing absorption quantal efficiency referred to the cornea DO NOT AGREE\n');
204
diffs = abs(T_quantalIsomerizations(:)-photoreceptors.isomerizationAbsorbtance(:));
205
if (max(diffs(:)) > 1e-7)
206
error('Two ways of computing isomerization quantal efficiency referred to the cornea DO NOT AGREE\n');