18
$\begingroup$

The MATLAB code

filter(0.5,[1, -0.5], [1:10]) 

is equivalent to

Rest@FoldList[(#1 + #2)/2. &, 0, Range[10]] 

I don't know how to implement something more general like,filter([1,2,3],[4,5,6], [1:10]) in Mathematica.

I'm trying to rewrite a snippet of MATLAB code to Mathematica. I'm just interested in the filter function and there is no other purpose. What is its equivalent or how can I implement it?

v = [0.0 + 2 j; -sqrt (3) - 1 j; sqrt (3) - 1 j]; n = randi (3, 1, 10000000); p = filter (0.5, [1 - 0.5], v (n)); plot (p, '.b'); 
$\endgroup$
2
  • 4
    $\begingroup$ Perhaps, for the benefit of those readers who do not know Matlab, you could explain what the more general expression means? $\endgroup$ Commented Mar 14, 2013 at 5:12
  • 1
    $\begingroup$ Could you please add an example to your question that makes clear what the a parameter of that function does? $\endgroup$ Commented Mar 14, 2013 at 5:33

3 Answers 3

29
$\begingroup$

There is a misunderstanding of what filter really does in the MATLAB community, largely because of its widespread use as a cheap moving average/smoother (because the actual moving average function is in a paid toolbox).

The function filter(b, a, x) convolves the input list x with a digital filter whose transfer function (TF) is described by the lists b and a. If a is 1, then the filter is an FIR filter and can be easily implemented using ListConvolve. If a is a list, then the filter is an IIR filter whose response is a little more involved.

In either case, the output is given by the following difference equation (I'm using the notation in the IIR wiki page I linked to, for reference):

$$y[n] = \frac{1}{a_{0}} \left(\sum_{i=0}^P b_{i}x[n-i] - \sum_{j=1}^Q a_{j} y[n-j]\right)$$

This can be implemented in Mathematica as:

Clear@filter filter[b_List, a_List, x_List] := Module[{y, L = Length@x, P = Length@b - 1, Q = Length@a - 1, X}, MapIndexed[(X[#2[[1]]] = #) &, x]; X[_] = 0; y[0 | 0. | _?Negative] = 0; y[n_] := y[n] = (Total[b Table[X[n - i], {i, 0, P}]] - Total[Rest@a Table[y[n - j], {j, Q}]])/First@a; Table[y[n], {n, 1, L}] ] 

Normally, this could be solved with RecurrenceTable (and indeed, it works for certain cases), but it doesn't sit well with arbitrary b and a. You can verify the results against MATLAB's filter:

MATLAB:

filter([1,2],1,1:6) % 1 4 7 10 13 16 filter([1,3,1],[3,2],1:6) % 0.3333 1.4444 2.3704 3.4198 4.3868 5.4088 

Mathematica:

filter[{1, 2}, {1}, Range@6] (* {1, 4, 7, 10, 13, 16} *) filter[{1, 3, 1}, {3, 2}, Range@6] // N (* {0.333333, 1.44444, 2.37037, 3.41975, 4.38683, 5.40878} *) 

Note that I don't do any error checking against the length of b and a, etc. That can be easily added, if so desired.

$\endgroup$
0
18
$\begingroup$

In Mathematica 9, there is a more direct way using the function RecurrenceFilter.

For example, the two examples from MATLAB can be done straightforwardly as:

 RecurrenceFilter[{{1}, {1, 2}}, Range[6]] 

and

RecurrenceFilter[{{3, 2}, {1, 3, 1}}, Range[6]] // N 

and return the same answers.

$\endgroup$
5
  • 1
    $\begingroup$ Nice! I should look into more of the new functions in v9 $\endgroup$ Commented Mar 15, 2013 at 18:24
  • 1
    $\begingroup$ There are a number of new functions (and improved functionality) in 9, especially in the signal processing area. Functions like RecurrenceFilter will make it easier for people to transition to Mathematica from Matlab. $\endgroup$ Commented Mar 16, 2013 at 7:05
  • $\begingroup$ @bills, I have another question, for two dimension list, RecurrenceFilter[{{1, -0.5}, {0.5}}, {{1, 2}, {3, 4}, {5, 6}}] isn't equivalent to matlab code filter([0.5], [1,-0.5], [[1,2]; [3,4]; [5,6]]), RecurrenceFilter[{{1, -0.5}, {0.5}}, {x, y, z}] /. {x -> {1, 2}, y -> {3, 4}, z -> {5, 6}} is equivalent to it, but I think it's not efficient , is there a more direct way? $\endgroup$ Commented Mar 24, 2013 at 6:00
  • 1
    $\begingroup$ chyanog -- I think you can just use RecurrenceFilter[{{1, -0.5}, {0.5}}, Transpose[{{1, 2}, {3, 4}, {5, 6}}]] . Neither of these (neither Matlab nor Mathematica) are doing 2D recursion, they are both just applying the filter to the rows (Mathematica) or the columns (Matlab) separately. $\endgroup$ Commented Mar 24, 2013 at 14:33
  • $\begingroup$ For those who want a drop-in replacement when porting MATLAB code, here's what worked for me: filter[b_List, a_List, x_List] := RecurrenceFilter[{a, b}, x]. Note the ordering of a and b. $\endgroup$ Commented Nov 5, 2021 at 19:43
8
$\begingroup$

I think you want ListConvolve or ListCorrelate.
You can implement the example on the linked page like this:

data = Range[1, 4, 0.2]; windowSize = 5; ones = ConstantArray; filter = ListCorrelate[#, #3, -1, 0] &; filter[ones[1, windowSize]/windowSize, 1, data] 
{0.2, 0.44, 0.72, 1.04, 1.4, 1.6, 1.8, 2., 2.2, 2.4, 2.6, 2.8, 3., 3.2, 3.4, 3.6} 

Please note this is not complete: I don't know how the "denominator coefficient vector a" is supposed to be used and the example on that page doesn't make it clear to me yet. Also, I guessed as what ones does and seem to have guessed right, but I didn't look it up.

$\endgroup$
1
  • 2
    $\begingroup$ I suspect the intent expressed in the Matlab reference might be a ratio of convolutions, but it's far from clear. $\endgroup$ Commented Mar 14, 2013 at 5:43

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.