Smoothing/Filtering a NDVI time series using a Savitzky Golay filter and R

Coarse scaled NDVI (or FAPAR, EVI…) images have a high temporal frequency and are delivered as Maximum Value Composites (MVC) of several days, which means the highest value is taken, assuming that clouds and other contaminated pixels have low values. However, especially in areas with a rainy season, the composites over 10-16 days still contain clouds and other disturbances. This figure illustrates a raw MODIS NDVI MVC of 16 days, and it’s obvious that several pixels are contaminated, and it’s also obvious that analyses will be affected by the noisy data.

unfiltered MODIS image
unfiltered MODIS image

Datasets like GIMMS or GEOV1 provide already filtered data, but e.g. MODIS, SPOT VGT, PROBA-V and AVHRR data are raw. The solution is to smooth the time series, using a filter, which calculates a smooth time series and interpolates the bad values using the previous and following images. Here is the same image, but smoothed with a Savitzky Golay filter.

filtered and smoothed MODIS image
filtered and smoothed MODIS image

The data are mostly delivered with quality rasters, rating the quality of each pixel. This can be used to either filter the raster and set bad quality pixels to  NA, or to weight the pixels. When the new time line is calculated, low weighted (i.e. contaminated) pixels are less considered in the calculation process. One possibility is the software TIMESAT (Eklundh & Jönsson, 2011), which offers different filter techniques. Here is an example how timesat smoothes the time line with a Savitzky Golay filter, omitting “bad” pixles and creating new rasters.

A Savitzky Golay filter applied on MODIS using TIMESAT
A Savitzky Golay filter applied on MODIS using TIMESAT

Filtering is also possible in R, and it’s very simple. First one has to decide if one wants to work with quality files, or simply use the raw data, both is possible. GIS software like GRASS has modules which allow an easy use of the quality files:

However, filtering without quality flags also provides reasonable results. Now we assume we have a time series of MODIS data from 2005-2010, with 23 images each year. This data is loaded in R in a raster stack or brick, called MODIS, bad values are masked as NA. We load the libraries, and create a function which uses the Savitzky Golay filter from the signal package. The parameters of the function need to be adapted (p, n, ts) (, also the time frame.



fun <- function(x) {
z=substituteNA(v, type=”mean”)
MODIS.ts2 = ts(z, start=c(2005,1), end=c(2010,23), frequency=23)
x=sgolayfilt(MODIS.ts2, p=1, n=3, ts=30)

MODIS.filtered <- calc(MODIS, fun)

MODIS.filtered is a new brick containing the smoothed time series. Compare the raw with the filtered tims series:

l=cellStats(MODIS, stat=mean)
MODIS.raw.ts = ts(l, start=c(2005,1), end=c(2010,23), frequency=23)
l=cellStats(MODIS.filtered, stat=mean)
MODIS.filt.ts = ts(l, start=c(2005,1), end=c(2010,23), frequency=23)

One may find out the perfect fitting parameters by looking at the whole area, playing with the parameters:

l=cellStats(MODIS, stat=’mean’)
MODIS.ts = ts(l, start=2005, end=c(2010,23), frequency=23)
sg=sgolayfilt(MODIS.ts, p=3, n=9, ts=20)
sg.ts = ts(sg, start=2005, end=c(2010,23), frequency=23)


Eklundh, L.; Jönsson, P. Timesat 3.1 Software Manual. 2011.

10 thoughts on “Smoothing/Filtering a NDVI time series using a Savitzky Golay filter and R

  1. sir i have MODIS ndvi 250m data in .tif format . i have to apply SG filter to smooth the values and use the smoothed data for LULC classification . i tried using timesat but the files are not loading. i am new to programming and i need help .

  2. Thanks for your sharing. It is useful. What is the time scaling factor? How to choose it?and if I have one year data, that means NDVI have 23 subfiles, each subfile contain 20 images. Should I need to mosic subfile images to one image at first or it can deal with directly and how to do it. Thanks

  3. I found great and useful this website, thanks for this. I would like to know how to set the parameters, specially the time scaling factor? Why do you use 30 and then 20? If we compare the parameters in TIMESAT and in this function, which TIMESAT parameters are equivalent in this function?
    Many thanks!

  4. Thanks Martin! Very much appreciate you posting this information. I’m in the process of doing similar analyses for study areas in Chad and Kenya. Really helpful.

  5. Hi Martin. Can you please explain what parameter ts (time scaling factor) means in SG filter. I looked at signal package documentation and also googled on it, but didn’t find anything helpful.

  6. intéressant,je travaille actuellement sur des séries temporelles NDVI MODIS Sur un pays de l’Afrique de l’Ouest(Mali). J’aurais aimé que vous spécifier s’il vous les paramètres (p,n et ts).
    Merci d’avance!!!

  7. Hi, I am smoothing MODIS timeseries from 2001-2017. I am getting this error below. Any idea how I can fix this. Thanks for your help:
    Error in .calcTest(x[1:5], fun, na.rm, forcefun, forceapply) :
    cannot use this function

  8. Hello Dr. Brandt,
    While trying this on a time series data I am getting the following error. Any suggestion towards solving the issue?

    fun1 savgol.trmm <- calc(sbst.trmm, fun1)
    Error in .calcTest(x[1:5], fun, na.rm, forcefun, forceapply) :
    cannot use this function

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s