## Loading required package: openair
## Loading required package: maps
## 
##  # maps v3.1: updated 'world': all lakes moved to separate new #
##  # 'lakes' database. Type '?world' or 'news(package="maps")'.  #
## Loading required package: reshape2

Introduction

The purpose of this analysis is to document the performance of the first ODIN prototypes built and deployed in Chile.

ODIN data

The units pr_ODIN_01-03 were deployed at Parque O’Higgins station.

## ODIN_01
odin_01.raw <- read.table("/home/gustavo/data/ODIN_Chile/pr_odin_01.txt",
                      header=T, quote="")
#force GMT as the time zone to avoid openair issues with daylight saving switches
#The actual time zone is '???'
odin_01.raw$date=as.POSIXct(paste(odin_01.raw$Date,odin_01.raw$Time),tz='GMT')
odin_01.raw$Time<-NULL
odin_01.raw$Date<-NULL
odin_01.raw$Battery<-5*odin_01.raw$Battery/1024

## ODIN_02
odin_02.raw <- read.table("/home/gustavo/data/ODIN_Chile/pr_odin_02.txt",
                      header=T, quote="")
#force GMT as the time zone to avoid openair issues with daylight saving switches
#The actual time zone is 'NZST'
odin_02.raw$date=as.POSIXct(paste(odin_02.raw$Date,odin_02.raw$Time),tz='GMT')
odin_02.raw$Time<-NULL
odin_02.raw$Date<-NULL
odin_02.raw$Battery<-5*odin_02.raw$Battery/1024

## ODIN_03
odin_03.raw <- read.table("/home/gustavo/data/ODIN_Chile/pr_odin_03.txt",
                      header=T, quote="")
#force GMT as the time zone to avoid openair issues with daylight saving switches
#The actual time zone is 'NZST'
odin_03.raw$date=as.POSIXct(paste(odin_03.raw$Date,odin_03.raw$Time),tz='GMT')
odin_03.raw$Time<-NULL
odin_03.raw$Date<-NULL
odin_03.raw$Battery<-5*odin_03.raw$Battery/1024

MMA data

The air quality monitoring station at Parque O’Higgins records PM10 and PM2.5 data.

mma_data <- read.delim("~/data/ODIN_Chile/mma_corr.txt")
mma_data$date <- as.POSIXct(mma_data$date, tz = 'GMT')

Merging the ODIN data

The clocks were not working on all units so independent indices are required to synchronise the data. To do that and because the units didn’t report at regular intervals, it is necessary to homogenise the timebase to 1 minute.

odin_01 <- timeAverage(odin_01.raw[450:112000,],avg.time = '1 min')
odin_02 <- timeAverage(odin_02.raw[450:112000,],avg.time = '1 min')
odin_03 <- timeAverage(odin_03.raw[500:105000,],avg.time = '1 min')

Now we need to create a “date-like” common index that can enable shifting dates between broken clock units as well. The “master” will be ODIN_01 and all units will be “date-shifted” to begin at that same time.

odin_01$date <- odin_01$date - 5*60*60
odin_02$date[1] <- odin_01$date[1]
odin_03$date[1] <- odin_01$date[1]
L2 <- length(odin_02$date)
for (rec in 2:L2){
  odin_02$date[rec] <- odin_02$date[rec-1] + 60
}
L3 <- length(odin_03$date)
for (rec in 2:L3){
  odin_03$date[rec] <- odin_03$date[rec-1] + 60
}

names(odin_01)<-c('date','Dust.01','Humidity.01','Temperature.01','Battery.01')
names(odin_02)<-c('date','Dust.02','Humidity.02','Temperature.02','Battery.02')
names(odin_03)<-c('date','Dust.03','Humidity.03','Temperature.03','Battery.03')

odin <- merge(odin_01,odin_02,by='date',all=TRUE)
odin <- merge(odin,odin_03,by='date',all=TRUE)

Time sync

lag_test=ccf(odin$Temperature.02,
             odin$Temperature.01,
             na.action=na.pass,
             lag.max=100,
             type='covariance',
             ylab='Correlation',
             main='Temperature correlation as function of clock lag')

