Processing math: 100%
In [1]:
 



1  A basic introduction to filtering

Through examples, we define several operations on signals and show how they transform them. Then we define what is a filter and the notion of impulse response.

1.1  Transformations of signals - Examples of difference equations

We begin by defining a test signal.

In [2]:
# rectangular pulse
N=20; L=5; M=10
r=np.zeros(N)

r[L:M]=1
#
plt.stem(r)
_=plt.ylim([0, 1.2])
In [3]:
def op1(signal):
    transformed_signal=np.zeros(np.size(signal))
    for t in np.arange(np.size(signal)):
        transformed_signal[t]=signal[t]-signal[t-1]
    return transformed_signal    

def op2(signal):
    transformed_signal=np.zeros(np.size(signal))
    for t in np.arange(np.size(signal)):
        transformed_signal[t]=0.5*signal[t]+0.5*signal[t-1]
    return transformed_signal
In [4]:
plt.figure()
plt.stem(op1(r))
_=plt.ylim([-1.2, 1.2])
plt.title("Filtering of rectangular signal with op1")
plt.figure()
plt.stem(op2(r),'r')
_=plt.ylim([-0.2, 1.2])
plt.title("Filtering of rectangular signal with op2")
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
<ipython-input-4-e2dbae2047ad> in <module>()
      4 plt.title("Filtering of rectangular signal with op1")
      5 plt.figure()
----> 6 plt.stem(op2(r),'r')
      7 _=plt.ylim([-0.2, 1.2])
      8 plt.title("Filtering of rectangular signal with op2")

/usr/local/lib/python3.5/site-packages/matplotlib/pyplot.py in stem(linefmt, markerfmt, basefmt, bottom, label, data, *args)
   2924         *args, linefmt=linefmt, markerfmt=markerfmt, basefmt=basefmt,
   2925         bottom=bottom, label=label, **({"data": data} if data is not
-> 2926         None else {}))
   2927 
   2928 

/usr/local/lib/python3.5/site-packages/matplotlib/__init__.py in inner(ax, data, *args, **kwargs)
   1808                         "the Matplotlib list!)" % (label_namer, func.__name__),
   1809                         RuntimeWarning, stacklevel=2)
-> 1810             return func(ax, *args, **kwargs)
   1811 
   1812         inner.__doc__ = _add_data_doc(inner.__doc__,

/usr/local/lib/python3.5/site-packages/matplotlib/axes/_axes.py in stem(self, linefmt, markerfmt, basefmt, bottom, label, *args)
   2625         else:
   2626             x = y
-> 2627             y = np.asarray(args[0], dtype=float)
   2628             args = args[1:]
   2629 

/usr/local/lib/python3.5/site-packages/numpy/core/numeric.py in asarray(a, dtype, order)
    499 
    500     """
--> 501     return array(a, dtype, copy=False, order=order)
    502 
    503 

ValueError: could not convert string to float: 'r'

We define a sine wave and check that the operation implemented by "op1" seems to be a derivative...

In [5]:
t=np.linspace(0,100,500)
sig=np.sin(2*pi*0.05*t)
plt.plot(t,sig, label="Initial signal")
plt.plot(t,5/(2*pi*0.05)*op1(sig), label="Filtered signal")
plt.legend()
Out[5]:
<matplotlib.legend.Legend at 0x7fdb1b34a0b8>

Composition of operations:

In [6]:
plt.stem(op1(op2(r)),'r')
_=plt.ylim([-1.2, 1.2])
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
<ipython-input-6-96c17cc23118> in <module>()
----> 1 plt.stem(op1(op2(r)),'r')
      2 _=plt.ylim([-1.2, 1.2])

/usr/local/lib/python3.5/site-packages/matplotlib/pyplot.py in stem(linefmt, markerfmt, basefmt, bottom, label, data, *args)
   2924         *args, linefmt=linefmt, markerfmt=markerfmt, basefmt=basefmt,
   2925         bottom=bottom, label=label, **({"data": data} if data is not
-> 2926         None else {}))
   2927 
   2928 

/usr/local/lib/python3.5/site-packages/matplotlib/__init__.py in inner(ax, data, *args, **kwargs)
   1808                         "the Matplotlib list!)" % (label_namer, func.__name__),
   1809                         RuntimeWarning, stacklevel=2)
-> 1810             return func(ax, *args, **kwargs)
   1811 
   1812         inner.__doc__ = _add_data_doc(inner.__doc__,

/usr/local/lib/python3.5/site-packages/matplotlib/axes/_axes.py in stem(self, linefmt, markerfmt, basefmt, bottom, label, *args)
   2625         else:
   2626             x = y
-> 2627             y = np.asarray(args[0], dtype=float)
   2628             args = args[1:]
   2629 

/usr/local/lib/python3.5/site-packages/numpy/core/numeric.py in asarray(a, dtype, order)
    499 
    500     """
--> 501     return array(a, dtype, copy=False, order=order)
    502 
    503 

ValueError: could not convert string to float: 'r'
In [7]:
def op3(signal):
    transformed_signal=np.zeros(np.size(signal))
    for t in np.arange(np.size(signal)):
        transformed_signal[t]= 0.7*transformed_signal[t-1]+signal[t]
    return transformed_signal

plt.stem(op3(r),'r')
plt.title("Filtering of rectangular signal with op3")
_=plt.ylim([-0.2, 3.2])
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
<ipython-input-7-3cf0c745df68> in <module>()
      5     return transformed_signal
      6 
----> 7 plt.stem(op3(r),'r')
      8 plt.title("Filtering of rectangular signal with op3")
      9 _=plt.ylim([-0.2, 3.2])

/usr/local/lib/python3.5/site-packages/matplotlib/pyplot.py in stem(linefmt, markerfmt, basefmt, bottom, label, data, *args)
   2924         *args, linefmt=linefmt, markerfmt=markerfmt, basefmt=basefmt,
   2925         bottom=bottom, label=label, **({"data": data} if data is not
-> 2926         None else {}))
   2927 
   2928 

