R lowpass filter using Signal package

1.8k views Asked by At

I am new to R and having trouble fitting a Lowpass filter to my data. I am measuring Force exerted on a treadmil over a period of 30 seconds with a sample rate of 250/s or 250Hz.

The data contains negative force values as seen in this image

This is due to ripples in the signal or background noise. I need to be able to filter out any force signal <0, and for this I have used the Butter function within the Signal package:

ritLowPass = function(s, frqCutOff, bPlot = F ) 

  {
  f = butter( 4, frqCutOff/(smpRate/2), "low" ); # lowpass filter 

  s.lp = rev( filter( f, rev( filter( f, s ))) );
  if( bPlot ) {


    idx=(1*smpRate):(4*smpRate);
    plot( x=idx/smpRate, y=s[idx], xlab="time/s", ylab="signal", ty="l" );
    lines( x=idx/smpRate, y=s.lp[idx], col="red", lwd=2) 
  }


  return(data.frame(s.lp));
}


VT_filter <- ritLowPass(guest$Fz, 250, bPlot)

sample data:

Time    Fz
0        3.769
0.004   -32.94
0.008   -117.305
0.012   -142.329
0.016   -55.35
0.02    -27.362
0.024   29.039
0.028   73.718
0.032   76.633
0.036   4.482
0.04    -80.949
0.044   -114.279
0.048   -102.968
0.052   -9.76
0.056   35.405
0.06    152.541
0.064   79.249
0.068   50.147
0.072   22.547
0.076   47.757
0.08    -29.123
0.084   57.384
0.088   88.715
0.092   195.115
0.096   118.752
0.1     183.22
0.104   157.957
0.108   37.992
0.112   -7.893

When I run the code I get the following error:

 VT_filter <- ritLowPass(guest$Fz, 250, bPlot)
Error in butter.default(4, frqCutOff/(smpRate/2), "low") : 
  butter: critical frequencies must be in (0 1)
Called from: butter.default(4, frqCutOff/(smpRate/2), "low")

I wonder if I should be using HighPass instead or is there another option for attenuating any force signal lower than zero?

2

There are 2 answers

5
Jason On

Preamble

I'm not sure I can see anything in the data that suggests your "culprit" frequency is 250 Hz, or that you should cut frequencies above this value.

If you're trying to remove signal noise at a specific frequency, you'll need to find the noise frequency first. spectrum is your friend.

However, assuming you actually want to filter frequencies above 250 Hz:

Short Answer

If you want to filter frequencies above 250 Hz, your sampling frequency needs to be at least 500 Hz.

Long Answer

Your filter can only filter between frequencies of 0 and the Nyquist frequency, i.e. 0 to (Sampling Frequency)/2. This is a hard limit of information theory, not an implementation issue.

You're asking it to filter something that is twice the Nyquist Frequency.

help(butter) gives the following about the W parameter:

W: critical frequencies of the filter. ... For digital filters, W must be between 0 and 1 where 1 is the Nyquist frequency.

The cutoff value you are trying to assign to the filter is (250)/(250/2) = 2. The function is telling you this is outside its capabilities (or the capabilities of any digital filter).

0
mrKirushko On

From the question it looks like you did not bother to read the whole output of ?butter manual. The frequencies for pretty much all filter design functions in the package are only used relative to the Nyquist frequency so whenever a function asks you for a frequency f_1 you are expected to provide it with f_1/(f_sample/2) and the result is expected to be between 0 and 1 because your signal is expected not to have nonrecoverable distortions. They don't tell you the simple equation exactly and they have some mistakes in the manuals (like the formula for the bilinear transform function) but you are of course expected to have some general and basic knowledge about the topic before you attempt to use the package so it is not a big deal.

Also if the only thing that makes you worry for whatever reason is the negative signal values then why even bother trying to filter it? Here I use the definition of the word "filtering" found in DSP-related books of course which is probably not what you mean in the question. You can just do something like guest$Fz[guest$Fz<0]=0. It is generally a better idea than using NAs or removing the samples completely because the missing values and therefore irregular sampling creates global signal artifacts and it is much worse than local high frequency spikes from just replacing a single sample value with another. Then you can use some data smoothing method to make your signal look nicer if you feel a need to do so.

In fact my guess is that this is some purely educational test signal and you probably really need to filter the signal with a simple low pass filter and the single cutoff frequency required is well below the 250Hz Fs and the negative values are not a problem by themselves but rather they are an indication of really bad or nonexistent filtering but who knows...