odin_lag_2=lag_test$lag[which.max(lag_test$acf)]
lag_test=ccf(odin$Temperature.03,
             odin$Temperature.01,
             na.action=na.pass,
             lag.max=100,
             type='covariance',
             ylab='Correlation',
             main='Temperature correlation as function of clock lag')

odin_lag_3=lag_test$lag[which.max(lag_test$acf)]

ODIN_02 is ahead of ODIN_01 by 0 minutes. ODIN_03 is ahead of ODIN_01 by 0 minutes. The correction was applied to the ODIN data as follows:

odin_02$date <- odin_02$date - odin_lag_2*60
odin_03$date <- odin_03$date - odin_lag_3*60

odin <- merge(odin_01,odin_02,by='date',all=TRUE)
odin <- merge(odin,odin_03,by='date',all=TRUE)

lag_test=ccf(odin$Temperature.02,
             odin$Temperature.01,
             na.action=na.pass,
             lag.max=100,
             type='covariance',
             ylab='Correlation',
             main='Temperature correlation as function of clock lag')

odin_lag_2=lag_test$lag[which.max(lag_test$acf)]
lag_test=ccf(odin$Temperature.03,
             odin$Temperature.01,
             na.action=na.pass,
             lag.max=100,
             type='covariance',
             ylab='Correlation',
             main='Temperature correlation as function of clock lag')

odin_lag_3=lag_test$lag[which.max(lag_test$acf)]

Remove drift from ODIN raw data

It has been documented that the dust sensors suffer from significant drift, therefore a linear fit of the baseline drift is estimated.

# Estimate the baseline from a simple linear regression
odin$ODIN_drift.01<-predict(lm(odin$Dust.01~seq(odin$Dust.01)),newdata = odin)
odin$ODIN_drift.02<-predict(lm(odin$Dust.02~seq(odin$Dust.02)),newdata = odin)
odin$ODIN_drift.03<-predict(lm(odin$Dust.03~seq(odin$Dust.03)),newdata = odin)

# Remove the baseline drift from the raw ODIN data

odin$Dust.01.raw <- odin$Dust.01
odin$Dust.01.detrend<-odin$Dust.01.raw - odin$ODIN_drift.01

odin$Dust.02.raw <- odin$Dust.02
odin$Dust.02.detrend<-odin$Dust.02.raw - odin$ODIN_drift.02

odin$Dust.03.raw <- odin$Dust.03
odin$Dust.03.detrend<-odin$Dust.03.raw - odin$ODIN_drift.03

Calculate the temperature interference

The Sharp sensors have a documented positive interference from temperature which means that at higher temperatures, the instrument overestimates the dust concentrations.

Some plots to see the effect that temperature has on the Dust signal:

scatterPlot(odin,'Temperature.01','Dust.01.detrend')

scatterPlot(odin,'Temperature.02','Dust.02.detrend')

scatterPlot(odin,'Temperature.03','Dust.03.detrend')

First we divide the temperature range for each unit.

odin$Temperature.01.bin<-cut(odin$Temperature.01,breaks = c(0,5,10,15,20,25),labels = c('2.5','7.5','12.5','17.5','22.5'))
odin$Temperature.02.bin<-cut(odin$Temperature.02,breaks = c(0,5,10,15,20,25),labels = c('2.5','7.5','12.5','17.5','22.5'))
odin$Temperature.03.bin<-cut(odin$Temperature.03,breaks = c(0,5,10,15,20,25),labels = c('2.5','7.5','12.5','17.5','22.5'))

Temp <- c(2.5,7.5,12.5,17.5,22.5)

Dust.01<-tapply(odin$Dust.01.detrend,odin$Temperature.01.bin,quantile,0.25)
Dust.02<-tapply(odin$Dust.02.detrend,odin$Temperature.02.bin,quantile,0.25)
Dust.03<-tapply(odin$Dust.03.detrend,odin$Temperature.03.bin,quantile,0.25)

TC_Dust.01 <- data.frame(Dust.01.detrend = Dust.01,Temperature.01 = Temp)
TC_Dust.02 <- data.frame(Dust.02.detrend = Dust.02,Temperature.02 = Temp)
TC_Dust.03 <- data.frame(Dust.03.detrend = Dust.03,Temperature.03 = Temp)

Now we calculate the linear regression for the minimum dust response in each temperature bin and subtract it from the detrended data