/usr/local/lib/python3.5/site-packages/matplotlib/__init__.py in inner(ax, data, *args, **kwargs)
   1808                         "the Matplotlib list!)" % (label_namer, func.__name__),
   1809                         RuntimeWarning, stacklevel=2)
-> 1810             return func(ax, *args, **kwargs)
   1811 
   1812         inner.__doc__ = _add_data_doc(inner.__doc__,

/usr/local/lib/python3.5/site-packages/matplotlib/axes/_axes.py in stem(self, linefmt, markerfmt, basefmt, bottom, label, *args)
   2625         else:
   2626             x = y
-> 2627             y = np.asarray(args[0], dtype=float)
   2628             args = args[1:]
   2629 

/usr/local/lib/python3.5/site-packages/numpy/core/numeric.py in asarray(a, dtype, order)
    499 
    500     """
--> 501     return array(a, dtype, copy=False, order=order)
    502 
    503 

ValueError: could not convert string to float: 'r'

1.1.1  A curiosity

In [8]:
def op4(signal):
    transformed_signal=np.zeros(np.size(signal))
    for t in np.arange(np.size(signal)):
        transformed_signal[t]= 1*transformed_signal[t-1]+signal[t]
    return transformed_signal

plt.stem(op4(r),'r')
plt.title("Filtering of rectangular signal with op4")
_=plt.ylim([-0.2, 5.6])
# And then..
plt.figure()
plt.stem(op1(op4(r)),'r')
plt.title("Filtering of rectangular signal with op1(op4)")
_=plt.ylim([-0.2, 1.2])
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
<ipython-input-8-46cc0d896a24> in <module>()
      5     return transformed_signal
      6 
----> 7 plt.stem(op4(r),'r')
      8 plt.title("Filtering of rectangular signal with op4")
      9 _=plt.ylim([-0.2, 5.6])

/usr/local/lib/python3.5/site-packages/matplotlib/pyplot.py in stem(linefmt, markerfmt, basefmt, bottom, label, data, *args)
   2924         *args, linefmt=linefmt, markerfmt=markerfmt, basefmt=basefmt,
   2925         bottom=bottom, label=label, **({"data": data} if data is not
-> 2926         None else {}))
   2927 
   2928 

/usr/local/lib/python3.5/site-packages/matplotlib/__init__.py in inner(ax, data, *args, **kwargs)
   1808                         "the Matplotlib list!)" % (label_namer, func.__name__),
   1809                         RuntimeWarning, stacklevel=2)
-> 1810             return func(ax, *args, **kwargs)
   1811 
   1812         inner.__doc__ = _add_data_doc(inner.__doc__,

/usr/local/lib/python3.5/site-packages/matplotlib/axes/_axes.py in stem(self, linefmt, markerfmt, basefmt, bottom, label, *args)
   2625         else:
   2626             x = y
-> 2627             y = np.asarray(args[0], dtype=float)
   2628             args = args[1:]
   2629 

/usr/local/lib/python3.5/site-packages/numpy/core/numeric.py in asarray(a, dtype, order)
    499 
    500     """
--> 501     return array(a, dtype, copy=False, order=order)
    502 
    503 

ValueError: could not convert string to float: 'r'

1.2  Filters

Definition A filter is a time-invariant linear system.

  • Time invariance means that if y(n) is the response associated with an input x(n), then y(nn0) is the response associated with the input x(nn0).
  • Linearity means that if y1(n) and y2(n) are the outputs associated with x1(n) and x2(n), then the output associated with a1x1(n)+a2x2(n) is a1y1(n)+a2y2(n) (superposition principle)

Exercise 1
Check whether the following systems are filters or not. - x(n)2x(n) - x(n)2x(n)+1 - x(n)2x(n)+x(n1) - x(n)x(n)2

1.2.1  Notion of impulse response

Definition 1
A Dirac impulse (or impulse for short) is defined by δ(n)={1 if n=00 elsewhere

Definition 2
The impulse response of a system is nothing but the output of the system excited by a Dirac impulse. It is often denoted h(h). δ(n)Systemh(n)
In [9]:
def dirac(n):
# dirac function
    return 1 if n==0 else 0
def dirac_vector(N):
    out = np.zeros(N)
    out[0]=1
    return out
In [10]:
d=dirac_vector(20)
fig,ax=plt.subplots(2,2,sharex=True)

ax[0][0].stem(op1(d),  label="Filter 1")
ax[0][0].legend()
ax[0][1].stem(op2(d),  label="Filter 2")
ax[0][1].legend()
ax[1][0].stem(op3(d), label="Filter 3")
ax[1][0].legend()
ax[1][1].stem(op4(d), label="Filter 4")
ax[1][1].legend()
plt.suptitle("Impulse responses")
Out[10]:
Text(0.5, 0.98, 'Impulse responses')

1.2.2  Curiosity (continued)

The impulse response of op4(op1) is given by

In [11]:
h=op4(op1(dirac_vector(20)))
plt.stem(h, label="Filter 4(1)")
_=plt.axis([-5, 20, 0, 1.2])

This is nothing but a Dirac impulse! We already observed that op4(op1(signal))=signal; that is the filter is an identity transformation. In other words, op4 acts as the "inverse" of op1. Finally, we note that the impulse response of the indentity filter is a Dirac impulse.