UE731 Travaux pratiques signal - correction

by Joseph Razik, last modified on 2024-10-03
ue731_tp
In [1]:
%pylab inline
%pylab is deprecated, use %matplotlib inline and import the required libraries.
Populating the interactive namespace from numpy and matplotlib

Partie 2

Définissez la fonction delta(n) (δ(n)) qui retourne 1 pour n=0, et 0 sinon.

In [2]:
def delta(n):
    # ici on utilise le fait qu'un booléen peut être converti en entier (True -> 1, False -> 0)
    # ce qui permettra d'accepter directement une comparaison avec un np.array 
    return n == 0

Afficher cette fonction sur l'intervalle [−20;20]×[−0.1;1.1] en utilisant la fonction stem.

In [3]:
X = np.arange(-20, 21)  # on définit les abscisses des points
stem(X, delta(X))
# on définit les plages de valeurs d'affichage du graphique
ylim(-0.1, 1.1)
xlim(-20, 20)
Out[3]:
(-20.0, 20.0)

Définir la fonction unit(n) qui retourne 0 pour n<0 et 1 sinon.

In [4]:
def unit(n):
    # idem pour cette fonction, on utilise le type booléen
    return n > 0

Afficher cette fonction sur l'intervalle [−20;20]×[−0.1;1.1] en utilisant la fonction stem.

In [5]:
stem(X, unit(X))
ylim(-0.1, 1.1)
xlim(-20, 20)
Out[5]:
(-20.0, 20.0)

Tester et afficher sur [−20;20] les fonctions δ(n), δ(−n), δ(n−5) et δ(n+5) en 4 sous-figures avec en titre la fonction.

In [6]:
figure(figsize=(6,14))  # on définit la taille globale de la figure (en cm)
subplot(4, 1, 1)  # on définit le partitionnement et la position de la sous-figure
stem(X, delta(X))
ylim(-0.1, 1.1)
xlim(-20, 20)
title("$\\delta(n)$")

subplot(4, 1, 2)
stem(X, delta(-X))
ylim(-0.1, 1.1)
xlim(-20, 20)
title("$\\delta(-n)$")

subplot(4, 1, 3)
stem(X, delta(X - 5))
ylim(-0.1, 1.1)
xlim(-20, 20)
title("$\\delta(n-5)$")

subplot(4, 1, 4)
stem(X, delta(X + 5))
ylim(-0.1, 1.1)
xlim(-20, 20)
title("$\\delta(n+5)$");

Afficher sur [−20;20] les fonctions $α^n×unit(n)$ pour les valeurs de α 0.95, 0.9, 0.6.

In [7]:
figure()
ylim(-0.1, 1.1)
xlim(-20, 20)
stem(X, (0.95**X) * unit(X), 'b')
stem(X, (0.9**X) * unit(X), 'r')
stem(X, (0.6**X) * unit(X), 'g')
Out[7]:
<StemContainer object of 3 artists>

Partie 3

Définissez le tableau Numpy array C, des valeurs de la fonction $cos(2πx)$ sur 100 points répartis uniformément entre -1 et 1.

In [8]:
X = linspace(-1, 1, 100)
C = np.cos(2*pi*X)  # la fonction cos de numpy permet de simplifier l'écriture et vectoriser le calcul 

Affichez sur [−1;1] la fonction $cos(2πx)$ avec 10 puis 100 points de résolution, en utilisant C.

In [9]:
figure()
xlim(-1.1, 1.1)
ylim(-1.1, 1.1)
stem(X[::10], C[::10])  # un array peut se parcourir comme une liste, ici on indique un pas de 10

figure()
xlim(-1.1, 1.1)
ylim(-1.1, 1.1)
stem(X, C)
Out[9]:
<StemContainer object of 3 artists>

Affichez sur [−1;1] la fonction $0.5×cos(2πx+1)$ avec 10 puis 100 points de résolution.

In [10]:
D = 0.5*np.cos(2*pi*X + 1)
figure()
xlim(-1.1, 1.1)
ylim(-1.1, 1.1)
stem(X[::10], D[::10])