summary(odin.01_T<-lm(data = TC_Dust.01,Dust.01.detrend~Temperature.01))
## 
## Call:
## lm(formula = Dust.01.detrend ~ Temperature.01, data = TC_Dust.01)
## 
## Residuals:
##     7.5    12.5    17.5    22.5 
## -0.2970  0.1002  0.6906 -0.4938 
## 
## Coefficients:
##                Estimate Std. Error t value Pr(>|t|)   
## (Intercept)     2.29357    0.91625   2.503   0.1293   
## Temperature.01 -0.62431    0.05724 -10.907   0.0083 **
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 0.6399 on 2 degrees of freedom
##   (1 observation deleted due to missingness)
## Multiple R-squared:  0.9835, Adjusted R-squared:  0.9752 
## F-statistic:   119 on 1 and 2 DF,  p-value: 0.008301
summary(odin.02_T<-lm(data = TC_Dust.02,Dust.02.detrend~Temperature.02))
## 
## Call:
## lm(formula = Dust.02.detrend ~ Temperature.02, data = TC_Dust.02)
## 
## Residuals:
##    7.5   12.5   17.5   22.5 
## -3.157  3.172  3.125 -3.141 
## 
## Coefficients:
##                Estimate Std. Error t value Pr(>|t|)
## (Intercept)      0.9611     6.3760   0.151    0.894
## Temperature.02  -0.8642     0.3983  -2.170    0.162
## 
## Residual standard error: 4.453 on 2 degrees of freedom
##   (1 observation deleted due to missingness)
## Multiple R-squared:  0.7018, Adjusted R-squared:  0.5528 
## F-statistic: 4.708 on 1 and 2 DF,  p-value: 0.1622
summary(odin.03_T<-lm(data = TC_Dust.03,Dust.03.detrend~Temperature.03))
## 
## Call:
## lm(formula = Dust.03.detrend ~ Temperature.03, data = TC_Dust.03)
## 
## Residuals:
##     7.5    12.5    17.5    22.5 
## -0.8969  1.2186  0.2535 -0.5752 
## 
## Coefficients:
##                Estimate Std. Error t value Pr(>|t|)  
## (Intercept)      6.5002     1.6588   3.919   0.0594 .
## Temperature.03  -0.8450     0.1036  -8.154   0.0147 *
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 1.159 on 2 degrees of freedom
##   (1 observation deleted due to missingness)
## Multiple R-squared:  0.9708, Adjusted R-squared:  0.9562 
## F-statistic: 66.49 on 1 and 2 DF,  p-value: 0.01471

Apparently, in this deployment, the ambient temperature doesn’t seem to significantly affect the Dust signal… Interesting. But let’s continue with the correction but bear in mind that we are overcorrecting this time because the regression with temperature is not significant.

odin$Dust.01.corr <- odin$Dust.01.detrend - predict(odin.01_T,newdata = odin)
odin$Dust.02.corr <- odin$Dust.02.detrend - predict(odin.02_T,newdata = odin)
odin$Dust.03.corr <- odin$Dust.03.detrend - predict(odin.03_T,newdata = odin)

Merging the MMA data

Trusting the clock on the MMA data, it will be merged “as is” and matched to ODIN-01 clock that it’s assumed to be working

all_data <- merge(odin,mma_data, by = 'date', all = TRUE)

Fitting the data

Using MMA’s data it is possible to find the best linear fit between both the detrended and corrected data from ODIN.

For the corrected ODIN data the conversion would be: \(Dust_{calibrated}=A*Dust_{corrected}+B\)

So, the regression to obtain \(A\) and \(B\) will be:

data2fit <- timeAverage(all_data,avg.time = '1 hour')
summary(odin1.lm.full.1hr.pm10<-
          lm(data=data2fit,PM10~Dust.01.corr))
## 
## Call:
## lm(formula = PM10 ~ Dust.01.corr, data = data2fit)
## 
## Residuals:
##      Min       1Q   Median       3Q      Max 
## -111.772  -23.208   -7.228   21.077  101.908 
## 
## Coefficients:
##              Estimate Std. Error t value Pr(>|t|)    
## (Intercept)   71.8604     3.7171   19.33  < 2e-16 ***
## Dust.01.corr   1.5108     0.3546    4.26 3.56e-05 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 36.94 on 152 degrees of freedom
##   (44 observations deleted due to missingness)
## Multiple R-squared:  0.1067, Adjusted R-squared:  0.1008 
## F-statistic: 18.15 on 1 and 152 DF,  p-value: 3.563e-05
summary(odin2.lm.full.1hr.pm10<-
          lm(data=data2fit,PM10~Dust.02.corr))
