```
import numpy as np
import scipy as sp
import scipy.signal
import matplotlib
import matplotlib.pyplot as plt
%matplotlib inline
```

Shannon's sampling theorem tells us the signal $x(t)$ can be exactly and uniquely reconstructed for all time from its samples $x(nT_S)$ by bandlimited interpolation:

\begin{equation}
\hat x(t) = \sum_{n=-\infty}^{+\infty} x(nT_S)h_S(t-nT_S) = (x \ast h_S)(t) \equiv x(t)
\end{equation}

where
$$
h_S(t) = \text{sinc}(tf_S)
$$


```
Ts = 1
Fs = 1/Ts

res = 10 # resolution parameter to fake continuous time
sc_zc = 10 # number of uni-directional zero crossing taken into account

t = np.arange(-sc_zc*Ts,+sc_zc*Ts,Ts/res)
h_S = np.sinc(t*Fs)

fig, ax = plt.subplots(1, 1, figsize=(13,4))
ax.plot(t, h_S)

ax.spines['top'].set_visible(False)
ax.spines['right'].set_visible(False)
ax.spines['left'].set_position('zero')
ax.spines['bottom'].set_position('zero')

n = np.arange(-10,10,1)
ax.set_xticks(Ts * n)
labels = ["$%d T_S$" % y for y in n[0:]]
labels[10] = "0"
ax.set_xticklabels(labels, fontsize=12)
ax.grid()
ax.set_xlim([-7, 7]);

```

This function is the impulse response of the ideal LPF with cut off frequency set at $F_S/2$. The convolution can be interpreted as a superpositon of shifted and scaled $\text{sinc}$ functions.


```
Ts = 1
Fs = 1/Ts
res = 10 # resolution parameter to fake continuous time
sc_zc = 10 # number of uni-directional zero crossing taken into account

t = np.arange(-sc_zc*Ts,+sc_zc*Ts,Ts/res)
h_S = np.sinc(t*Fs)

# my discrete signal
x = np.array([0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0]) 
# x = np.sin(np.arange(10)*2*np.pi/10)
# x = np.array([0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0]) 

# interpolation
sampled_t = np.arange(0,len(x)*Ts,Ts)
continuous_t = np.arange(0,(len(x)-1)*Ts + Ts/res,Ts/res)
x_interp = np.zeros((len(continuous_t),))
x_interp[0::res] = x

#convolve
x_hat = np.convolve(x_interp, h_S)
x_hat = x_hat[(len(h_S)/2):-len(h_S)/2+1]

# plot
fig, axes = plt.subplots(1, 2, figsize=(16,6))
axes[0].stem(sampled_t, x)
axes[1].plot(continuous_t, x_hat)

for ax in axes:
    ax.spines['top'].set_visible(False)
    ax.spines['right'].set_visible(False)
    ax.spines['left'].set_position('zero')
    ax.spines['bottom'].set_position('zero')

    n = np.arange(0,len(x),1)
    ax.set_xticks(Ts * n)
    labels = ["$%d T_S$" % y for y in n[0:]]
    labels[0] = "0"
    ax.set_xticklabels(labels, fontsize=12)
    ax.grid()
    ax.set_xlim([0, continuous_t[-1]+Ts]);
    ax.set_ylim([np.min((0,np.min((np.min(x),np.min(x_hat)))))-0.1,np.max((np.max(x),np.max(x_hat)))+0.1])
```

155df34082123a3e48c9efb9c5cd3a783d3b8df9
ipynb
Jupyter Notebook
audio/BandlimitedInterpolation.ipynb
brunodigiorgi/ipn-notes
c8840a45989f25442c1d800ef8acdf8c630cdafc
CC-BY-3.0
2018-03-07T13:46:17.000Z
2018-03-07T13:46:17.000Z
audio/BandlimitedInterpolation.ipynb
brunodigiorgi/ipn-notes
c8840a45989f25442c1d800ef8acdf8c630cdafc
CC-BY-3.0
audio/BandlimitedInterpolation.ipynb
brunodigiorgi/ipn-notes
c8840a45989f25442c1d800ef8acdf8c630cdafc
CC-BY-3.0
Qwen/Qwen-72B
1. YES
2. YES