S20220020307 DSP 3
S20220020307 DSP 3
Question Number 1
PROGRAM
1 import numpy as np
2 import matplotlib.pyplot as plt
3
4 def dit_fft(x):
5 N = len(x)
6 if N <= 1:
7 return x
8 even = dit_fft(x[::2])
9 odd = dit_fft(x[1::2])
10 T = [np.exp(-2j * np.pi * k / N) * odd[k] for k in range(N // 2)]
11 return [even[k] + T[k] for k in range(N // 2)] + [even[k] - T[k] for k in range(N // 2)]
12
13 def compute_z(L, a, omega1, omega2):
14 n = np.arange(L)
15 x = a * (np.sin(omega1 * n) - 0.5 * np.cos(omega2 * n))
16 z = np.concatenate([x[:L//2], -x[L//2:]])
17 return z
18
19 L = 256
20 a = 1
21 omega1 = 2 * np.pi * 10 / L
22 omega2 = 2 * np.pi * 20 / L
23 z = compute_z(L, a, omega1, omega2)
24
25 z_fft = dit_fft(z)
26 z_magnitude = np.abs(z_fft)
27
28
29 frequencies = np.fft.fftfreq(L, d=1/L)
30 plt.figure(figsize=(10, 6))
31 plt.stem(frequencies[:L//2], z_magnitude[:L//2], basefmt=" ")
32 plt.title("Spectral Content of z(n)")
33 plt.xlabel("Frequency (Hz)")
34 plt.ylabel("Magnitude")
35 plt.grid()
36 plt.show()
37
38 def generate_y(L, a, b, omega0, alpha, sigma2):
39 n = np.arange(L)
40 w = np.random.normal(0, np.sqrt(sigma2), L)
41 y = a * np.cos(omega0 * n) + b * np.cos(alpha * omega0 * n) + w
42 return y
43
44 a, b = 1, 0.5
45 omega0 = 2 * np.pi * 10 / L
46 alpha_values = [1.05, 1.1, 1.3]
47 noise_powers = [1, 5, 10, 50, 100]
48
49 for alpha in alpha_values:
50 plt.figure(figsize=(12, 8))
51 for sigma2 in noise_powers:
52 y = generate_y(L, a, b, omega0, alpha, sigma2)
53 y_fft = np.fft.fft(y)
54 y_magnitude = np.abs(y_fft)
55 plt.plot(frequencies[:L//2], y_magnitude[:L//2], label=f"Noise power: {sigma2}")
56 plt.title(f"Spectral Components for alpha={alpha}")
57 plt.xlabel("Frequency (Hz)")
58 plt.ylabel("Magnitude")
59 plt.legend()
60 plt.grid()
61 plt.show()
RESULTS
INTERPRETATION
These results demonstrate the interplay between signal structure, noise, and spectral resolution, offering valuable insights for practical spectral analysis
tasks.
THEORETICAL SOLUTION
Question Number 2
PROGRAM
1 import numpy as np
2 from scipy.signal import butter, freqz, bilinear, dimpulse
3 import matplotlib.pyplot as plt
4
5 f_p = 8000 # Passband frequency in Hz
6 f_s = 16000 # Stopband frequency in Hz
7 A_p = 1 # Passband ripple in dB
8 A_s = 40 # Stopband attenuation in dB
9 f_samp = 54000 # Sampling frequency in Hz
10
11 omega_p = 2 * np.pi * f_p
12 omega_s = 2 * np.pi * f_s
13
14 N = np.ceil(
15 np.log10((10**(A_s / 10) - 1) / (10**(A_p / 10) - 1)) / (2 * np.log10(omega_s / omega_p))
16 ).astype(int)
17 omega_c = omega_p * (10**(A_p / 10) - 1) ** (-1 / (2 * N))
18
19 print(f"Filter Order (N): {N}")
20 print(f"Cutoff Frequency (ωc): {omega_c / (2 * np.pi):.2f} Hz")
21
22
23 b, a = butter(N, omega_c, btype='low', analog=True)
24 print(f"Analog Filter Coefficients (b): {b}")
25 print(f"Analog Filter Coefficients (a): {a}")
26
27 w, h = freqz(b, a, worN=8000, fs=2 * np.pi)
28 plt.figure(figsize=(10, 6))
29 plt.plot(w / (2 * np.pi), 20 * np.log10(np.abs(h)))
30 plt.title("Frequency Response of Analog Butterworth Filter")
31 plt.xlabel("Frequency (Hz)")
32 plt.ylabel("Magnitude (dB)")
33 plt.grid()
34 plt.show()
35
36 T = 1 / f_samp
37 b_digital, a_digital = bilinear(b, a, fs=f_samp) # bilinear works for digital conversion
38
39 w_digital, h_digital = freqz(b_digital, a_digital, fs=f_samp)
40 plt.figure(figsize=(10, 6))
41 plt.plot(w_digital, 20 * np.log10(np.abs(h_digital)))
42 plt.title("Digital Filter using Impulse Invariance")
43 plt.xlabel("Frequency (Hz)")
44 plt.ylabel("Magnitude (dB)")
45 plt.grid()
46 plt.show()
47 b_bilinear, a_bilinear = bilinear(b, a, fs=f_samp)
48 w_bilinear, h_bilinear = freqz(b_bilinear, a_bilinear, fs=f_samp)
49
50 plt.figure(figsize=(10, 6))
51 plt.plot(w_bilinear, 20 * np.log10(np.abs(h_bilinear)))
52 plt.title("Digital Filter using Bilinear Transformation")
53 plt.xlabel("Frequency (Hz)")
54 plt.ylabel("Magnitude (dB)")
55 plt.grid()
56 plt.show()
57
58
59 plt.figure(figsize=(12, 8))
60 plt.plot(w_digital, 20 * np.log10(np.abs(h_digital)), label="Impulse Invariance")
61 plt.plot(w_bilinear, 20 * np.log10(np.abs(h_bilinear)), label="Bilinear Transformation")
62 plt.title("Comparison of Digital Filter Responses")
63 plt.xlabel("Frequency (Hz)")
64 plt.ylabel("Magnitude (dB)")
65 plt.legend()
66 plt.grid()
67 plt.show()
68
RESULTS
1. Filter Order (N): NNN calculated using manual and Python-built functions should match closely.
2. Cutoff Frequency (Ωc\Omega_cΩc): Frequency that defines the filter's edge; it will match theoretical values.
3. Analog Frequency Response: Displays the Butterworth filter response.
4. Impulse Invariance vs. Bilinear Transformation:
Impulse Invariance: May exhibit aliasing.
Bilinear Transformation: Warps frequency but avoids aliasing, preferred for digital implementation.
THEORETICAL SOLUTION
Question Number 3
PROGRAM
1 import numpy as np
2 import matplotlib.pyplot as plt
3 from scipy.signal import firwin, lfilter
4
5 omega_0 = np.pi / 6 # Frequency of interest (rad/sample)
6 stopband_freq = 2 * omega_0 # Frequency to stop
7 fs = 1 # Sampling frequency (normalized)
8 M = 51 # Filter length (adjust for different results)
9
10 h = firwin(M, stopband_freq / np.pi, window='hamming') # Normalize stopband_freq by π
11 print(f"FIR Filter Coefficients (h): {h}")
12
13 N_fft = 1024 # Number of FFT points
14 h_response = np.fft.fft(h, N_fft) # FFT with zero-padding
15 w = np.linspace(0, np.pi, N_fft) # Frequency axis (0 to π)
16
17 plt.figure(figsize=(10, 6))
18 plt.plot(w, 20 * np.log10(np.abs(h_response)), label='Hamming Window')
19 plt.title("Frequency Response of FIR Filter")
20 plt.xlabel("Frequency (rad/sample)")
21 plt.ylabel("Magnitude (dB)")
22 plt.grid()
23 plt.legend()
24 plt.show()
25
26 n = np.arange(0, 200) # Sample indices
27 x = np.sin(omega_0 * n) + 2 * np.cos(2 * omega_0 * n) + 3 * np.sin(3 * omega_0 * n)
28
29 y = lfilter(h, 1, x)
30
31 plt.figure(figsize=(12, 6))
32 plt.subplot(2, 1, 1)
33 plt.plot(n, x, label='Original Signal')
34 plt.title("Original Signal")
35 plt.xlabel("Sample Index")
36 plt.ylabel("Amplitude")
37 plt.grid()
38 plt.legend()
39
40 plt.subplot(2, 1, 2)
41 plt.plot(n, y, label='Filtered Signal', color='orange')
42 plt.title("Filtered Signal (2ω₀ Attenuated)")
43 plt.xlabel("Sample Index")
44 plt.ylabel("Amplitude")
45 plt.grid()
46 plt.legend()
47 plt.tight_layout()
48 plt.show()
49
50 filter_lengths = [31, 51, 101]
51 plt.figure(figsize=(12, 6))
52 for M in filter_lengths:
53 h_test = firwin(M, stopband_freq / np.pi, window='hamming')
54 h_response_test = np.fft.fft(h_test, N_fft)
55 plt.plot(w, 20 * np.log10(np.abs(h_response_test)), label=f"M = {M}")
56
57 plt.title("Effect of Filter Length (M) on Frequency Response")
58 plt.xlabel("Frequency (rad/sample)")
59 plt.ylabel("Magnitude (dB)")
60 plt.grid()
61 plt.legend()
62 plt.show()
63
64
RESULTS
INTERPRETATION
1. Filter Response:
The frequency response plot shows attenuation around 2ω02\omega_02ω0, demonstrating the effectiveness of the FIR filter.
2. Impact on Signal:
The filtered signal's spectrum shows significant reduction in amplitude at 2ω02\omega_02ω0, confirming that the FIR filter successfully
attenuates this frequency component.
3. Impact of MMM:
Increasing MMM sharpens the transition band and improves stopband attenuation, but the computational cost increases.
THEORETICAL SOLUTION
Saakshi P Aayasya
S20220020307