## 
## Call:
## lm(formula = PM10 ~ Dust.02.corr, data = data2fit)
## 
## Residuals:
##     Min      1Q  Median      3Q     Max 
## -96.926 -25.948  -6.696  21.787 101.659 
## 
## Coefficients:
##              Estimate Std. Error t value Pr(>|t|)    
## (Intercept)   73.7146     3.8189  19.303  < 2e-16 ***
## Dust.02.corr   0.6755     0.2044   3.305  0.00118 ** 
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 37.75 on 152 degrees of freedom
##   (44 observations deleted due to missingness)
## Multiple R-squared:  0.06704,    Adjusted R-squared:  0.0609 
## F-statistic: 10.92 on 1 and 152 DF,  p-value: 0.001185
summary(odin3.lm.full.1hr.pm10<-
          lm(data=data2fit,PM10~Dust.03.corr))
## 
## Call:
## lm(formula = PM10 ~ Dust.03.corr, data = data2fit)
## 
## Residuals:
##    Min     1Q Median     3Q    Max 
## -68.91 -28.06 -10.40  23.95 103.37 
## 
## Coefficients:
##              Estimate Std. Error t value Pr(>|t|)    
## (Intercept)   78.4168     3.8799  20.211   <2e-16 ***
## Dust.03.corr   0.4465     0.3482   1.283    0.202    
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 39.42 on 147 degrees of freedom
##   (49 observations deleted due to missingness)
## Multiple R-squared:  0.01107,    Adjusted R-squared:  0.004338 
## F-statistic: 1.645 on 1 and 147 DF,  p-value: 0.2017
summary(odin1.lm.full.1hr.pm2.5<-
          lm(data=data2fit,PM2.5~Dust.01.corr))
## 
## Call:
## lm(formula = PM2.5 ~ Dust.01.corr, data = data2fit)
## 
## Residuals:
##     Min      1Q  Median      3Q     Max 
## -26.400 -10.414  -1.802   8.644  42.727 
## 
## Coefficients:
##              Estimate Std. Error t value Pr(>|t|)    
## (Intercept)   38.5411     1.4501  26.579   <2e-16 ***
## Dust.01.corr   0.3185     0.1384   2.302   0.0227 *  
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 14.34 on 152 degrees of freedom
##   (44 observations deleted due to missingness)
## Multiple R-squared:  0.03369,    Adjusted R-squared:  0.02734 
## F-statistic:   5.3 on 1 and 152 DF,  p-value: 0.02268
summary(odin2.lm.full.1hr.pm2.5<-
          lm(data=data2fit,PM2.5~Dust.02.corr))
## 
## Call:
## lm(formula = PM2.5 ~ Dust.02.corr, data = data2fit)
## 
## Residuals:
##     Min      1Q  Median      3Q     Max 
## -22.378 -10.969  -1.803   8.601  43.561 
## 
## Coefficients:
##              Estimate Std. Error t value Pr(>|t|)    
## (Intercept)  38.83319    1.46157  26.570   <2e-16 ***
## Dust.02.corr  0.15211    0.07828   1.943   0.0539 .  
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 14.41 on 152 degrees of freedom
##   (44 observations deleted due to missingness)
## Multiple R-squared:  0.02424,    Adjusted R-squared:  0.01782 
## F-statistic: 3.776 on 1 and 152 DF,  p-value: 0.05385
summary(odin3.lm.full.1hr.pm2.5<-
          lm(data=data2fit,PM2.5~Dust.03.corr))