figure()
xlim(-1.1, 1.1)
ylim(-1.1, 1.1)
stem(X, D)
Out[10]:
<StemContainer object of 3 artists>

Définissez la matrice M de dimension 4x3, remplie uniquement de la valeur 2.

In [11]:
M = full((4, 3), 2)
M
Out[11]:
array([[2, 2, 2],
       [2, 2, 2],
       [2, 2, 2],
       [2, 2, 2]])

Extrayez la ligne 3, puis la colonne 3.

In [12]:
L3 = M[2, :]  # l'indice de la 3e ligne est 2 (commence à 0)
print(L3)
C3 = M[:, 2]
print(C3)
[2 2 2]
[2 2 2 2]

Modifiez M de telle sorte que la ligne 2 soit égale à la ligne 2 plus 3 fois la ligne 4. Puis la colonne 1 égale à la colonne 1 plus la moitié de la colonne 3.

In [13]:
# d'abord la modification sur la ligne
M[1, :] = M[1, :]  + 3*M[3, :] 
M
Out[13]:
array([[2, 2, 2],
       [8, 8, 8],
       [2, 2, 2],
       [2, 2, 2]])
In [14]:
# puis sur la colonne
M[:, 0] = M[:, 0] + 0.5*M[:, 2]
M
Out[14]:
array([[ 3,  2,  2],
       [12,  8,  8],
       [ 3,  2,  2],
       [ 3,  2,  2]])

Changez les caractéristiques de M pour qu'elle soit maintenant une matrice 6x2.

In [15]:
# les nouvelles dimensions sont compatibles (12 éléments)
M = M.reshape((6,2))
M
Out[15]:
array([[ 3,  2],
       [ 2, 12],
       [ 8,  8],
       [ 3,  2],
       [ 2,  3],
       [ 2,  2]])

Créez les matrices carré B et C 4x4 et de valeur respective 2 et 3. Les résultats de B+C, B*C et B@C correspondent-ils bien avec ce que vous pensiez ?

In [16]:
B = full((4,4), 2)
C = full((4,4), 3)
B, C
Out[16]:
(array([[2, 2, 2, 2],
        [2, 2, 2, 2],
        [2, 2, 2, 2],
        [2, 2, 2, 2]]),
 array([[3, 3, 3, 3],
        [3, 3, 3, 3],
        [3, 3, 3, 3],
        [3, 3, 3, 3]]))
In [17]:
B + C  # addition élément par élément, normal
Out[17]:
array([[5, 5, 5, 5],
       [5, 5, 5, 5],
       [5, 5, 5, 5],
       [5, 5, 5, 5]])
In [18]:
B * C  # attention, ici produit élément par élément
Out[18]:
array([[6, 6, 6, 6],
       [6, 6, 6, 6],
       [6, 6, 6, 6],
       [6, 6, 6, 6]])
In [19]:
B @ C  # vrai produit matriciel
Out[19]:
array([[24, 24, 24, 24],
       [24, 24, 24, 24],
       [24, 24, 24, 24],
       [24, 24, 24, 24]])

Créez une matrice 3x3 avec les valeurs de 0 à 8.

In [20]:
N = arange(9).reshape((3, 3))
N
Out[20]:
array([[0, 1, 2],
       [3, 4, 5],
       [6, 7, 8]])

Trouvez les indices des valeurs supérieures à 3 dans le tableau [1, 0, 2, 0, 0, 3, 4, 0, 5].

In [21]:
where(array([1, 0, 2, 0, 0, 3, 4, 0, 5]) > 3)
# donne les indices des positions sur une dimension, comme le vecteur en entrée 
Out[21]:
(array([6, 8]),)

Trouvez les indices des valeurs de M supérieures à 3.

In [22]:
where(M > 3)
# donne les indices mais sur deux dimensions: une liste des lignes, une liste des colonnes
Out[22]:
(array([1, 2, 2]), array([1, 0, 1]))

Modifiez la matrice M afin de mettre à -1 toutes les valeurs supérieures à 3.

