În acest laborator vom încerca să ne familiarizăm cu limbajul de programare Python și vom folosi câteva elemente pe care le vom utiliza in cadrul laboratoarelor de procesarea semnalelor. Majoritatea tehnicilor de procesare de semnal pot fi executate ca operații pe vectori și matrici, deci Python este o unealtă foarte folositoare pentru a face aceste operații.
Laboratoarele se pot face utilizând Google Colab (care ne oferă un notebook Python în browser în care putem rula cod fără a ne mai preocupa de setup), sau Pycharm (care este un IDE dedicat pentru Python).
Google Colab
Download Pycharm - folosiți versiunea Community care este gratuită
1. Obișnuiți-vă cu mediul de lucru: spațiul de lucru (workspace), editarea scriptului, consola.
scrieți a = 2
scrieți b = 3
scrieți print(a+b)
scrieți c=a+b
scrieți print(c )
scrieți print(a*b)
scrieți print(a**b)
Pentru procesarea semnalelor ne vom folosi de bibliotecile scipy și numpy. Aceastea ne vor ajuta să aplicăm o mulțime de operații matematice vectoriale. Putem defini elementele pe care le folosim cel mai des, precum vectorii și matricele, folosindu-ne de aceaste biblioteci.
Va trebui să importați bibliotecile de care aveți nevoie pentru a le folosi
import numpy as np
import scipy as sp
2. Vectori
Semnalele pot fi reprezentate ca secvențe de valori, unde în Python se face, de obicei, prin vectori sau matrice. Să începem cu vectorii.
Pentru a genera un vector de valori date, putem scrie pur și simplu ceva de genul:
vec1 = [1, 2, 3, 4] # Notați parantezele drepte '[' și ']' necesare pentru a include valori.
sau putem folosi functia 'array' din numpy: vec2 = np.array([1, 2, 3, 4])
Creați un vector cu 7 elemente de unu (folosind funcția 'np.ones'), iar apoi multiplicați-l cu o constantă. Afișați rezultatul.
Creați un vector de 5 valori aleatoare folosind modulul 'np.random'.
Indexarea în Python pornește de la 0, deci puteți selecta primul element din vector folosind comanda vec1[0].
De asemenea, puteți indexa părți din vector: vec1[1:3] pentru a selecta un vector format din al doilea și al treilea element din vec1.
vec1[-2:] selectează ultimele 2 elemente din vec1.
Pentru a beneficia de performanță și de operațiile matematice din $numpy$, vom încerca să folosim mereu numpy arrays.
3. Matrice
În Python, putem implementa o matrice ca o listă de liste. Putem trata fiecare element ca o linie a matricei.
Spre exemplu, X = [[1, 2], [4, 5], [3, 6]] va reprezenta o matrice de 3 pe 2 (3 linii și 2 coloane). Prima linie poate fi selectată ca X[0], iar primul element de pe prima linie poate fi selectat ca X[0][0].
În continuare ne vom folosi de numpy.array pentru a crea și a manipula matrice(2D array) sau putem folosi o clasă deprecated, numpy.matrix.
4. Transpusa
Transpusa unei matrice poate fi obținută prin aplicarea funcției transpose pe o matrice: 'numpy.transpose'.
Transpuneți matricea pe care ați creat-o mai devreme.
Creați un vector coloană cu elemente de unu, folosind funcția 'np.ones' și modificând parametrul shape cu un număr de elemente mai mare decât unu pentru prima dimensiune. Printați acest vector.
Acum transpuneți acest vector și printați-l din nou. Care este diferența dintre afișări?
Când folosiți vectori (adunare, înmulțire, etc.) trebuie să aveți grijă să folosiți forma potrivită (fie coloană, fie linie).
5. Alte modalități pentru a crea vectori și matrice
Pentru a crea o secvență continuă (de exemplu de la 1 la 5), putem folosi range și list comprehension, ca în exemplul v = [x for x in range(1, 10)].
Creați o secvență de 10 elemente, pornind de la 5.
Putem face incrementul diferit de 1, folosind ceva de genul range(1, 10, 3). Încercați și vedeți rezultatul. De asemenea, puteți folosi funcția 'numpy.linspace' pentru a crea puncte egal distanțate.
6. Șiruri de caractere și afișaj
Putem crea într-un mod ușor șiruri de caractere folosind s = 'Hello'.
Creați o variabilă care să conțină șirul de caractere 'Signal processing'.
Folosiți funcția 'print' pentru a afișa acest șir.
Afișați un șir care conține 'Lab of ', concatenat cu șirul precedent.
Acum folosiți fstring pentru a afișa un șir de caractere, urmat de o cifră aleasă de voi.
7. Grafice
În laboratoarele care vor urma va trebui să generăm grafice cu ajutorul cărora vom vizualiza datele noastre.
Vom folosi matplotlib pentru a genera grafice așa că importați această bibliotecă
import matplotlib.pyplot as plt
Folosiți funcția 'sin' pentru a genera o sinusoidă de frecvență 1 Hz peste 1 secundă (astfel încât ar trebui să obțineți o perioadă completă). Pentru asta trebuie să generați intervalul de timp peste [0 … 1] în pași foarte mici (e.g. 100 de puncte) și apoi să apelați funcția sin(2*pi*f*t) peste această secvență (unde f este frecvența, t este intervalul de timp, iar pi este numărul 3.1415…) pentru a obține sinusoida ca o secvență. Observație: Folosiți numpy.pi pentru variabila pi !
Plotați sinusoida pe care ați făcut-o mai devreme folosind funcția 'plt.plot'.
Schimbați culoarea liniei sinusoidei.
Schimbați tipul liniei sinusoidei.
Creați altă sinusoidă cu o frecvență diferită (e.g. 2 Hz).
Afișați ambele sinusoide pe același grafic (prin apelarea succesivă a funcției plot pentru cele două semnale).
Încercați să adăugați denumiri axelor X și Y, de asemenea să puneți și titlu figurii.
Adăugați o legendă pentru a clarifica care sunt semnalele.
Aici este un exemplu cum ar trebui să arate:
8. Câteva exerciții simple de procesare de semnal
Generați două sinusoide, ca mai devreme, cu diferite frecvențe, dar care acoperă același interval (e.g. 1 Hz și 2 Hz pe o perioadă de 1 secundă).
Generați un semnal care conține suma celor două sinusoide.
Afișați aceste trei semnale și verificați diferențele.
Hint: folosiți 'figure', înaintea fiecărei comenzi 'plot' pentru a genera trei grafice diferite sau afișați-le pe toate în același grafic (sau în două grafice, unul pentru sinusoida inițială și altul pentru sinusoida rezultată).
Ar trebui să obțineți ceva de genul:
9. O aplicație ușoară
În acestă arhivă data.zip aveți trei imagini, reprezentate ca matrice tridimensionale (o matrice per culoare - R, G, B).
Matricile reprezintă o imagine Img_initial care a fost distorsionată prin adăugarea unui zgomot (matricele R1 și R2), prin formula:
IR = Img_initial * 0.3 + R1 * 0.3 + R2 * 0.3
Task-ul vostru este să încercați să reconstruiți matricea originală a imaginii și să o afișați. Pentru asta trebuie să faceți pașii următori:
dezarhivați imaginile și încărcați-le în mediul vostru de lucru
încărcați matricele (puteți folosi funția 'imread' din modulul 'matplotlib.image')
afișați cele trei imagini date (matrice) pentru a le vizualiza, folosind funcția 'imshow' din 'matplotlib.pyplot', e.g. 'plt.imshow(R1)'.
scădeți cumva matricele de zgomot
afișați imaginea după ce ați eliminat zgomotul
Rețineți că o matrice imagine conține numai valori de la 0 la 255.
10. Row-major
În numpy se foloseste convenția de row-major, deci este indicat să se parcurgă întâi dimensiunea cea mai din dreapta (în cazul matricelor, dimensiunea liniilor). De asemenea, mereu când este posibil, este indicat să se folosească operații vectoriale.
În mod default operatorul '*' va face înmulțire element cu element.
Pentru înmulțire de matrici trebuie să folosim funcția 'numpy.dot' sau operatorul '@'.
import numpy as np
import time
N = 1000
A = np.random.rand(N, N)
B = np.random.rand(N, N)
C = np.zeros((N, N))
time1 = time.time()
for i in range(N):
for j in range(N):
C[i, j] = A[i, j] * B[i, j]
time_row = time.time() - time1
time2 = time.time()
for j in range(N):
for i in range(N):
C[i, j] = A[i, j] * B[i, j]
time_column = time.time() - time2
time3 = time.time()
C = A * B
time_matrix_operation = time.time() - time3
print(f'Timp row-major: {time_row} s')
print(f'Timp column-major: {time_column} s')
print(f'Timp matrix operation: {time_matrix_operation} s')