## 
## Call:
## lm(formula = PM2.5 ~ Dust.03.corr, data = data2fit)
## 
## Residuals:
##     Min      1Q  Median      3Q     Max 
## -22.319 -11.106  -3.055   9.267  44.282 
## 
## Coefficients:
##              Estimate Std. Error t value Pr(>|t|)    
## (Intercept)  40.03348    1.47711  27.102   <2e-16 ***
## Dust.03.corr  0.06367    0.13344   0.477    0.634    
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 14.8 on 147 degrees of freedom
##   (49 observations deleted due to missingness)
## Multiple R-squared:  0.001546,   Adjusted R-squared:  -0.005246 
## F-statistic: 0.2276 on 1 and 147 DF,  p-value: 0.634
all_data$Dust.01.cal.10<-predict(odin1.lm.full.1hr.pm10,newdata = all_data)
all_data$Dust.02.cal.10<-predict(odin2.lm.full.1hr.pm10,newdata = all_data)
all_data$Dust.03.cal.10<-predict(odin3.lm.full.1hr.pm10,newdata = all_data)

all_data$Dust.01.cal.2.5<-predict(odin1.lm.full.1hr.pm2.5,newdata = all_data)
all_data$Dust.02.cal.2.5<-predict(odin2.lm.full.1hr.pm2.5,newdata = all_data)
all_data$Dust.03.cal.2.5<-predict(odin3.lm.full.1hr.pm2.5,newdata = all_data)

For the detrended ODIN data the conversion would be: \(Dust_{calibrated}=A_{dust}*Dust_{corrected}+A_{temperature}*Temperature+B\)

So, the regression to obtain \(A_{dust}\), \(A_{temperature}\) and \(B\) will be:

summary(odin1.lm.full.1hr.pm10.d<-
          lm(data=data2fit,PM10~Temperature.01 + Dust.01.detrend))
## 
## Call:
## lm(formula = PM10 ~ Temperature.01 + Dust.01.detrend, data = data2fit)
## 
## Residuals:
##      Min       1Q   Median       3Q      Max 
## -109.020  -23.073   -7.174   22.026   98.451 
## 
## Coefficients:
##                 Estimate Std. Error t value Pr(>|t|)    
## (Intercept)      59.8479     8.8140   6.790 2.41e-10 ***
## Temperature.01    1.5535     0.5940   2.615  0.00982 ** 
## Dust.01.detrend   1.5029     0.3544   4.240 3.88e-05 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 36.91 on 151 degrees of freedom
##   (44 observations deleted due to missingness)
## Multiple R-squared:  0.1139, Adjusted R-squared:  0.1021 
## F-statistic: 9.702 on 2 and 151 DF,  p-value: 0.0001087
summary(odin2.lm.full.1hr.pm10.d<-
          lm(data=data2fit,PM10~Temperature.02 + Dust.02.detrend))
## 
## Call:
## lm(formula = PM10 ~ Temperature.02 + Dust.02.detrend, data = data2fit)
## 
## Residuals:
##      Min       1Q   Median       3Q      Max 
## -101.354  -25.876   -7.573   22.273   94.314 
## 
## Coefficients:
##                 Estimate Std. Error t value Pr(>|t|)    
## (Intercept)      55.4162     9.5528   5.801 3.74e-08 ***
## Temperature.02    1.8313     0.6407   2.858 0.004861 ** 
## Dust.02.detrend   0.7691     0.2076   3.706 0.000295 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 37.37 on 151 degrees of freedom
##   (44 observations deleted due to missingness)
## Multiple R-squared:  0.09168,    Adjusted R-squared:  0.07965 
## F-statistic: 7.621 on 2 and 151 DF,  p-value: 0.0007029
summary(odin3.lm.full.1hr.pm10.d<-
          lm(data=data2fit,PM10~Temperature.03 + Dust.03.detrend))
## 
## Call:
## lm(formula = PM10 ~ Temperature.03 + Dust.03.detrend, data = data2fit)
## 
## Residuals:
##     Min      1Q  Median      3Q     Max 
## -67.516 -26.700  -9.964  23.232  97.274 
## 
## Coefficients:
##                 Estimate Std. Error t value Pr(>|t|)    
## (Intercept)      59.5539    11.5734   5.146 8.45e-07 ***
## Temperature.03    1.5026     0.7774   1.933   0.0552 .  
## Dust.03.detrend   0.5031     0.3484   1.444   0.1508    
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 39.23 on 146 degrees of freedom
##   (49 observations deleted due to missingness)
## Multiple R-squared:  0.02733,    Adjusted R-squared:  0.01401 
## F-statistic: 2.051 on 2 and 146 DF,  p-value: 0.1323
summary(odin1.lm.full.1hr.pm2.5.d<-
          lm(data=data2fit,PM2.5~Temperature.01 + Dust.01.detrend))