In [23]:
print(M)
M[M > 3] = -1
M
[[ 3  2]
 [ 2 12]
 [ 8  8]
 [ 3  2]
 [ 2  3]
 [ 2  2]]
Out[23]:
array([[ 3,  2],
       [ 2, -1],
       [-1, -1],
       [ 3,  2],
       [ 2,  3],
       [ 2,  2]])

Partie 4

Définissez la fonction w_k qui aux paramètres k et N retourne le k-ième vecteur $w_k=[e^{2iπkn/N}]_{n∈[0,N[}$ de la base $\mathbb{C}^N$. La valeur par défaut de $N$ sera de 64.

In [24]:
def w_k(k, N=64):
    return exp(2*1j*pi*k*arange(0,N)/(N*1.0))

Définissez la fonction affiche_w_k, qui pour un k donné affiche dans une sous-figure les parties réelles du vecteur $w_k$ et dans une autre sous-figure les parties imaginaires du vecteur $w_k$. Les signaux étant discrets, utilisez la fonction stem à la place de la fonction plot.

In [25]:
def afficher_w_k(k):
    figure(figsize=(12,6))
    subplot(121)
    stem(arange(0, 64), real(w_k(k)))
    ylim(-1.1, 1.1)
    title("partie réelle de w_" + str(k))
    subplot(122)
    stem(arange(0, 64), imag(w_k(k)))
    title("partie imaginaire de w_" + str(k))
    ylim(-1.1, 1.1)
In [26]:
afficher_w_k(0)

Afficher en utilisant la fonction précédente les vecteurs $w_k$ et $w_{N−k}$ sur la base $\mathbb{C}^{64}$ pour les valeurs suivantes de $k$ : 0, 1, 2, 3, 4, 16, 20, 30, 31 et 32. Utilisez la fonction map pour faire ces affichages d'un coup. (Remarque: map retourne un générateur, il faut donc parcourir ce générateur pour exécuter les affichages. Pour cela, convertissez le simplement en liste : list(map(...))).

In [27]:
list(map(afficher_w_k, array([[k, 64-k] for k in [0, 1, 2, 3, 4, 16, 20, 30, 31, 32]]).flatten()));

Partie 5

Définissez la fonction scalaire(x, k) qui retourne pour un k fixé le produit scalaire entre un vecteur $x=x[n]$ et le vecteur $w_k$. Le résultat attendu est un nombre, réel ou complexe, mais pas un vecteur.

In [28]:
def scalaire(x, k):
    return vdot(x, w_k(k))

Définissez la fonction decompose(x) qui retourne un vecteur formé des produits scalaires du signal $x=x[n]$ sur toute la base des $w_k$. Le premier élément sera $<x|w_0>$, le deuxième sera $<x|w_1>$ etc.

In [29]:
def decompose(x):
    return array([scalaire(x, k) for k in range(64)]) 
In [30]:
decompose(w_k(1))
Out[30]:
array([-2.88657986e-15-8.46545056e-16j,  6.40000000e+01+0.00000000e+00j,
       -3.66220291e-15+3.91696172e-16j, -4.32122697e-15+3.12586753e-16j,
       -4.41798457e-15-3.71714330e-15j,  2.76435496e-15-1.36103843e-15j,
        2.94521218e-15-2.89473809e-17j, -3.10862447e-15-8.88178420e-16j,
        6.11342887e-15+8.09035252e-15j, -1.50990331e-14+3.10862447e-15j,
       -9.68323067e-15+1.60610104e-16j, -8.52012035e-15+4.11429400e-15j,
       -9.79381570e-16+7.53723902e-15j, -6.67277742e-15-1.78983005e-14j,
       -7.48169098e-15+2.19263261e-14j,  1.49518309e-14+2.42681310e-14j,
        2.07326833e-14+2.59519507e-14j, -9.90244977e-15-7.32192688e-17j,
       -1.31820469e-15+2.65760901e-15j, -1.10494709e-14-1.15066269e-14j,
        7.74209396e-15-2.96904526e-16j,  1.55865164e-14-6.03856189e-15j,
       -6.25852536e-15+8.26555608e-15j, -2.57571742e-14-8.88178420e-16j,
       -1.04744248e-14+3.67485415e-15j, -3.06421555e-14-1.86517468e-14j,
        1.92388707e-14-1.07641092e-14j, -4.64459898e-15+1.60740063e-14j,
        1.19301822e-14-2.87403215e-15j, -1.23830996e-14+6.78862422e-15j,
       -4.88532842e-15+2.33847998e-14j,  5.32907052e-15+3.80670281e-14j,
       -4.68316560e-15-1.49601182e-14j,  0.00000000e+00+1.24235300e-14j,
        3.07343730e-15+1.99106909e-14j,  3.69561750e-14-1.42848333e-14j,
       -3.46935469e-14+3.02042613e-14j,  1.38334459e-13+2.42981190e-14j,
        2.68620520e-14+9.17283650e-15j,  5.77315973e-15+1.24344979e-14j,
        1.52147905e-14+3.36840712e-14j,  5.01820807e-14-2.66453526e-15j,
       -1.85927698e-14+5.69602600e-14j,  2.78975175e-14-1.70481468e-14j,
        1.05658059e-14+1.77532247e-14j,  1.07539249e-14+4.91226320e-14j,
        9.33275404e-14-4.93618440e-14j,  5.04313914e-15-1.67812183e-14j,
       -6.85160110e-14+9.59127027e-14j, -6.58631343e-14+6.03757266e-14j,
        5.80242375e-14-2.64773917e-15j, -3.65034358e-14-4.14731733e-14j,
       -2.91879825e-16-1.93564107e-14j, -1.50510177e-14+2.44523591e-14j,
       -1.76578365e-14+1.43879570e-13j, -3.90798505e-14+1.77635684e-15j,
       -1.93328762e-14-9.63042210e-14j,  1.15463195e-13+3.99680289e-14j,
        2.47614334e-14+8.13296514e-14j,  1.26644721e-13-1.43729488e-14j,
        4.44677789e-14+1.41991010e-13j,  1.13344347e-13-1.37581556e-13j,
        1.23890923e-13+8.13042578e-14j, -6.39488462e-14-3.38129722e-14j])

Définissez la fonction affiche_decompose(x) qui affiche dans quatre sous-figures le module, la phase, la partie réelle et la partie imaginaire du vecteur égale à la décomposition du vecteur $x$. Affichez la décomposition pour le vecteur $cos(\frac{2\pi}{4}n)$ sur cette base $\mathbb{C}^{64}$.

In [31]:
def affiche_decompose(Z):
    figure(figsize=(8, 8))
    subplot(2, 2, 1)
    stem(abs(Z))
    title("module")
    subplot(2, 2, 2)
    # stem(angle(Z))
    Z[abs(Z) < 10**(-10)] = 0
    stem(angle(Z))
    title("phase")
    ylim(-pi, pi)
    subplot(2, 2, 3)
    stem(real(Z))
    title("partie réelle")
    subplot(2, 2, 4)
    stem(imag(Z))
    title("partie imaginaire")
In [32]:
X = cos(2*pi/4*arange(64))                      
Y = decompose(X)
affiche_decompose(Y)

Écrivez le code permettant de d'indiquer quels sont les indices et les valeurs à ces indices pour lesquels les contributions en module sont non-nulles ?

In [33]:
# attention aux comparaisons à 0 quand on manipule des floats
where(abs(Y) > 10**(-10))
Out[33]:
(array([16, 48]),)

Quels sont ces indices et valeurs pour le vecteur défini par $cos(\frac{2π}{4}n+π/4)$.

In [34]:
X2 = cos(2*pi/4*arange(64) + pi/4)
Y2 = decompose(X2)
affiche_decompose(Y2)
In [35]:
where(abs(Y2) > 10**(-10))
Out[35]:
(array([16, 48]),)

Et pour le vecteur $cos(\frac{2π}{15}n)$. Que constatez-vous ?

In [36]:
X3 = cos(2*pi/15*arange(64))
Y3 = decompose(X3)
affiche_decompose(Y3)