## Methods for Single-Level Discrete Wavelet Transform of 1D Signals in Python (II): Wavelet Reconstruction

Master the Discrete wavelet reconstruction methods using easily understanding examples

The methods for 1D Single-Level Discrete Wavelet Transform in Python will be discussed in the following 3 parts:

(II): Wavelet Reconstruction

In the last part (I), we have talked about how to decompose a 1D signal into approximation and detail coefficients at the first level. The next part of the story of Discrete wavelet transform is how to reconstruct the signal from these decomposition components. In this post, we discuss this top still using simple examples so that you can easily grasp the method.

### 1. Inverse Discrete Wavelet Transform (idwt)

We perform single levelidwt (inverse Discrete Wavelet Transform) method to reconstructs a signal from the first-level decomposition coefficients.

pywt.idwt(cA, cD, wavelet, mode='sym', correct_size=0)

Parameters:

• cA: Approximation coefficient.
• cD: Detail coefficient.
• wavelet: Wavelet used in the transform
• mode: Signal extension mode to deal with the border distortion problem
• correct_size: Typically, cA and cD coefficients must have same lengths in order to perform IDWT. Setting correct_size to True allows cA to be greater in size by one element than the cD size.

Return:

• the reconstructed signal

### 2. Example 1: Even Length Signal

First, let’s create a simple signal with values from 1 to 100. First, let’s decompose it using the dwt method learned in the last part.

#### (1) Create a signal

s_even = list(range(1,101))
print(s_even)

The result is:

[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100]

#### (2) Decompose it at the first level

We use sym3 discrete wavelet and constant extension mode.

import pywt

(cA,cD) = pywt.dwt(s_even,'sym3','constant') # Symlets 3 (sym3)

print('Approximation Coefficient: \n',cA)
print('Detail Coefficient: \n',cD)
Approximation Coefficient:
[  1.44943985   1.21399887   2.57019338   5.3986205    8.22704763
11.05547475  13.88390188  16.712329    19.54075613  22.36918325
25.19761038  28.0260375   30.85446463  33.68289175  36.51131888
39.339746    42.16817313  44.99660025  47.82502738  50.6534545
53.48188163  56.31030875  59.13873587  61.967163    64.79559012
67.62401725  70.45244437  73.2808715   76.10929862  78.93772575
81.76615287  84.59458     87.42300712  90.25143425  93.07986137
95.9082885   98.73671562 101.56514275 104.39356987 107.221997
110.05042412 112.87885124 115.70727837 118.53570549 121.36413262
124.19255974 127.02098687 129.84941399 132.67784112 135.50626824
138.34968406 141.08868568]
Detail Coefficient:
[-3.32670553e-01  1.55893858e-01 -9.61654367e-13 -6.95765667e-12
-1.29543598e-11 -1.89513127e-11 -2.49475995e-11 -3.09423043e-11
-3.69395625e-11 -4.29357661e-11 -4.89323027e-11 -5.49287282e-11
-6.09251538e-11 -6.69194700e-11 -7.29143412e-11 -7.89122101e-11
-8.49103010e-11 -9.09072817e-11 -9.69069269e-11 -1.02899467e-10
-1.08896225e-10 -1.14888765e-10 -1.20889299e-10 -1.26885169e-10
-1.32881262e-10 -1.38878242e-10 -1.44877665e-10 -1.50867097e-10
-1.56860080e-10 -1.62855951e-10 -1.68856928e-10 -1.74852577e-10
-1.80850002e-10 -1.86848315e-10 -1.92848848e-10 -1.98839167e-10
-2.04833928e-10 -2.10831352e-10 -2.16827889e-10 -2.22815544e-10
-2.28834729e-10 -2.34824160e-10 -2.40813591e-10 -2.46802134e-10
-2.52798671e-10 -2.58802313e-10 -2.64790856e-10 -2.70794942e-10
-2.76785261e-10 -2.82780022e-10 -1.41550404e-01 -3.52262922e-02]

#### (3) Reconstruct the signal

Now, let’s reconstruct the signal using idwt method. The same wavelet and extension should be used in the wavelet decomposition and reconstruction.

s_even_recon = pywt.idwt(cA, cD, 'sym3', 'constant')

print(s_even_recon)
[  1.   2.   3.   4.   5.   6.   7.   8.   9.  10.  11.  12.  13.  14.
15.  16.  17.  18.  19.  20.  21.  22.  23.  24.  25.  26.  27.  28.
29.  30.  31.  32.  33.  34.  35.  36.  37.  38.  39.  40.  41.  42.
43.  44.  45.  46.  47.  48.  49.  50.  51.  52.  53.  54.  55.  56.
57.  58.  59.  60.  61.  62.  63.  64.  65.  66.  67.  68.  69.  70.
71.  72.  73.  74.  75.  76.  77.  78.  79.  80.  81.  82.  83.  84.
85.  86.  87.  88.  89.  90.  91.  92.  93.  94.  95.  96.  97.  98.
99. 100.]

The reconstruction result reveals that it successfully reconstruct the signal.

However, it is not so easy to see the result for a complicate real-world signal. Then we have to evaluate the method through comparison tests, such as length and errors.

#### (i) check the length

print('Length of the orignal signal:',len(s_even))
print('Length of the reconstructed signal:',len(s_even_recon))
Length of the orignal signal: 100
Length of the reconstructed signal: 100

So the length of the reconstructed signal has the same length with the original.

(ii) check the errors
Here, let’s evaluate the reconstruction using Mean absolute error (MAE) and maximum absolute error(Max. AE).

print('MAE:', sum(abs(s_even-s_even_recon))/len(S))
print('Max.AE:',max(abs(s_even-s_even_recon)))
MAE: 5.769074107320193e-13
Max.AE: 1.0771827874123119e-11