## 
## Call:
## lm(formula = PM2.5 ~ Temperature.01 + Dust.01.detrend, data = data2fit)
## 
## Residuals:
##     Min      1Q  Median      3Q     Max 
## -25.820 -10.269  -2.333   8.941  43.039 
## 
## Coefficients:
##                 Estimate Std. Error t value Pr(>|t|)    
## (Intercept)      36.2220     3.4379  10.536   <2e-16 ***
## Temperature.01    0.3116     0.2303   1.353   0.1781    
## Dust.01.detrend   0.3177     0.1387   2.291   0.0234 *  
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 14.37 on 151 degrees of freedom
##   (44 observations deleted due to missingness)
## Multiple R-squared:  0.03547,    Adjusted R-squared:  0.0227 
## F-statistic: 2.777 on 2 and 151 DF,  p-value: 0.06542
summary(odin2.lm.full.1hr.pm2.5.d<-
          lm(data=data2fit,PM2.5~Temperature.02 + Dust.02.detrend))
## 
## Call:
## lm(formula = PM2.5 ~ Temperature.02 + Dust.02.detrend, data = data2fit)
## 
## Residuals:
##     Min      1Q  Median      3Q     Max 
## -22.494 -11.078  -1.303   8.010  44.134 
## 
## Coefficients:
##                 Estimate Std. Error t value Pr(>|t|)    
## (Intercept)     34.87174    3.70052   9.423   <2e-16 ***
## Temperature.02   0.39948    0.24686   1.618   0.1077    
## Dust.02.detrend  0.17379    0.08053   2.158   0.0325 *  
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 14.39 on 151 degrees of freedom
##   (44 observations deleted due to missingness)
## Multiple R-squared:  0.0324, Adjusted R-squared:  0.01959 
## F-statistic: 2.528 on 2 and 151 DF,  p-value: 0.08316
summary(odin3.lm.full.1hr.pm2.5.d<-
          lm(data=data2fit,PM2.5~Temperature.03 + Dust.03.detrend))
## 
## Call:
## lm(formula = PM2.5 ~ Temperature.03 + Dust.03.detrend, data = data2fit)
## 
## Residuals:
##     Min      1Q  Median      3Q     Max 
## -21.948 -10.903  -2.527   9.097  44.750 
## 
## Coefficients:
##                 Estimate Std. Error t value Pr(>|t|)    
## (Intercept)     36.47744    4.40715   8.277  7.3e-14 ***
## Temperature.03   0.27387    0.29392   0.932    0.353    
## Dust.03.detrend  0.07654    0.13454   0.569    0.570    
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 14.81 on 146 degrees of freedom
##   (49 observations deleted due to missingness)
## Multiple R-squared:  0.006023,   Adjusted R-squared:  -0.007593 
## F-statistic: 0.4424 on 2 and 146 DF,  p-value: 0.6434
all_data$Dust.01.cal.10d<-predict(odin1.lm.full.1hr.pm10.d,newdata = all_data)
all_data$Dust.02.cal.10d<-predict(odin2.lm.full.1hr.pm10.d,newdata = all_data)
all_data$Dust.03.cal.10d<-predict(odin3.lm.full.1hr.pm10.d,newdata = all_data)

all_data$Dust.01.cal.2.5d<-predict(odin1.lm.full.1hr.pm2.5.d,newdata = all_data)
all_data$Dust.02.cal.2.5d<-predict(odin2.lm.full.1hr.pm2.5.d,newdata = all_data)
all_data$Dust.03.cal.2.5d<-predict(odin3.lm.full.1hr.pm2.5.d,newdata = all_data)

Some plots

Now we can compare the ODIN response to the official PM10 and PM2.5 data.

ODIN 1

timePlot(all_data,pollutant = c('Dust.01.cal.10',
                                'Dust.01.cal.10d',
                            'PM10')
         ,avg.time = '1 hour'
         ,group = TRUE
         ,main = 'Odin data against PM10')

timeVariation(all_data,pollutant = c('Dust.01.cal.10',
                                'Dust.01.cal.10d',
                                'PM10'))

