From 1ea109c587d930e061bb0e2980c49bab42296f71 Mon Sep 17 00:00:00 2001 From: Subhendu Dash Date: Sat, 25 Feb 2023 23:29:04 +0530 Subject: [PATCH 1/6] add circular convolution --- electronics/circular_convolution.py | 95 +++++++++++++++++++++++++++++ 1 file changed, 95 insertions(+) create mode 100644 electronics/circular_convolution.py diff --git a/electronics/circular_convolution.py b/electronics/circular_convolution.py new file mode 100644 index 000000000000..523ac4cabc79 --- /dev/null +++ b/electronics/circular_convolution.py @@ -0,0 +1,95 @@ +# https://en.wikipedia.org/wiki/Circular_convolution + +""" +Circular convolution, also known as cyclic convolution, +is a special case of periodic convolution, which is the convolution of two +periodic functions that have the same period. Periodic convolution arises, +for example, in the context of the discrete-time Fourier transform (DTFT). +In particular, the DTFT of the product of two discrete sequences is the periodic +convolution of the DTFTs of the individual sequences. And each DTFT is a periodic +summation of a continuous Fourier transform function. + +Source: https://en.wikipedia.org/wiki/Circular_convolution +""" + +import numpy as np +from collections import deque +import doctest + + +class CircularConvolution: + """ + This class stores the first and second signal and performs the circular convolution + """ + + def __init__(self): + """ + First signal and second signal are stored as 1-D array + """ + + self.first_signal = [2, 1, 2, -1] + self.second_signal = [1, 2, 3, 4] + + def circular_convolution(self) -> list[float]: + """ + This function performs the circular convolution of the first and second signal + using matrix method + + Usage: + >>> import circular_convolution as cc + >>> convolution = cc.CircularConvolution() + >>> convolution.circular_convolution() + [10, 10, 6, 14] + + >>> convolution.first_signal = [1, 0.5] + >>> convolution.second_signal = [0.5, 1] + >>> convolution.circular_convolution() + [1.0, 1.25] + + >>> convolution.first_signal = [0.2, 0.4, 0.6, 0.8, 1.0, 1.2, 1.4, 1.6] + >>> convolution.second_signal = [0.1, 0.3, 0.5, 0.7, 0.9, 1.1, 1.3, 1.5] + >>> convolution.circular_convolution() + [5.2, 6.0, 6.48, 6.64, 6.48, 6.0, 5.2, 4.08] + + """ + + length_first_signal = len(self.first_signal) + length_second_signal = len(self.second_signal) + + max_length = max(length_first_signal, length_second_signal) + + # create a zero matrix of max_length x max_length + matrix = [[0] * max_length for i in range(max_length)] + + # fills the smaller signal with zeros to make both signals of same length + if length_first_signal < length_second_signal: + self.second_signal = self.second_signal + np.zeros(max_length) + elif length_first_signal > length_second_signal: + self.first_signal = self.first_signal + np.zeros(max_length) + + """ + Fills the matrix in the following way assuming 'x' is the signal + [ + [x[0], x[3], x[2], x[1]], + [x[1], x[0], x[3], x[2]], + [x[2], x[1], x[0], x[3]], + [x[3], x[2], x[1], x[0]] + ] + """ + for i in range(max_length): + rotated_signal = deque(self.second_signal) + rotated_signal.rotate(i) + for j in range(max_length): + matrix[i][j] += rotated_signal[j] + + matrix = list(np.transpose(matrix)) + + # multiply the matrix with the first signal + self.first_signal = np.transpose(self.first_signal) + final_signal = list(np.matmul(matrix, self.first_signal)) + + return final_signal + + +if __name__ == "__main__": + doctest.testmod() From 4d4ff48c6366e842c9896c4ece4785377781ab9b Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Sat, 25 Feb 2023 18:05:05 +0000 Subject: [PATCH 2/6] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- electronics/circular_convolution.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/electronics/circular_convolution.py b/electronics/circular_convolution.py index 523ac4cabc79..045ed2fbaa7c 100644 --- a/electronics/circular_convolution.py +++ b/electronics/circular_convolution.py @@ -12,9 +12,10 @@ Source: https://en.wikipedia.org/wiki/Circular_convolution """ -import numpy as np -from collections import deque import doctest +from collections import deque + +import numpy as np class CircularConvolution: From 5fef81dbc1a7b63074dfda1ae086b8253113a5f6 Mon Sep 17 00:00:00 2001 From: Subhendu Dash <71781104+subhendudash02@users.noreply.github.com> Date: Sat, 25 Feb 2023 23:48:42 +0530 Subject: [PATCH 3/6] add type hint for __init__ --- electronics/circular_convolution.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/electronics/circular_convolution.py b/electronics/circular_convolution.py index 045ed2fbaa7c..2134adec73fc 100644 --- a/electronics/circular_convolution.py +++ b/electronics/circular_convolution.py @@ -23,7 +23,7 @@ class CircularConvolution: This class stores the first and second signal and performs the circular convolution """ - def __init__(self): + def __init__(self) -> None: """ First signal and second signal are stored as 1-D array """ From 944b0004f6fe748467d1ae267ae33694ddadc305 Mon Sep 17 00:00:00 2001 From: Subhendu Dash Date: Sun, 26 Feb 2023 00:15:54 +0530 Subject: [PATCH 4/6] rounding off final values to 2 and minor changes --- electronics/circular_convolution.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/electronics/circular_convolution.py b/electronics/circular_convolution.py index 2134adec73fc..57fe69392b72 100644 --- a/electronics/circular_convolution.py +++ b/electronics/circular_convolution.py @@ -64,9 +64,9 @@ def circular_convolution(self) -> list[float]: # fills the smaller signal with zeros to make both signals of same length if length_first_signal < length_second_signal: - self.second_signal = self.second_signal + np.zeros(max_length) + self.second_signal += np.zeros(max_length) elif length_first_signal > length_second_signal: - self.first_signal = self.first_signal + np.zeros(max_length) + self.first_signal += np.zeros(max_length) """ Fills the matrix in the following way assuming 'x' is the signal @@ -86,9 +86,12 @@ def circular_convolution(self) -> list[float]: matrix = list(np.transpose(matrix)) # multiply the matrix with the first signal - self.first_signal = np.transpose(self.first_signal) + np.transpose(self.first_signal) final_signal = list(np.matmul(matrix, self.first_signal)) + # rounding-off to two decimal places + final_signal = [round(i, 2) for i in final_signal] + return final_signal From 41cd2ec7831ac0e4610a9a0f698e075b5f0e8b70 Mon Sep 17 00:00:00 2001 From: Subhendu Dash Date: Sun, 26 Feb 2023 16:36:29 +0530 Subject: [PATCH 5/6] add test case for unequal signals --- electronics/circular_convolution.py | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/electronics/circular_convolution.py b/electronics/circular_convolution.py index 57fe69392b72..4291cd47f430 100644 --- a/electronics/circular_convolution.py +++ b/electronics/circular_convolution.py @@ -42,16 +42,21 @@ def circular_convolution(self) -> list[float]: >>> convolution.circular_convolution() [10, 10, 6, 14] - >>> convolution.first_signal = [1, 0.5] - >>> convolution.second_signal = [0.5, 1] - >>> convolution.circular_convolution() - [1.0, 1.25] - >>> convolution.first_signal = [0.2, 0.4, 0.6, 0.8, 1.0, 1.2, 1.4, 1.6] >>> convolution.second_signal = [0.1, 0.3, 0.5, 0.7, 0.9, 1.1, 1.3, 1.5] >>> convolution.circular_convolution() [5.2, 6.0, 6.48, 6.64, 6.48, 6.0, 5.2, 4.08] + >>> convolution.first_signal = [-1, 1, 2, -2] + >>> convolution.second_signal = [0.5, 1, -1, 2, 0.75] + >>> convolution.circular_convolution() + [6.25, -3.0, 1.5, -2.0, -2.75] + + >>> convolution.first_signal = [1, -1, 2, 3, -1] + >>> convolution.second_signal = [1, 2, 3] + >>> convolution.circular_convolution() + [8, -2, 3, 4, 11] + """ length_first_signal = len(self.first_signal) @@ -64,12 +69,12 @@ def circular_convolution(self) -> list[float]: # fills the smaller signal with zeros to make both signals of same length if length_first_signal < length_second_signal: - self.second_signal += np.zeros(max_length) + self.first_signal += [0 for i in range(max_length - length_first_signal)] elif length_first_signal > length_second_signal: - self.first_signal += np.zeros(max_length) + self.second_signal += [0 for i in range(max_length - length_second_signal)] """ - Fills the matrix in the following way assuming 'x' is the signal + Fills the matrix in the following way assuming 'x' is the signal of length 4 [ [x[0], x[3], x[2], x[1]], [x[1], x[0], x[3], x[2]], @@ -83,11 +88,8 @@ def circular_convolution(self) -> list[float]: for j in range(max_length): matrix[i][j] += rotated_signal[j] - matrix = list(np.transpose(matrix)) - # multiply the matrix with the first signal - np.transpose(self.first_signal) - final_signal = list(np.matmul(matrix, self.first_signal)) + final_signal = np.matmul(np.transpose(matrix), np.transpose(self.first_signal)) # rounding-off to two decimal places final_signal = [round(i, 2) for i in final_signal] From 8cb2a634bc747c7a8361074919290bb4537c7aff Mon Sep 17 00:00:00 2001 From: Subhendu Dash Date: Tue, 7 Mar 2023 19:44:55 +0530 Subject: [PATCH 6/6] changes in list comprehension and enumeraton --- electronics/circular_convolution.py | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/electronics/circular_convolution.py b/electronics/circular_convolution.py index 4291cd47f430..f2e35742e944 100644 --- a/electronics/circular_convolution.py +++ b/electronics/circular_convolution.py @@ -69,9 +69,9 @@ def circular_convolution(self) -> list[float]: # fills the smaller signal with zeros to make both signals of same length if length_first_signal < length_second_signal: - self.first_signal += [0 for i in range(max_length - length_first_signal)] + self.first_signal += [0] * (max_length - length_first_signal) elif length_first_signal > length_second_signal: - self.second_signal += [0 for i in range(max_length - length_second_signal)] + self.second_signal += [0] * (max_length - length_second_signal) """ Fills the matrix in the following way assuming 'x' is the signal of length 4 @@ -85,16 +85,14 @@ def circular_convolution(self) -> list[float]: for i in range(max_length): rotated_signal = deque(self.second_signal) rotated_signal.rotate(i) - for j in range(max_length): - matrix[i][j] += rotated_signal[j] + for j, item in enumerate(rotated_signal): + matrix[i][j] += item # multiply the matrix with the first signal final_signal = np.matmul(np.transpose(matrix), np.transpose(self.first_signal)) # rounding-off to two decimal places - final_signal = [round(i, 2) for i in final_signal] - - return final_signal + return [round(i, 2) for i in final_signal] if __name__ == "__main__":