1 2 #include <math.h> 3 4 /** 5 <p> 6 Daubechies D4 wavelet transform (D4 denotes four coefficients) 7 </p> 8 <p> 9 I have to confess up front that the comment here does not even come 10 close to describing wavelet algorithms and the Daubechies D4 11 algorithm in particular. I don't think that it can be described in 12 anything less than a journal article or perhaps a book. I even have 13 to apologize for the notation I use to describe the algorithm, which 14 is barely adequate. But explaining the correct notation would take 15 a fair amount of space as well. This comment really represents some 16 notes that I wrote up as I implemented the code. If you are 17 unfamiliar with wavelets I suggest that you look at the bearcave.com 18 web pages and at the wavelet literature. I have yet to see a really 19 good reference on wavelets for the software developer. The best 20 book I can recommend is <i>Ripples in Mathematics</i> by Jensen and 21 Cour-Harbo. 22 </p> 23 24 <p> 25 All wavelet algorithms have two components, a wavelet function and a 26 scaling function. These are sometime also referred to as high pass 27 and low pass filters respectively. 28 </p> 29 30 <p> 31 The wavelet function is passed two or more samples 32 and calculates a wavelet coefficient. In the case of 33 the Haar wavelet this is 34 </p> 35 36 <pre> 37 coef<sub>i</sub> = odd<sub>i</sub> - even<sub>i</sub> 38 or 39 coef<sub>i</sub> = 0.5 * (odd<sub>i</sub> - even<sub>i</sub>) 40 </pre> 41 <p> 42 depending on the version of the Haar algorithm used. 43 </p> 44 <p> 45 The scaling function produces a smoother version of the 46 original data. In the case of the Haar wavelet algorithm 47 this is an average of two adjacent elements. 48 </p> 49 <p> 50 The Daubechies D4 wavelet algorithm also has a wavelet 51 and a scaling function. The coefficients for the 52 scaling function are denoted as h<sub>i</sub> and the 53 wavelet coefficients are g<sub>i</sub>. 54 </p> 55 <p> 56 Mathematicians like to talk about wavelets in terms of 57 a wavelet algorithm applied to an infinite data set. rd_tmpabuf_new(rd_tmpabuf_t * tab,size_t size,int assert_on_fail)58 In this case one step of the forward transform can be expressed 59 as the infinite matrix of wavelet coefficients 60 represented below multiplied by the infinite signal 61 vector. 62 </p> 63 <pre> 64 a<sub>i</sub> = ...h0,h1,h2,h3, 0, 0, 0, 0, 0, 0, 0, ... s<sub>i</sub> 65 c<sub>i</sub> = ...g0,g1,g2,g3, 0, 0, 0, 0, 0, 0, 0, ... s<sub>i+1</sub> 66 a<sub>i+1</sub> = ...0, 0, h0,h1,h2,h3, 0, 0, 0, 0, 0, ... s<sub>i+2</sub> 67 c<sub>i+1</sub> = ...0, 0, g0,g1,g2,g3, 0, 0, 0, 0, 0, ... s<sub>i+3</sub> 68 a<sub>i+2</sub> = ...0, 0, 0, 0, h0,h1,h2,h3, 0, 0, 0, ... s<sub>i+4</sub> 69 c<sub>i+2</sub> = ...0, 0, 0, 0, g0,g1,g2,g3, 0, 0, 0, ... s<sub>i+5</sub> 70 a<sub>i+3</sub> = ...0, 0, 0, 0, 0, 0, h0,h1,h2,h3, 0, ... s<sub>i+6</sub> 71 c<sub>i+3</sub> = ...0, 0, 0, 0, 0, 0, g0,g1,g2,g3, 0, ... s<sub>i+7</sub> 72 </pre> 73 <p> 74 The dot product (inner product) of the infinite vector and 75 a row of the matrix produces either a smoother version of the 76 signal (a<sub>i</sub>) or a wavelet coefficient (c<sub>i</sub>). 77 </p> 78 <p> 79 In an ordered wavelet transform, the smoothed (a<sub>i</sub>) are 80 stored in the first half of an <i>n</i> element array region. The 81 wavelet coefficients (c<sub>i</sub>) are stored in the second half 82 the <i>n</i> element region. The algorithm is recursive. The 83 smoothed values become the input to the next step. 84 </p> 85 <p> 86 The transpose of the forward transform matrix above is used 87 to calculate an inverse transform step. Here the dot product is 88 formed from the result of the forward transform and an inverse 89 transform matrix row. 90 </p> 91 <pre> 92 s<sub>i</sub> = ...h2,g2,h0,g0, 0, 0, 0, 0, 0, 0, 0, ... a<sub>i</sub> 93 s<sub>i+1</sub> = ...h3,g3,h1,g1, 0, 0, 0, 0, 0, 0, 0, ... c<sub>i</sub> 94 s<sub>i+2</sub> = ...0, 0, h2,g2,h0,g0, 0, 0, 0, 0, 0, ... a<sub>i+1</sub> 95 s<sub>i+3</sub> = ...0, 0, h3,g3,h1,g1, 0, 0, 0, 0, 0, ... c<sub>i+1</sub> 96 s<sub>i+4</sub> = ...0, 0, 0, 0, h2,g2,h0,g0, 0, 0, 0, ... a<sub>i+2</sub> 97 s<sub>i+5</sub> = ...0, 0, 0, 0, h3,g3,h1,g1, 0, 0, 0, ... c<sub>i+2</sub> 98 s<sub>i+6</sub> = ...0, 0, 0, 0, 0, 0, h2,g2,h0,g0, 0, ... a<sub>i+3</sub> 99 s<sub>i+7</sub> = ...0, 0, 0, 0, 0, 0, h3,g3,h1,g1, 0, ... c<sub>i+3</sub> 100 </pre> 101 102 <p> 103 Using a standard dot product is grossly inefficient since most 104 of the operands are zero. In practice the wavelet coefficient 105 values are moved along the signal vector and a four element 106 dot product is calculated. Expressed in terms of arrays, for 107 the forward transform this would be: 108 </p> 109 <pre> 110 a<sub>i</sub> = s[i]*h0 + s[i+1]*h1 + s[i+2]*h2 + s[i+3]*h3 111 c<sub>i</sub> = s[i]*g0 + s[i+1]*g1 + s[i+2]*g2 + s[i+3]*g3 112 </pre> 113 <p> 114 This works fine if we have an infinite data set, since we don't 115 have to worry about shifting the coefficients "off the end" of 116 the signal. 117 </p> 118 <p> 119 I sometimes joke that I left my infinite data set in my other bear 120 suit. The only problem with the algorithm described so far is that 121 we don't have an infinite signal. The signal is finite. In fact 122 not only must the signal be finite, but it must have a power of two 123 number of elements. 124 </p> 125 <p> 126 If i=N-1, the i+2 and i+3 elements will be beyond the end of 127 the array. There are a number of methods for handling the 128 wavelet edge problem. This version of the algorithm acts 129 like the data is periodic, where the data at the start of 130 the signal wraps around to the end. 131 </p> 132 <p> 133 This algorithm uses a temporary array. A Lifting Scheme version of 134 the Daubechies D4 algorithm does not require a temporary. The 135 matrix discussion above is based on material from <i>Ripples in 136 Mathematics</i>, by Jensen and Cour-Harbo. Any error are mine. 137 </p> 138 139 <p> 140 <b>Author</b>: Ian Kaplan<br> 141 <b>Use</b>: You may use this software for any purpose as long 142 as I cannot be held liable for the result. Please credit me 143 with authorship if use use this source code. 144 <p> 145 This comment is formatted for the doxygen documentation generator 146 </p> 147 */ 148 149 //hacks by Nick 150 //doubles -> floats 151 //avoid new and delete within transform functions, put in one place 152 153 class Daubechies { 154 private: 155 /** forward transform scaling coefficients */ 156 float h0, h1, h2, h3; 157 /** forward transform wave coefficients */ 158 float g0, g1, g2, g3; 159 160 float Ih0, Ih1, Ih2, Ih3; 161 float Ig0, Ig1, Ig2, Ig3; 162 float* tmp; 163 164 165 /** 166 Forward Daubechies D4 transform 167 */ 168 void transform( float* a, const int n ) 169 { 170 171 // printf("inside transform a %p tmp %p \n", a, tmp); 172 173 174 175 // for(int i=0; i<64; ++i) printf("transform data i %d a %f tmp %f \n",i, a[i], tmp[i]); 176 177 178 if (n >= 4) { 179 int i, j; 180 const int half = n >> 1; 181 182 //float* tmp = new float[n]; 183 184 for (i = 0, j = 0; j < n-3; j += 2, i++) { 185 tmp[i] = a[j]*h0 + a[j+1]*h1 + a[j+2]*h2 + a[j+3]*h3; 186 tmp[i+half] = a[j]*g0 + a[j+1]*g1 + a[j+2]*g2 + a[j+3]*g3; 187 //printf("transform data i %d j %d tmp[i] %f tmp[i+half] %f \n",i,j, tmp[i], tmp[i+half]); 188 } 189 190 tmp[i] = a[n-2]*h0 + a[n-1]*h1 + a[0]*h2 + a[1]*h3; 191 tmp[i+half] = a[n-2]*g0 + a[n-1]*g1 + a[0]*g2 + a[1]*g3; 192 193 for (i = 0; i < n; i++) { 194 a[i] = tmp[i]; 195 } 196 // delete [] tmp; 197 } 198 } 199 200 /** 201 Inverse Daubechies D4 transform 202 */ 203 void invTransform( float* a, const int n ) 204 { 205 if (n >= 4) { 206 int i, j; 207 const int half = n >> 1; 208 const int halfPls1 = half + 1; 209 210 // float* tmp = new float[n]; 211 212 // last smooth val last coef. first smooth first coef 213 tmp[0] = a[half-1]*Ih0 + a[n-1]*Ih1 + a[0]*Ih2 + a[half]*Ih3; 214 tmp[1] = a[half-1]*Ig0 + a[n-1]*Ig1 + a[0]*Ig2 + a[half]*Ig3; 215 for (i = 0, j = 2; i < half-1; i++) { 216 // smooth val coef. val smooth val coef. val 217 tmp[j++] = a[i]*Ih0 + a[i+half]*Ih1 + a[i+1]*Ih2 + a[i+halfPls1]*Ih3; 218 tmp[j++] = a[i]*Ig0 + a[i+half]*Ig1 + a[i+1]*Ig2 + a[i+halfPls1]*Ig3; 219 } 220 for (i = 0; i < n; i++) { 221 a[i] = tmp[i]; 222 } 223 //delete [] tmp; 224 } 225 } 226 227 228 public: 229 230 Daubechies() 231 { 232 const float sqrt_3 = sqrt( 3 ); 233 const float denom = 4 * sqrt( 2 ); 234 235 // 236 // forward transform scaling (smoothing) coefficients 237 // 238 h0 = (1 + sqrt_3)/denom; 239 h1 = (3 + sqrt_3)/denom; 240 h2 = (3 - sqrt_3)/denom; 241 h3 = (1 - sqrt_3)/denom; 242 // 243 // forward transform wavelet coefficients 244 // 245 g0 = h3; 246 g1 = -h2; 247 g2 = h1; 248 g3 = -h0; 249 250 Ih0 = h2; 251 Ih1 = g2; // h1 252 Ih2 = h0; 253 Ih3 = g0; // h3 254 255 Ig0 = h3; 256 Ig1 = g3; // -h0 257 Ig2 = h1; 258 Ig3 = g1; // -h2 259 260 tmp = new float[4096]; //make sure big enough never to be an issue; size chosen here limits overall wavelet transform max N 261 } 262 263 ~Daubechies() { 264 delete [] tmp; 265 } 266 267 void daubTrans( float* ts, int N ) 268 { 269 int n; 270 for (n = N; n >= 4; n >>= 1) { 271 272 //printf("pre sub transform %d \n",n); 273 transform( ts, n ); 274 //printf("post sub transform %d \n",n); 275 } 276 } 277 278 279 void invDaubTrans( float* coef, int N ) 280 { 281 int n; 282 for (n = 4; n <= N; n <<= 1) { 283 invTransform( coef, n ); 284 } 285 } 286 287 }; // Daubechies 288