~ubuntu-branches/ubuntu/trusty/psychtoolbox-3/trusty-proposed

« back to all changes in this revision

Viewing changes to Psychtoolbox/PsychColorimetricData/ComputeCIEConeFundamentals.m

  • Committer: Package Import Robot
  • Author(s): Yaroslav Halchenko
  • Date: 2013-11-19 23:34:50 UTC
  • mfrom: (3.1.4 experimental)
  • Revision ID: package-import@ubuntu.com-20131119233450-f7nf92vb8qavjmk8
Tags: 3.0.11.20131017.dfsg1-3
Upload to unsable since fresh glew has arrived to sid!

Show diffs side-by-side

added added

removed removed

Lines of Context:
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])
3
3
%
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.
15
15
%
16
 
% Note that this routine returns normalized quantal sensitivities.  You
 
16
% To get the Stockman-Sharpe/CIE 10-deg fundamentals, use
 
17
%   fieldSizeDegrees = 10;
 
18
%   ageInYears = 32;
 
19
%   pupilDiameterMM = 3;
 
20
% and don't pass the rest of the arguments.
 
21
%
 
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.)
21
27
%
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.
 
39
%
 
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
27
45
% to go below 400.
28
46
%
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).
33
51
%
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.
 
69
%
 
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.
50
80
%
51
81
% See also: ComputeRawConeFundamentals, CIEConeFundamentalsTest, 
52
82
% FitConeFundamentalsTest, FitConeFundamentalsWithNomogram, StockmanSharpeNomogram.
53
83
%
54
84
% 8/13/11  dhb  Wrote it.
55
85
% 8/14/11  dhb  Clean up a little.
56
 
 
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.
 
89
 
 
90
%% Are we doing rods rather than cones?
 
91
if (nargin < 8 || isempty(DORODS))
 
92
    DORODS = 0;
 
93
end
 
94
 
 
95
%% Get some basic parameters.
 
96
%
 
97
%
 
98
% We start with default CIE parameters in 
 
99
% the photoreceptors structure, and then override
 
100
% as necessary.
 
101
% then override to match the CIE standard.
 
102
if (fieldSizeDegrees <= 4)
 
103
    whatCalc = 'CIE2Deg';
 
104
else
 
105
    whatCalc = 'CIE10Deg';
 
106
end
61
107
photoreceptors = DefaultPhotoreceptors(whatCalc);
62
108
 
63
109
%% Override default values so that FillInPhotoreceptors does
64
 
% our work for us.
 
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';
72
117
 
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';
78
125
    end
 
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;
81
131
else
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;
 
137
end
 
138
 
 
139
%% Are we doing the rods?  In that case, a little more
 
140
% mucking is necessary.
 
141
if (DORODS)
 
142
    if (isempty(lambdaMax) || length(lambdaMax) ~= 1)
 
143
        error('When computing for rods, must specify exactly one lambda max');
 
144
    end
 
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;
85
151
end
86
152
 
87
153
%% Do the work.  Note that to modify this code, you'll want a good
90
156
% can be computed is specified directly in the passed structure is
91
157
% actually specified, the speciefied value overrides what could be computed.
92
158
photoreceptors = FillInPhotoreceptors(photoreceptors);
 
159
if (SET_ABSORBANCE)
 
160
    params.absorbance = photoreceptors.absorbance;
 
161
end
93
162
 
94
163
%% Set up for call into the low level routine that computes the CIE fundamentals.
95
164
staticParams.S = photoreceptors.nomogram.S;
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;
103
174
else
104
175
    staticParams.LserWeight = LserWeight;
105
176
end
106
 
params.axialDensity = photoreceptors.axialDensity.value;
107
 
 
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;
 
180
else
 
181
    params.axialDensity = photoreceptors.axialDensity.value;
 
182
end
 
183
 
 
184
if (~isfield(params,'absorbance'))
 
185
    if (length(params.lambdaMax) ~= 3 & length(params.lambdaMax) ~= 1)
 
186
        CHECK_FOR_AGREEMENT = false;
 
187
    end
 
188
end
 
189
 
 
190
%% Drop into more general routine to compute
 
191
[T_quantalAbsorptionsNormalized,T_quantalAbsorptions,T_quantalIsomerizations] = ComputeRawConeFundamentals(params,staticParams);
 
192
 
 
193
%% A little reality check.
 
194
%
 
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');
 
203
    end
 
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');
 
207
    end
 
208
end
 
209
 
 
210
end
110
211