Intel® Integrated Performance Primitives (Intel® IPP) Developer Guide and Reference

ID 790148
Date 3/22/2024
Public
Document Table of Contents

Wavelet Transforms Example

The delay line paradigm is well-known interface solution for functions that require some pre-history in the streaming processing. In such application the use of the Intel IPP wavelet transform functions is similar to the use of the FIR, IIR, or multi-rate filters. (See also the discussion on the synchronization of low-pass and high-pass filter delays in this chapter.) But very often the wavelet transforms are used to process entire non-streaming data by extending with borders that are suitable for filter bank type that are used in transforms.

The following code example demonstrates how to implement this approach using the Intel IPP functions. It performs forward and inverse wavelet transforms of a short vector containing 12 elements. It uses Daubechies filter bank of the order 2 (that allows the perfect reconstruction) and periodical data extension by wrapping.

It is also may be useful as an illustration of how to fill delay line, if you need non-zero pre-history of signal in streaming applications.

Example

//   Filter bank for Daubechies, order 2  
static const int fwdFltLenL = 4;
static const int fwdFltLenH = 4;
static const Ipp32f pFwdFltL[4] =
{    -1.294095225509215e-001f,     2.241438680418574e-001f,     8.365163037374690e-001f,     4.829629131446903e-001f  };
static const Ipp32f pFwdFltH[4] =
{    -4.829629131446903e-001f,     8.365163037374690e-001f,    -2.241438680418574e-001f,    -1.294095225509215e-001f  };
static const int invFltLenL = 4;
static const int invFltLenH = 4;
static const Ipp32f pInvFltL[4] =
{     4.829629131446903e-001f,     8.365163037374690e-001f,     2.241438680418574e-001f,    -1.294095225509215e-001f  };
static const Ipp32f pInvFltH[4] =
{    -1.294095225509215e-001f,    -2.241438680418574e-001f,     8.365163037374690e-001f,    -4.829629131446903e-001f  };
// minimal values
static const int fwdFltOffsL = -1;
static const int fwdFltOffsH = -1;
// minimal values, that corresponds to perfect reconstruction
static const int invFltOffsL = 0;
static const int invFltOffsH = 0;

void func_wavelet()
{
   IppStatus status=ippStsNoErr;
   Ipp32f pSrc[] = {1, -10, 324, 48, -483, 4, 7, -5532, 34, 8889, -57, 54};
   Ipp32f pDst[12];
   Ipp32f pLow[6];
   Ipp32f pHigh[6];
   IppsWTFwdState_32f* pFwdState;
   IppsWTInvState_32f* pInvState;
   int i, szState;

   printf("original:\n");
   for(i = 0; i < 12; i++)
      printf("%.0f; ", pSrc[i]);
   printf("\n");

   // Forward transform
   ippsWTFwdGetSize( ipp32f, fwdFltLenL, fwdFltOffsL, fwdFltLenH, fwdFltOffsH, &szState );
   pFwdState = (IppsWTFwdState_32f*)ippMalloc( szState );
   ippsWTFwdInit_32f( pFwdState, pFwdFltL, fwdFltLenL, fwdFltOffsL, pFwdFltH, fwdFltLenH, fwdFltOffsH);
   // We substitute wrapping extension in "the beginning of stream"
   // Here should be the same pointers for this offsets,
   // but in the general case it may be different
   ippsWTFwdSetDlyLine_32f( pFwdState, &pSrc[10], &pSrc[10] );
   ippsWTFwd_32f( pSrc, pLow, pHigh, 6, pFwdState );

   printf("approx:\n");
   for(i = 0; i < 6; i++)
      printf("%.4f; ", pLow[i]);
   printf("\n");
   printf("details:\n");
   for(i = 0; i < 6; i++)
      printf("%.4f; ", pHigh[i]);
   printf("\n");

   // Inverse transform
   ippsWTInvGetSize( ipp32f, invFltLenL, invFltOffsL, invFltLenH, invFltOffsH, &szState );
   pInvState = (IppsWTInvState_32f*)ippMalloc( szState );
   ippsWTInvInit_32f( pInvState, pInvFltL, invFltLenL, invFltOffsL, pInvFltH, invFltLenH, invFltOffsH );
   // For this particular case (non-shifted reconstruction)
   // here is first data itself,
   // that we need to place to delay line
   // [(invFltLenL + invFltOffsL - 1) / 2] elements for l. filtering
   // [(invFltLenH + invFltOffsH - 1) / 2] elements for h. filtering
   ippsWTInvSetDlyLine_32f( pInvState, pLow, pHigh);
   ippsWTInv_32f( &pLow[1], &pHigh[1], 5, pDst, pInvState );
   // Here are the substitution of the wrapping extension
   // at the "end of stream" and calculation of last samples of reconstruction
   // We do not use additional buffer and do not copy any data externally,
   // just substitute beginning of input data itself to simulate wrapping
   ippsWTInv_32f( pLow, pHigh, 1, &pDst[10], pInvState );

   printf("reconstruction:\n");
   for(i = 0; i < 12; i++)
      printf("%.0f; ", pDst[i]);
   printf("\n");

   ippFree(pFwdState);
   ippFree(pInvState);
}

After compiling and running it gives the following console output:

original:
1; -10; 324; 48; -483; 4; 7; -5532; 34; 8889; -57; 54;
approx:
19.1612; 58.5288; 87.8536; 487.5375; -5766.9277; 7432.4497;
details:
0.9387; 249.9611; -458.6568; 2739.2146; -3025.5576; -2070.5762;
reconstruction:
1; -10; 324; 48; -483; 4; 7; -5532; 34; 8889; -57; 54;

The program prints on console the original data, approximation, and details components after forward transform and perfect reconstruction of original data after inverse transform.