Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I run a high pass or low pass filter on data points in R?

I am a beginner in R and I have tried to find information about the following without finding anything.

The green graph in the picture is composed by the red and yellow graphs. But let's say that I only have the data points of something like the green graph. How do I extract the low/high frequencies (i.e. approximately the red/yellow graphs) using a low pass/high pass filter?

low frequency sinus curve with high frequency sinus curve modulated onto

Update: The graph was generated with

number_of_cycles = 2 max_y = 40  x = 1:500 a = number_of_cycles * 2*pi/length(x)  y = max_y * sin(x*a) noise1 = max_y * 1/10 * sin(x*a*10)  plot(x, y, type="l", col="red", ylim=range(-1.5*max_y,1.5*max_y,5)) points(x, y + noise1, col="green", pch=20) points(x, noise1, col="yellow", pch=20) 

Update 2: Using the Butterworth filter in the signal package suggested I get the following:

Original picture with filtered graphs added

library(signal)  bf <- butter(2, 1/50, type="low") b <- filter(bf, y+noise1) points(x, b, col="black", pch=20)  bf <- butter(2, 1/25, type="high") b <- filter(bf, y+noise1) points(x, b, col="black", pch=20) 

The calculations was a bit work, signal.pdf gave next to no hints about what values W should have, but the original octave documentation at least mentioned radians which got me going. The values in my original graph was not chosen with any specific frequency in mind, so I ended up with the following not so simple frequencies: f_low = 1/500 * 2 = 1/250, f_high = 1/500 * 2*10 = 1/25 and the sampling frequency f_s = 500/500 = 1. Then I chose a f_c somewhere inbetween the low and high frequencies for the low/high pass filters (1/100 and 1/50 respectively).

like image 933
hlovdal Avatar asked Aug 18 '11 10:08

hlovdal


People also ask

How do I apply a low-pass filter to data?

Lowpass Filter Steepness Filter white noise sampled at 1 kHz using an infinite impulse response lowpass filter with a passband frequency of 200 Hz. Use different steepness values. Plot the spectra of the filtered signals. Compute and plot the frequency responses of the filters.

How do you determine if a filter is low-pass or high pass?

Filters can be placed into broad categories that correspond to the general characteristics of the filter's frequency response. If a filter passes low frequencies and blocks high frequencies, it is called a low-pass filter. If it blocks low frequencies and passes high frequencies, it is a high-pass filter.

How do I add a high pass filter?

In the Filter menu, select Other, then High Pass. Go to the Filter menu and select Other, and then High Pass. You will see the entire image turn a flat grey color. Not to worry, as this will allow you to see what the filter is doing.

How do you make a band pass filter using low-pass and high pass?

A simple passive Band Pass Filter can be made by cascading together a single Low Pass Filter with a High Pass Filter. The frequency range, in Hertz, between the lower and upper -3dB cut-off points of the RC combination is know as the filters “Bandwidth”.


2 Answers

I bumped into similar problem recently and did not find the answers here particularly helpful. Here is an alternative approach.

Let´s start by defining the example data from the question:

number_of_cycles = 2 max_y = 40  x = 1:500 a = number_of_cycles * 2*pi/length(x)  y = max_y * sin(x*a) noise1 = max_y * 1/10 * sin(x*a*10) y <- y + noise1  plot(x, y, type="l", ylim=range(-1.5*max_y,1.5*max_y,5), lwd = 5, col = "green") 

enter image description here

So the green line is the dataset we want to low-pass and high-pass filter.

Side note: The line in this case could be expressed as a function by using cubic spline (spline(x,y, n = length(x))), but with real world data this would rarely be the case, so let's assume that it is not possible to express the dataset as a function.

The easiest way to smooth such data I have came across is to use loess or smooth.spline with appropriate span/spar. According to statisticians loess/smooth.spline is probably not the right approach here, as it does not really present a defined model of the data in that sense. An alternative is to use Generalized Additive Models (gam() function from package mgcv). My argument for using loess or smoothed spline here is that it is easier and does not make a difference as we are interested in the visible resulting pattern. Real world datasets are more complicated than in this example and finding a defined function for filtering several similar datasets might be difficult. If the visible fit is good, why to make it more complicated with R2 and p values? To me the application is visual for which loess/smoothed splines are appropriate methods. Both of the methods assume polynomial relationships with the difference that loess is more flexible also using higher degree polynomials, while cubic spline is always cubic (x^2). Which one to use depends on trends in a dataset. That said, the next step is to apply a low-pass filter on the dataset by using loess() or smooth.spline():

lowpass.spline <- smooth.spline(x,y, spar = 0.6) ## Control spar for amount of smoothing lowpass.loess <- loess(y ~ x, data = data.frame(x = x, y = y), span = 0.3) ## control span to define the amount of smoothing  lines(predict(lowpass.spline, x), col = "red", lwd = 2) lines(predict(lowpass.loess, x), col = "blue", lwd = 2) 

enter image description here

Red line is the smoothed spline filter and blue the loess filter. As you see results differ slightly. I guess one argument of using GAM would be to find the best fit, if the trends really were this clear and consistent among datasets, but for this application both of these fits are good enough for me.

After finding a fitting low-pass filter, the high-pass filtering is as simple as subtracting the low-pass filtered values from y:

highpass <- y - predict(lowpass.loess, x) lines(x, highpass, lwd =  2) 

enter image description here

This answer comes late, but I hope it helps someone else struggling with similar problem.

like image 119
Mikko Avatar answered Oct 06 '22 17:10

Mikko


Use filtfilt function instead of filter (package signal) to get rid of signal shift.

library(signal) bf <- butter(2, 1/50, type="low") b1 <- filtfilt(bf, y+noise1) points(x, b1, col="red", pch=20) 

Red line shows result of filtfilt

like image 33
d2a2d Avatar answered Oct 06 '22 16:10

d2a2d