Skip to content

Commit f5cc08f

Browse files
author
Victor O. Costa
committed
Implement OS convolution and upload bibliography
1 parent af77c7e commit f5cc08f

File tree

4 files changed

+73
-29
lines changed

4 files changed

+73
-29
lines changed

apply_filter.py

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,22 @@
11
#!python3
2+
# Test script for the overlap_save class
23

3-
import overlap_save
4+
from overlap_save import overlap_save
5+
6+
# Declare the OS
7+
os = overlap_save()
8+
9+
# Define sequence x and filter impulse response h
10+
x = [3,-1,0,1,3,2,0,1,2,1]
11+
h = [1,1,1]
12+
13+
# Set overlap-save signal and filter to be applied
14+
os.set_signals(x, h)
15+
16+
# Define overlap-save block size
17+
os.set_block_size(5)
18+
19+
# Compute convolution
20+
conv = os.overlap_save_convolution()
21+
22+
print(conv)

overlap_save.py

Lines changed: 53 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
#!python3
2+
# Victor O. Costa (nov, 2019)
23

34
import numpy as np
5+
import collections
46

57
class overlap_save:
68
""" Class containing the overlap-save algorithm for long 1D convolution betweem x and h signals """
@@ -12,15 +14,20 @@ def __init__(self):
1214

1315
self.block_size = 0 # Commonly appears as N in the literature
1416
self.overlap = 0
15-
17+
18+
def reset(self):
19+
self.x = []
20+
self.h = []
21+
self.block_size = 0
22+
1623
def set_signals(self, x, h):
17-
""" """
24+
""" Define long signal x and the corresponding filter impulse response h """
1825

1926
# Checks for invalid signals
2027
if len(x) < len(h):
2128
print("Please enter the long signal as x")
2229
exit(-1)
23-
if len(x) == 0 or len(y) == 0:
30+
if len(x) == 0 or len(h) == 0:
2431
print("Please enter valid signals")
2532
exit(-1)
2633

@@ -29,33 +36,29 @@ def set_signals(self, x, h):
2936
self.overlap = len(h) - 1
3037

3138

32-
def reset(self):
33-
self.x = []
34-
self.h = []
35-
36-
3739
def set_block_size(self, block_size):
38-
""" Define the block """
40+
""" Define the size of each data block """
3941

40-
if len(x) == 0 or len(y) == 0:
42+
if len(self.x) == 0 or len(self.h) == 0:
4143
print("Please set signals before block size")
4244
exit(-1)
4345

4446
if block_size <= 0:
4547
print("Please enter a valid block size")
4648
exit(-1)
4749

48-
if block_size <= len(h) - 1:
50+
if block_size <= len(self.h) - 1:
4951
print("Block size should be greater than length of h - 1")
5052
exit(-1)
5153

5254
self.block_size = block_size
5355

5456

5557
# Irregular list flattening (Josh Lee, https://stackoverflow.com/a/2158522/6129362
56-
def flatten(x):
58+
def _flatten_list(self, x):
59+
""" Flattens a list composed of lists and elements """
5760
if isinstance(x, collections.Iterable):
58-
return [a for i in x for a in flatten(i)]
61+
return [a for i in x for a in self._flatten_list(i)]
5962
else:
6063
return [x]
6164

@@ -66,27 +69,49 @@ def flatten(x):
6669
def circular_convolution(self, x_block, h):
6770
""" Computes circular convolution theorem using the fft """
6871
## Padding
69-
# Append zeroes in the begining of h to equal h_padded and block_len sizes
70-
h_padded = h
71-
h_padded.append([0]*(len(x_block)-len(h)))
72-
h_padded = flatten(h_padded)
73-
print(h_padded)
72+
# Appends zeroes in the begining of h to equal h_padded and block_len sizes
73+
h_padded = list(h)
74+
h_padded.extend([0] * (len(x_block)-len(h)))
7475

7576
# From circular convolution theorem
76-
x_convolved = np.real(np.fft.ifft( np.fft.fft(x_block) * np.fft.fft(h_padded) ))
77+
x_convolved = np.real(np.fft.ifft(np.fft.fft(x_block) * np.fft.fft(h_padded)))
7778
return x_convolved
7879

7980

80-
def apply_convolution(self):
81-
""" """
81+
def overlap_save_convolution(self):
82+
""" Apply the filter defined by impulse response h over the long signal x using the overlap-save method """
8283

8384
if self.block_size == 0:
8485
print("Please set block size before applying convolution")
8586

86-
#loop over X, len(h)-1 steps each time, with each subX being the past block_size positions
87-
88-
for
89-
90-
return
91-
92-
87+
# In the beginning there is no past block to overlap from, so the first M-1 positions are set to zero
88+
x_padded = list(self.x)
89+
x_padded.insert(0,[0]*(len(self.h) - 1))
90+
x_padded = self._flatten_list(x_padded)
91+
92+
# Defines convolution result
93+
y = []
94+
95+
# loop over x len(h) steps at time, creating a overlap of M-1 positions
96+
for i in range(0, len(x_padded), len(self.h)):
97+
## Define x block
98+
# Covers the border case of the last block not being N-sized by appending N - (Len(x_padded) - i) zeroes to it
99+
if len(x_padded) - i < self.block_size:
100+
x_block = x_padded[i : len(x_padded)]
101+
x_block.extend([0] * (self.block_size - (len(x_padded) - i)))
102+
103+
# For all other blocks, simply copy x_padded from i to i+N-1
104+
else:
105+
x_block = x_padded[i : i + self.block_size]
106+
107+
print("X_bloc, y_local")
108+
print(x_block)
109+
# The partial result for a given block is the circular convolution between the signal block and filter impulse response
110+
y_local = self.circular_convolution(x_block, self.h)
111+
print(y_local)
112+
print(len(self.h))
113+
114+
# Keeps only values unnafected by the filter delay of circular convolution, achieving similar result as the linear convolution
115+
y.extend(y_local[len(self.h) - 1:])
116+
117+
return y

practical bibliography - JNTUH.pdf

1.49 MB
Binary file not shown.
207 KB
Binary file not shown.

0 commit comments

Comments
 (0)