22# # Correlation Time Analysis of Cloud Cover Data
33#
44# This example is inspired by the work of P. A. Jones {cite:p}`jones_1992_cloudcover`
5- # on the analysis of time (and spatial) correlations in cloud cover data.
6- # Jones observed an exponential decay of the time correlation function,
5+ # on the analysis of temporal (and spatial) correlations in cloud cover data.
6+ # Jones observed an exponential decay of the autocorrelation function,
77# with half-life times ranging from 5 to 40 hours.
88#
99# Here, we analyze a time series of cloud cover data obtained from
3838# %% [markdown]
3939# ## Cloud Cover Data
4040#
41- # Cloud cover is expressed here as a fraction of the sky covered by clouds,
41+ # In this example, cloud cover is expressed as the fraction of the sky covered by clouds,
4242# ranging from 0 (clear sky) to 1 (completely overcast).
4343
4444# %%
@@ -98,7 +98,7 @@ def plot_histogram():
9898plot_histogram ()
9999
100100# %% [markdown]
101- # This histogram reflects the typical weather patterns in Belgium,
101+ # This histogram reflects the typical weather pattern in Belgium,
102102# with plenty of cloudy days.
103103# This is also reflected in the normalized standard deviation (NS),
104104# as defined by Jones {cite:p}`jones_1992_cloudcover`:
@@ -121,19 +121,33 @@ def plot_histogram():
121121#
122122# Before applying STACIE to the data, let's first compute and plot the
123123# autocorrelation function (ACF) directly.
124+ #
125+ # Mind the normalization: due to the zero padding in `np.correlate`,
126+ # the number of terms contributing to the ACF decreases with lag time.
127+ # Furthermore, the ACF is not normalized to 1 in this plot,
128+ # as we want to keep the amplitude information.
124129
125130
126131# %%
132+ AMP_EXP = 0.0347 # From STACIE Lorentz B parameter, see below.
133+ TAU_EXP = 57.6 # From STACIE corrtime_exp, see below.
134+
135+
127136def plot_acf ():
128137 plt .close ("acf" )
129138 _ , ax = plt .subplots (num = "acf" )
130139 delta = cover - np .mean (cover )
131140 acf = np .correlate (delta , delta , mode = "same" )
132141 nkeep = acf .size // 2
133142 acf = acf [nkeep :] / (len (acf ) - np .arange (nkeep ))
134- acf /= acf [0 ]
135143 time = np .arange (240 )
136144 ax .plot (time , acf [:240 ], "C0-" )
145+ ax .plot (
146+ time ,
147+ AMP_EXP * np .exp (- time / TAU_EXP ),
148+ "C1--" ,
149+ label = r"exp(-t/\tau_\mathrm{exp})" ,
150+ )
137151 xticks = np .arange (0 , 241 , 24 )
138152 ax .set_xlim (- 1 , 240 )
139153 ax .set_xticks (xticks )
@@ -150,9 +164,14 @@ def plot_acf():
150164# resulting in weak correlations at multiples of 24 hours.
151165# Superimposed on these diurnal effects,
152166# an overall exponential decay of the ACF can be observed.
153- # However, it is difficult to fit an exponential function to the ACF due to the ripples.
154- # Although the conventional approach of fitting an exponential decay curve provides a rough estimate,
155- # we will use STACIE instead to perform a more robust analysis of the correlation time.
167+ # However, it is difficult to fit an exponential function to the ACF
168+ # due to (i) the ripples and (ii) non-exponential short-time effects.
169+ # Hence, fitting an exponential function can at best provide
170+ # a rough estimate of the correlation time.
171+
172+ # Below, it is shown how to use STACIE instead to perform a more robust analysis.
173+ # The exponential decay shown in the plot is derived from STACIE's output below.
174+ # It is only expected to be representative at long lag times.
156175
157176# %% [markdown]
158177# ## Autocorrelation Time
@@ -185,6 +204,16 @@ def plot_acf():
185204# The exponential correlation time, which is about 60 hours,
186205# is the longest because it captures the slowest relaxation process.
187206# The integrated correlation time is notably shorter at about 20 hours.
207+ #
208+ # In the code below, we also derive the $B$ parameter of the Lorentz model,
209+ # which has been used to plot the exponential decay in the ACF above.
210+
211+ # %%
212+ pars = result .props ["pars" ]
213+ tau_exp = result .corrtime_exp
214+ amp_exp = (pars [0 ] - pars [1 ] / pars [2 ]) / (2 * tau_exp )
215+ print (f"TAU_EXP = { tau_exp :.4f} h" )
216+ print (f"AMP_EXP = { amp_exp :.4f} " )
188217
189218# %% [markdown]
190219# The plots below show the fitted spectrum and additional diagnostics.
0 commit comments