1 |
% |
---|
2 |
% correctThermalLag.m |
---|
3 |
% |
---|
4 |
% This function receives as input parameter a CTD profile, and applies a |
---|
5 |
% thermal lag correction on it. |
---|
6 |
% |
---|
7 |
% The correction applied uses the recursive scheme described in |
---|
8 |
% Morison, J., R. Andersen, N. Larson, E. D'Asaro, and T. Boyd, 1994: |
---|
9 |
% The Correction for Thermal-Lag Effects in Sea-Bird CTD Data. |
---|
10 |
% Journal of Atmospheric and Oceanic Technology, vol. 11, pages 1151�1164. |
---|
11 |
% |
---|
12 |
% Syntax: |
---|
13 |
% correctedProfileData = correctThermalLag(basicProfileData) |
---|
14 |
% correctedProfileData = correctThermalLag(basicProfileData, correctionParams) |
---|
15 |
% [correctedProfileData, correctionParams] = correctThermalLag(basicProfileData) |
---|
16 |
% |
---|
17 |
% Inputs: |
---|
18 |
% basicProfileData - A profile structure* |
---|
19 |
% correctionParams - The set of parameters to be used in the correction* |
---|
20 |
% gliderVelocity - Glider velocity from the dbd files (m_speed) |
---|
21 |
% |
---|
22 |
% Outputs: |
---|
23 |
% correctedProfileData - A profile structure* |
---|
24 |
% correctionParams - The set of parameters used in the correction* |
---|
25 |
% |
---|
26 |
% Profile structure: |
---|
27 |
% A struct that contains several fields, all of them column vectors with the same length: |
---|
28 |
% - ptime: Present time instant at which this row was collected |
---|
29 |
% - depth: Depth (pressure in decibars) measured by the CTD |
---|
30 |
% - temp: Temperature measured by the CTD |
---|
31 |
% - cond: Conductivity measured by the CTD |
---|
32 |
% - pitch: Pitch angle of the glider (optional) |
---|
33 |
% The output profile has the same information of the input plus two fields with the |
---|
34 |
% corrected profile properties: |
---|
35 |
% - condOutCell: corrected conductivity, removing the effects of the |
---|
36 |
% temperature difference between the outer and inner parts of the |
---|
37 |
% conductivity cell. |
---|
38 |
% - tempInCell: corrected temperature, that is, the temperature of |
---|
39 |
% the water mass lying inside the conductivity cell. |
---|
40 |
% |
---|
41 |
% From this information, the user can choose which one of the two |
---|
42 |
% corrections to use in order to compute salinity: |
---|
43 |
% - Combine 'condOutCell' with 'temp' (Expected values outside of the |
---|
44 |
% conductivity cell). |
---|
45 |
% - Combine 'cond' with 'tempInCell' (Expected values inside of the |
---|
46 |
% conductivity cell). |
---|
47 |
% |
---|
48 |
% Correction parameters: |
---|
49 |
% A vector of four elements, consisting of alpha_offset, alpha_slope, |
---|
50 |
% tau_offset and tau_slope. These parameters are used to compute alpha and tau, |
---|
51 |
% the amplitude and time constant respectively, which are inversely |
---|
52 |
% proportional to the flow speed. |
---|
53 |
% |
---|
54 |
% Example: |
---|
55 |
% correctedProfileData = correctThermalLag(basicProfileData) corrects the |
---|
56 |
% profile information contained in the input 'basicProfileData', |
---|
57 |
% using Morison parameters |
---|
58 |
% |
---|
59 |
% correctedProfileData = correctThermalLag(basicProfileData, correctionParams) |
---|
60 |
% corrects the profile information contained in 'basicProfileData', |
---|
61 |
% using correctionParams as the parameters to be used |
---|
62 |
% during the correction. |
---|
63 |
% |
---|
64 |
% [correctedProfileData, correctionParams] = correctThermalLag(basicProfileData) |
---|
65 |
% corrects the profile information contained in 'basicProfileData', and |
---|
66 |
% provides in the output the correction parameters used for the correction. |
---|
67 |
% |
---|
68 |
% Other m-files required: none |
---|
69 |
% Subfunctions: none |
---|
70 |
% MAT-files required: none |
---|
71 |
% |
---|
72 |
% See also: ADJUSTTHERMALLAGPARAMS |
---|
73 |
% |
---|
74 |
% Author: Bartolome Garau |
---|
75 |
% Work address: Parc Bit, Naorte, Bloc A 2ºp. pta. 3; Palma de Mallorca SPAIN. E-07121 |
---|
76 |
% Author e-mail: tgarau@socib.es |
---|
77 |
% Website: http://www.socib.es |
---|
78 |
% Created: 17-Feb-2011 |
---|
79 |
% |
---|
80 |
%////////////////////////////////////////////////////////////////////////// |
---|
81 |
|
---|
82 |
|
---|
83 |
function [correctedProfileData, varargout] = correctThermalLag(basicProfileData, varargin) |
---|
84 |
|
---|
85 |
% Extract the information contained in the profile |
---|
86 |
time = basicProfileData.ptime; |
---|
87 |
depth = basicProfileData.depth; |
---|
88 |
temp = basicProfileData.temp; |
---|
89 |
cond = basicProfileData.cond; |
---|
90 |
if isfield(basicProfileData, 'pitch'), |
---|
91 |
pitch = basicProfileData.pitch * pi / 180; |
---|
92 |
else |
---|
93 |
pitch = (26 * pi / 180) * ones(size(depth)); |
---|
94 |
end; |
---|
95 |
|
---|
96 |
% Copy the original fields into the output struct |
---|
97 |
correctedProfileData = basicProfileData; |
---|
98 |
if numel(time) <= 1 |
---|
99 |
correctedProfileData.condOutCell = correctedProfileData.cond; |
---|
100 |
correctedProfileData.tempInCell = correctedProfileData.temp; |
---|
101 |
return; |
---|
102 |
end; |
---|
103 |
|
---|
104 |
if nargin == 1, % Only basicProfileData is provided as input |
---|
105 |
% These values are proposed in Morison94 |
---|
106 |
alpha_offset = 0.0135; |
---|
107 |
alpha_slope = 0.0264; |
---|
108 |
tau_offset = 7.1499; |
---|
109 |
tau_slope = 2.7858; |
---|
110 |
|
---|
111 |
elseif nargin == 2, % offset and slope for alpha and tau are also given |
---|
112 |
paramVector = varargin{1}; |
---|
113 |
alpha_offset = paramVector(1); |
---|
114 |
alpha_slope = paramVector(2); |
---|
115 |
tau_offset = paramVector(3); |
---|
116 |
tau_slope = paramVector(4); |
---|
117 |
|
---|
118 |
% ADDED 6/13/2012 (William Stark, whs@unc.edu): Allow for glider velocity vector |
---|
119 |
% to be passed in. |
---|
120 |
elseif nargin == 3, % Glider velocity vector is also provided |
---|
121 |
% copy in offset and slope for alpha and tau as before... |
---|
122 |
paramVector = varargin{1}; |
---|
123 |
alpha_offset = paramVector(1); |
---|
124 |
alpha_slope = paramVector(2); |
---|
125 |
tau_offset = paramVector(3); |
---|
126 |
tau_slope = paramVector(4); |
---|
127 |
% copy in glider velocity... |
---|
128 |
gliderVelocity = varargin{2}; |
---|
129 |
|
---|
130 |
else |
---|
131 |
disp('Incorrect number of parameters. Type ''help correctThermalLag'' for more information'); |
---|
132 |
return; |
---|
133 |
end; |
---|
134 |
|
---|
135 |
|
---|
136 |
% Some initial precomputations... |
---|
137 |
deltaTime = abs(diff(time)); |
---|
138 |
deltaTemp = diff(temp) ; |
---|
139 |
samplingFreq = 1 ./ deltaTime ; |
---|
140 |
|
---|
141 |
% Calculate the surge speed from the depth rate and pitch |
---|
142 |
deltaDepth = abs(diff(depth)); % does not matter if downcast or upcast |
---|
143 |
depthRate = deltaDepth ./ deltaTime; |
---|
144 |
pitchSinus = sin(pitch); |
---|
145 |
surgeSpeed = depthRate ./ pitchSinus(1:end-1); |
---|
146 |
|
---|
147 |
% The relative coefficient between the flow speed inside and outside |
---|
148 |
% of the conductivity cell. This is still uncertain (ask Gordon for origin). |
---|
149 |
% Here are three choices for first three orders polynomial. |
---|
150 |
speedFactorPols = [0.00, 0.00, 0.40; % 0th order degree |
---|
151 |
0.00, 0.03, 0.45; % 1st order degree |
---|
152 |
1.58, 1.15, 0.70]; % 2nd order degree |
---|
153 |
|
---|
154 |
selectedDegree = 1; % First order approximation, second row of the matrix |
---|
155 |
speedFactor = polyval(speedFactorPols(selectedDegree+1, :), surgeSpeed); |
---|
156 |
|
---|
157 |
|
---|
158 |
|
---|
159 |
% ADDED 6/13/2012 (William Stark, whs@unc.edu): if/else statement added |
---|
160 |
% so that if a glider velocity was passed in it is used as the flow |
---|
161 |
% speed... otherwise the flow speed is calculated using the surge speed |
---|
162 |
% and speed factor as before. |
---|
163 |
if (exist('gliderVelocity')==1), % if glider velocity was passed in |
---|
164 |
% use gliderVelocity as the flow speed |
---|
165 |
flowSpeed = gliderVelocity; |
---|
166 |
% calculation of flow speed using surge speed and speed factor |
---|
167 |
% results in a flow speed vector that is one element shorter. For |
---|
168 |
% this reason we must trim the length of this 'passed-in' flow |
---|
169 |
% speed vector by one... |
---|
170 |
flowSpeed(end) = []; |
---|
171 |
|
---|
172 |
else; % calculate the flow speed using surge speed and speed factor... |
---|
173 |
% ADDED 6/6/12 (William Stark, whs@unc.edu): set eps=0.01 TO AVOID BLOWUPS WHEN |
---|
174 |
% CALLING THIS FUNCTION DIRECTLY... |
---|
175 |
%flowSpeed = abs(speedFactor .* surgeSpeed) + eps; % Avoid division by zero |
---|
176 |
flowSpeed = abs(speedFactor .* surgeSpeed) + 0.01; % Avoid division by zero |
---|
177 |
|
---|
178 |
end; |
---|
179 |
|
---|
180 |
|
---|
181 |
% The alpha and tau parameters, as suggested in the reference paper, |
---|
182 |
% depend on the flow with tne next expressions |
---|
183 |
alpha = alpha_offset + alpha_slope ./ flowSpeed ; |
---|
184 |
tau = tau_offset + tau_slope ./ sqrt(flowSpeed); |
---|
185 |
|
---|
186 |
% Relation between a and b coefficients with respect to alpha and tau |
---|
187 |
coefa = 4 .* samplingFreq .* alpha .* tau ./ (1 + 4 .* samplingFreq .* tau); |
---|
188 |
coefb = 1 - 2 .* coefa ./ alpha; |
---|
189 |
|
---|
190 |
% Sensitivity of conductivity with respect to temperature, |
---|
191 |
% approximation suggested by SeaBird: SBE Data Processing User�s Manual |
---|
192 |
% at Section 6: Data Processing Modules, Cell Thermal Mass |
---|
193 |
% Software Release 7.16a and later. Date: 01/18/08 |
---|
194 |
% dCdT = 0.1 .* (1 + 0.006 .* (temp - 20)); |
---|
195 |
dCdT = 0.088 + 0.0006 * temp; |
---|
196 |
|
---|
197 |
% Recursive processing of the corrections |
---|
198 |
condCorrection = zeros(size(cond)); |
---|
199 |
tempCorrection = zeros(size(temp)); |
---|
200 |
|
---|
201 |
for depthLevel = 1:length(depth)-1, |
---|
202 |
% Compute corrections for next depth level |
---|
203 |
condCorrection(depthLevel+1) = ... |
---|
204 |
- coefb(depthLevel) .* condCorrection(depthLevel) + ... |
---|
205 |
coefa(depthLevel) .* dCdT(depthLevel) .* deltaTemp(depthLevel); |
---|
206 |
tempCorrection(depthLevel+1) = ... |
---|
207 |
- coefb(depthLevel) .* tempCorrection(depthLevel) + ... |
---|
208 |
coefa(depthLevel) .* deltaTemp(depthLevel); |
---|
209 |
end; |
---|
210 |
|
---|
211 |
% Apply corrections and save them as fields in the output struct |
---|
212 |
correctedProfileData.condOutCell = cond + condCorrection; |
---|
213 |
correctedProfileData.tempInCell = temp - tempCorrection; |
---|
214 |
|
---|
215 |
if nargout == 2, % If required, output alpha and tau offsets and slopes |
---|
216 |
varargout{1} = [alpha_offset, alpha_slope, tau_offset, tau_slope]; |
---|
217 |
end; |
---|
218 |
if nargout == 3, % If required, output also alpha and tau parameters |
---|
219 |
varargout{2} = [alpha, tau]; |
---|
220 |
end; |
---|
221 |
|
---|
222 |
clear gliderVelocity; |
---|
223 |
return; |
---|
224 |
|
---|