Stratospheric ozone time series trend analysis

This demo reproduces calculation for article: Laine, M., Latva-Pukkila, N., Kyrölä, E., Analyzing time varying trends in stratospheric ozone time series using state space approach, Atmospheric Chemistry and Physics Discussion, 13, pages 20503-20530, 2013. doi:10.5194/acpd-13-20503-2013

First load example data set. Stratospheric ozone observations from two satellite instruments SAGE II and GOMOS. The original satellite observations has been combined and processed to produce averaged zonal data for different altitudes. Here we use monthly avarages between 45 km to 55 km and 40N to 50N for years 1984 to 2012.

load ozonedata.mat % data, label

time = data(:,1); % time in years from 1984 to 2012
y = data(:,2); % ozone density [1/cm^3]
s = data(:,3); % uncertainty standard deviation for y
X = data(:,4:6); % proxies

We scale y for numerical stability.

ys = stdnan(y);
yy = y./ys;
ss = s./ys;

Prior means for some components of W, the model error matrix.

ym = meannan(yy);  % mean observations
wtrend = abs(ym)*0.00005; % trend std
wseas  = abs(ym)*0.015;   % seasonal component std
w0 = [0 wtrend wseas wseas wseas wseas];

Calculate the DLM smoother solution, do MCMC over some components in the matrix W.

options = struct('trig',2,'mcmc',1,'nsimu',2000,'winds',[0 1 2 2 2 2]);
dlm = dlmfit(yy,ss,w0,[],[],X,options);
Sampling these parameters:
name   start [min,max] N(mu,s^2)
w2: -7.48787 [-Inf,Inf] N(-7.48787,1^2)
w3: -1.78409 [-Inf,Inf] N(-1.78409,1^2)

woptv =

  1x0 empty double row vector


woptw =

   0.00063132      0.22512


woptg =

  1x0 empty double row vector

figure(1);
dlmplotfit(dlm, time, ys)
title(label);xlabel('time');ylabel('average O3 density [cm^{-3}]')
figure(2);
dlmplotdiag(dlm, time, ys)

Produce sample from the model states using dlmsmosam. It accounts the posterior uncertainty in W using the MCMC chain in dlm.chain.

nsam = 200; % number of sampled to draw from the posterior
dlm_sample = dlmsmosam(dlm,nsam);

Draw dome sample realizations of the level component over the plot in Figure 2.

figure(1);
hold on
for i=1:5:nsam
  plot(time,ys*squeeze(dlm_sample(1,:,i)),'-')
end
hold off

The next figure shows prior and posterior distributions for standard deviations from the diagonal of model error matrix W.

figure(3); clf
mcmcplot(dlm.chain,[],dlm.res,'denspanel',2);
subplot(2,1,1);title('prior and posterior for variance parameters');xlabel('parameter w(2,2)')
subplot(2,1,2);title('');xlabel('parameter w(3,3)')

Sample trend statistics form DLM sample. We calculate 10 year running trend.

nyear = 10;
tsamp = ys*squeeze(dlm_sample(1,:,:)); % sample of levels
ysm = mean(tsamp(:));                   % their mean
ysf = 1/(ysm*nyear)*100;      % scale factor to get % change / 10 year
t10 = mean((tsamp(nyear*12+1:end,:)-tsamp(1:end-nyear*12,:))')*ysf; % mean trend
s10 = std((tsamp(nyear*12+1:end,:)-tsamp(1:end-nyear*12,:))')*ysf;  % std in the sample
time10 = time(fix(nyear/2)*12+1:end); time10 = time10(1:length(t10)); % time axis for plot
figure(4); clf
confband(time10,t10,s10);grid;
xlim([time(1),time(end)]); % match axis to other plots
title('10 year trend');
ylabel('% change / year')