From the above results, we can see that there are very small errors, which can be ignored. This is why we see the reconstructed signal is just the same with the original, except that values are expressed by float.

The question next is how about the signal of odd length? Let’s discuss it as follows.

### 3. Example 2: Odd Length Signal

#### (1) Create the signal

Suppose our signal is odd length with values ranging from 1 to 99, for example.

s_odd = list(range(1,100))
print(s_odd)
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99]

#### (2) Decompose the signal

Let’s decompose it first. We use cA1 and cD1 this time in order for comparison with the even signal.

(cA1,cD1) = pywt.dwt(s_odd,'sym3','constant') # Symlets 3 (sym3)

print('Approximation Coefficient: \n',cA1)
print('Detail Coefficient: \n',cD1)
Approximation Coefficient:
[  1.44943985   1.21399887   2.57019338   5.3986205    8.22704763
11.05547475  13.88390188  16.712329    19.54075613  22.36918325
25.19761038  28.0260375   30.85446463  33.68289175  36.51131888
39.339746    42.16817313  44.99660025  47.82502738  50.6534545
53.48188163  56.31030875  59.13873587  61.967163    64.79559012
67.62401725  70.45244437  73.2808715   76.10929862  78.93772575
81.76615287  84.59458     87.42300712  90.25143425  93.07986137
95.9082885   98.73671562 101.56514275 104.39356987 107.221997
110.05042412 112.87885124 115.70727837 118.53570549 121.36413262
124.19255974 127.02098687 129.84941399 132.67784112 135.47104195
138.53491006 140.00714267]
Detail Coefficient:
[-3.32670553e-01  1.55893858e-01 -9.61654367e-13 -6.95765667e-12
-1.29543598e-11 -1.89513127e-11 -2.49475995e-11 -3.09423043e-11
-3.69395625e-11 -4.29357661e-11 -4.89323027e-11 -5.49287282e-11
-6.09251538e-11 -6.69194700e-11 -7.29143412e-11 -7.89122101e-11
-8.49103010e-11 -9.09072817e-11 -9.69069269e-11 -1.02899467e-10
-1.08896225e-10 -1.14888765e-10 -1.20889299e-10 -1.26885169e-10
-1.32881262e-10 -1.38878242e-10 -1.44877665e-10 -1.50867097e-10
-1.56860080e-10 -1.62855951e-10 -1.68856928e-10 -1.74852577e-10
-1.80850002e-10 -1.86848315e-10 -1.92848848e-10 -1.98839167e-10
-2.04833928e-10 -2.10831352e-10 -2.16827889e-10 -2.22815544e-10
-2.28834729e-10 -2.34824160e-10 -2.40813591e-10 -2.46802134e-10
-2.52798671e-10 -2.58802313e-10 -2.64790856e-10 -2.70794942e-10
-2.76785261e-10  3.32670553e-01 -1.55893858e-01 -2.96810576e-10]

#### (3) Reconstruct the signal

s_odd_recon = pywt.idwt(cA1, cD1, 'sym3', 'constant')
print(s_odd_recon)
[ 1.  2.  3.  4.  5.  6.  7.  8.  9. 10. 11. 12. 13. 14. 15. 16. 17. 18.
19. 20. 21. 22. 23. 24. 25. 26. 27. 28. 29. 30. 31. 32. 33. 34. 35. 36.
37. 38. 39. 40. 41. 42. 43. 44. 45. 46. 47. 48. 49. 50. 51. 52. 53. 54.
55. 56. 57. 58. 59. 60. 61. 62. 63. 64. 65. 66. 67. 68. 69. 70. 71. 72.
73. 74. 75. 76. 77. 78. 79. 80. 81. 82. 83. 84. 85. 86. 87. 88. 89. 90.
91. 92. 93. 94. 95. 96. 97. 98. 99. 99.]

#### (4) Evaluate the results

# check length
print('Length of the orignal signal:',len(s_odd))
print('Length of the reconstructed signal:',len(s_odd_recon))
Length of the orignal signal: 99
Length of the reconstructed signal: 100

We can see that the original signal has 99 values, while the reconstructed signal has 100 values. If we check the reconstructed signal, we found that there is another ‘99’ was added. It will add one more value at end based on the extension model because DWT requires even number length of the signal.

Thus, the reconstructed signal should be the one after removing the extra value.

# reconstructed signal
s_odd_recon = s_odd_recon[:-1]
print(s_odd_recon)
[ 1.  2.  3.  4.  5.  6.  7.  8.  9. 10. 11. 12. 13. 14. 15. 16. 17. 18.
19. 20. 21. 22. 23. 24. 25. 26. 27. 28. 29. 30. 31. 32. 33. 34. 35. 36.
37. 38. 39. 40. 41. 42. 43. 44. 45. 46. 47. 48. 49. 50. 51. 52. 53. 54.
55. 56. 57. 58. 59. 60. 61. 62. 63. 64. 65. 66. 67. 68. 69. 70. 71. 72.
73. 74. 75. 76. 77. 78. 79. 80. 81. 82. 83. 84. 85. 86. 87. 88. 89. 90.
91. 92. 93. 94. 95. 96. 97. 98. 99.]

So we cannot see any different between the reconstructed signal and the original one from the above result. Whereas, they are the same because there might be errors, since the signal is transformed through filters, downsampling and upsampling. Let’s check to confirm the conclusion.

print('MAE:', sum(abs(s_odd-s_odd_recon))/len(S))
print('Max.AE:',max(abs(s_odd-s_odd_recon)))
MAE: 5.766231936377153e-13
Max.AE: 1.0786038728838321e-11