diff --git a/contents/convolutions/code/python/conv.py b/contents/convolutions/code/python/conv.py new file mode 100644 index 000000000..f8c8f48fc --- /dev/null +++ b/contents/convolutions/code/python/conv.py @@ -0,0 +1,60 @@ +import math +from scipy.fftpack import fft, ifft + +def conv(signal1, signal2): + """Discrete convolution by definition""" + + n = len(signal1) + len(signal2) - 1 + out = [] + + for i in range(n): + s = 0 + + for j in range(i + 1): + if j < len(signal1) and i - j < len(signal2): + s += signal1[j] * signal2[i - j] + + out.append(s) + + return out + + +def conv_fft(signal1, signal2): + """Convolution using fft and convolutional theorem""" + + signal1 = signal1.copy() + signal2 = signal2.copy() + + # pad signals to same len + max_len = max(len(signal1), len(signal2)) + + for i in range(max_len - len(signal1)): + signal1.append(0) + for i in range(max_len - len(signal2)): + signal2.append(0) + + fft_s1 = fft(signal1) + fft_s2 = fft(signal2) + out = [] + + for i in range(len(signal1)): + out.append(fft_s1[i] * fft_s2[i]) + + return list(ifft(out)) + + +def main(): + # Example convolution with sin and cos + s1 = [math.sin(x) for x in range(5)] + s2 = [math.cos(x) for x in range(5)] + + print("Discrete Convolution") + print(conv(s1, s2)) + + print("FFT Convolution") + print(conv_fft(s1, s2)) + + +if __name__ == "__main__": + main() + diff --git a/contents/convolutions/convolutions.md b/contents/convolutions/convolutions.md index f74f7f458..c74288467 100644 --- a/contents/convolutions/convolutions.md +++ b/contents/convolutions/convolutions.md @@ -44,6 +44,8 @@ In code, this looks something like: [import:5-18, lang:"c_cpp"](code/c/convolutions.c) {% sample lang="cpp"%} [import:68-88, lang:"c_cpp"](code/c++/convolutions.cpp) +{% sample lang="python"%} +[import:4-19, lang:"python"](code/python/conv.py) {% endmethod %} Note that in this case, the output array will be the size of `f[n]` and `g[n]` put together. @@ -93,6 +95,8 @@ Where the `.*` operator is an element-wise multiplication. [import:20-30, lang:"c_cpp"](code/c/convolutions.c) {% sample lang="cpp"%} [import:90-105, lang:"c_cpp"](code/c++/convolutions.cpp) +{% sample lang="python"%} +[import:22-43, lang:"python"](code/python/conv.py) {% endmethod %} This method also has the added advantage that it will *always output an array of the size of your signal*; however, if your signals are not of equal size, we need to pad the smaller signal with zeros.