timePlot(all_data,pollutant = c('Dust.01.cal.2.5',
                                'Dust.01.cal.2.5d',
                            'PM2.5')
         ,avg.time = '1 hour'
         ,group = TRUE
         ,main = 'Odin data against PM2.5')

timeVariation(all_data,pollutant = c('Dust.01.cal.2.5',
                                'Dust.01.cal.2.5d',
                                'PM2.5'))

ODIN 2

timePlot(all_data,pollutant = c('Dust.02.cal.10',
                                'Dust.02.cal.10d',
                            'PM10')
         ,avg.time = '1 hour'
         ,group = TRUE
         ,main = 'Odin data against PM10')

timeVariation(all_data,pollutant = c('Dust.02.cal.10',
                                'Dust.02.cal.10d',
                                'PM10'))

timePlot(all_data,pollutant = c('Dust.02.cal.2.5',
                                'Dust.02.cal.2.5d',
                            'PM2.5')
         ,avg.time = '1 hour'
         ,group = TRUE
         ,main = 'Odin data against PM2.5')

timeVariation(all_data,pollutant = c('Dust.02.cal.2.5',
                                'Dust.02.cal.2.5d',
                                'PM2.5'))

ODIN 3

timePlot(all_data,pollutant = c('Dust.03.cal.10',
                                'Dust.03.cal.10d',
                            'PM10')
         ,avg.time = '1 hour'
         ,group = TRUE
         ,main = 'Odin data against PM10')

timeVariation(all_data,pollutant = c('Dust.03.cal.10',
                                'Dust.03.cal.10d',
                                'PM10'))

timePlot(all_data,pollutant = c('Dust.03.cal.2.5',
                                'Dust.03.cal.2.5d',
                            'PM2.5')
         ,avg.time = '1 hour'
         ,group = TRUE
         ,main = 'Odin data against PM2.5')

timeVariation(all_data,pollutant = c('Dust.03.cal.2.5',
                                'Dust.03.cal.2.5d',
                                'PM2.5'))

System information

The preceeding analysis was performed in the following system:

sessionInfo()
## R version 3.3.1 (2016-06-21)
## Platform: x86_64-redhat-linux-gnu (64-bit)
## Running under: Fedora 24 (Workstation Edition)
## 
## locale:
##  [1] LC_CTYPE=en_NZ.UTF-8       LC_NUMERIC=C              
##  [3] LC_TIME=en_NZ.UTF-8        LC_COLLATE=en_NZ.UTF-8    
##  [5] LC_MONETARY=en_NZ.UTF-8    LC_MESSAGES=en_NZ.UTF-8   
##  [7] LC_PAPER=en_NZ.UTF-8       LC_NAME=C                 
##  [9] LC_ADDRESS=C               LC_TELEPHONE=C            
## [11] LC_MEASUREMENT=en_NZ.UTF-8 LC_IDENTIFICATION=C       
## 
## attached base packages:
## [1] stats     graphics  grDevices utils     datasets  methods   base     
## 
## other attached packages:
## [1] reshape2_1.4.1 openair_1.8-6  maps_3.1.0    
## 
## loaded via a namespace (and not attached):
##  [1] Rcpp_0.12.5         knitr_1.13          cluster_2.0.4      
##  [4] magrittr_1.5        lattice_0.20-33     R6_2.1.2           
##  [7] mapdata_2.2-6       plyr_1.8.3          stringr_1.0.0      
## [10] dplyr_0.4.3         tools_3.3.1         parallel_3.3.1     
## [13] grid_3.3.1          nlme_3.1-128        mgcv_1.8-12        
## [16] png_0.1-7           latticeExtra_0.6-28 DBI_0.4-1          
## [19] htmltools_0.3.5     lazyeval_0.1.10     yaml_2.1.13        
## [22] digest_0.6.9        assertthat_0.1      RJSONIO_1.3-0      
## [25] Matrix_1.2-6        mapproj_1.2-4       RColorBrewer_1.1-2 
## [28] formatR_1.4         evaluate_0.9        rmarkdown_0.9.6    
## [31] stringi_1.1.1       RgoogleMaps_1.2.0.7 lubridate_1.5.6    
## [34] hexbin_1.27.1