/*
* These functions calculate the values for quadrature mirror filter
* coefficient arrays.
*
* Copyright (C) 1991--94 Wickerhauser Consulting. All Rights Reserved.
* May be freely copied for personal, noncommercial use by owners of
* ``Adapted Wavelet Analysis from Theory to Software'' ISBN 1-56881-041-5
* by Mladen Victor Wickerhauser [AK Peters, Ltd., Wellesley, Mass., 1994]
*
*/
#include
#include
#include "real.h"
#include "common.h"
#include "qf.h" /* Data structs and function prototypes */
#include "oqfs.h" /* Orthogonal filter coefficients. */
/********************************************************************
* mkpqf()
*
* Function `mkpqf()' returns a pointer to a `pqf' data structure
* containing the coefficients, length and the pre-periodized filter
* named by the input parameters.
*
* Calling sequence:
* mkpqf( coefs, alpha, omega, flags )
*
* Inputs:
* (const real *)coefs These are the filter coefficients,
* assumed to be given in the array
* `coefs[0],...,coefs[omega-alpha]'
* are the only nonzero values.
*
* (int)alpha These are to be the first and last valid
* (int)omega indices of the pqf->f struct member.
*
* (int)flags This is reserved for later uses, such as
* indicating when to generate a full QF
* sequence from just one symmetric half.
*
* Return value:
* (pqf *)mkpqf The return value is a pointer to a newly
* allocated pqf struct containing `coefs[]',
* `alpha', `omega', and the preperiodized
* version of `coefs[]'.
* Assumptions:
* (1) Conventional indexing: `alpha <= 0 <= omega'.
*/
extern pqf *
mkpqf(
const real *coefs, /* Original filter coefficients. */
int alpha, /* Least valid index of `?->f[]'. */
int omega, /* Greatest valid index of `?->f[]'. */
int flags) /* Reserved for future use. */
{
pqf *qm;
int M;
assert(alpha <= 0); /* Conventional indexing. */
assert(0 <= omega); /* Conventional indexing. */
qm = (pqf *)calloc(1,sizeof(pqf)); assert(qm);
qm->alpha = alpha;
qm->omega = omega;
qm->f = coefs-alpha;
M = IFH( omega-alpha );
qm->fp = (real *)calloc( PQFL(M), sizeof(real)); assert(qm->fp);
qfcirc( qm->fp, qm->f, alpha, omega );
qm->center = coe( qm->f, alpha, omega );
qm->deviation = lphdev( qm->f, alpha, omega );
return(qm);
}
/********************************************************************
* qf()
*
* Function `qf()' returns a pointer to a `pqf' data structure
* containing the coefficients, name, length and kind of the filter
* named by the input parameters.
*
* Calling sequence:
* qf( name, range, kind )
*
* Inputs:
* (const char *)name This is the name of the filter, specified as
* at least the first letter of "Beylkin",
* "Coifman", "Vaidyanathan", or "Daubechies",
* written as a string (enclosed in " marks).
* Case is ignored, only the first letter
* matters, and "Standard" is an alias for "D".
*
* (int)range This is the length of the requested filter. Allowed
* values depend on what `name' is.
*
* (int)kind If kind==LOW_PASS_QF, qf() returns the summing or
* low-pass filter `pqf' structure.
* If kind==HIGH_PASS_QF, qf() returns the differencing
* or high-pass filter `pqf' structure.
*
* Return value:
* (pqf *)qf If a `name'd filter of the requested `range' and
* `kind' is listed, then the return value is
* a pointer to a newly-allocated pqf struct
* specifying a conventionally-indexed filter
* to be used for convolution-decimation.
* Otherwise, the returned pointer is NULL.
*
*/
extern pqf *
qf( /* Coefficient struct or NULL pointer. */
const char *name, /* String "B", "C", "D", or "V". */
int range, /* Length of coefficient array. */
int kind) /* LOW_PASS_QF or HIGH_PASS_QF. */
{
pqf *qm;
/* These macros call `mkpqf()' with the right arguments: */
#define MKMKPQF(n, sd) mkpqf( n##sd##oqf, n##sd##alpha, n##sd##omega, 0 )
#define SETSDPQF(n, k) ( k==LOW_PASS_QF ) ? MKMKPQF(n, s) : MKMKPQF(n, d)
qm = 0; /* Return NULL pointer if unsuccessful. */
/* Choose an orthogonal filter based on the first letter of
* the filter name: `name' argument starts with B, C, D, V
*/
switch( name[0] ) {
case 'b':
case 'B':
/* Beylkin filters.
*
* Here are the coefficients for Gregory BEYLKIN'S wave packets.
*/
switch( range )
{
case 18: qm = SETSDPQF( b18, kind ); break;
default: break; /* Fall out: the length is unavailable. */
}
break; /* Beylkin type. */
case 'c':
case 'C':
/* Coiflet filters.
*
* Here are the coefficients for COIFLETS with respectively
* 2, 4, 6, 8 and 10 moments vanishing for phi. Filter Q has
* range/3 moments vanishing. Filter P has range/3 moments
* vanishing with the appropriate shift.
*/
switch( range )
{
case 6: qm = SETSDPQF( c06, kind ); break;
case 12: qm = SETSDPQF( c12, kind ); break;
case 18: qm = SETSDPQF( c18, kind ); break;
case 24: qm = SETSDPQF( c24, kind ); break;
case 30: qm = SETSDPQF( c30, kind ); break;
default: break; /* Fall out: the length is unavailable. */
}
break; /* Coifman type. */
case 's':
case 'S': /* STANDARD filters, in old terminology. */
case 'd':
case 'D':
/* Daubechies filters.
*
* Initialize quadrature mirror filters P,Q of length 'range' with
* smooth limits and minimal phase, as in DAUBECHIES:
*/
switch( range )
{
case 2: qm = SETSDPQF( d02, kind ); break;
case 4: qm = SETSDPQF( d04, kind ); break;
case 6: qm = SETSDPQF( d06, kind ); break;
case 8: qm = SETSDPQF( d08, kind ); break;
case 10: qm = SETSDPQF( d10, kind ); break;
case 12: qm = SETSDPQF( d12, kind ); break;
case 14: qm = SETSDPQF( d14, kind ); break;
case 16: qm = SETSDPQF( d16, kind ); break;
case 18: qm = SETSDPQF( d18, kind ); break;
case 20: qm = SETSDPQF( d20, kind ); break;
default: break; /* Fall out: the length is unavailable. */
}
break; /* Standard or Daubechies type. */
case 'v':
case 'V':
/* Vaidyanathan filters
*
* The following coefficients correspond to one of the filters
* constructed by Vaidyanathan (Filter #24B from his paper
* in IEEE Trans. ASSP Vol.36, pp 81-94 (1988). These coefficients
* give an exact reconstruction scheme, but they don't satisfy ANY
* moment condition (not even the normalization : the sum of the c_n
* is close to 1, but not equal to 1). The function one obtains after
* iterating the reconstruction procedure 9 times looks continuous,
* but is of course not differentiable. It would be interesting to
* see how such a filter performs. It has been optimized, for its
* filter length, for the standard requirements that speech people
* impose.
*/
switch( range )
{
case 24: qm = SETSDPQF( v24, kind ); break;
default: break; /* Fall out: the length is unavailable. */
}
break; /* Vaidyanathan type. */
default: break; /* Fall out: the filter is unavailable. */
}
return(qm);
}
/*******************************************************************
* coe()
*
* Compute the center-of-energy for a sequence.
*
* Basic algorithm:
* center = ( Sum_k k*in[x]^2 ) / (Sum_k in[k]^2 )
*
* Calling sequence:
* coe( in, alpha, omega )
*
* Inputs:
* (const real *)in The sequence is `in[alpha],...,in[omega]'
*
* (int)alpha These are to be the first and last
* (int)omega valid indices of the array `in[]'.
*
* Output:
* (real)coe This is in the interval `[alpha, omega]'.
*
* Assumptions:
* (1) Conventional indexing: `alpha <= 0 <= omega'.
*/
extern real
coe( /* Center of energy. */
const real *in, /* Sequence of coefficients. */
int alpha, /* First valid `in[]' index. */
int omega) /* Last valid `in[]' index. */
{
real center, energy;
int k;
assert(alpha <= 0); /* Conventional indexing. */
assert(0 <= omega); /* Conventional indexing. */
center = 0; energy = 0;
for( k=alpha; k<=omega; k++)
{
center += k*in[k]*in[k];
energy += in[k]*in[k];
}
if( energy>0 ) center /= energy;
return(center);
}
/*******************************************************************
* lphdev()
*
* Compute the maximum deviation from linear phase of the
* convolution-decimation operator associated to a sequence.
* Basic algorithm:
* Sum_{x>0} (-1)^x Sum_k k*in[k-x]*in[k+x]
* deviation = 2 * ----------------------------------------
* Sum_k in[k]^2
*
* Calling sequence:
* lphdev( in, alpha, omega )
*
* Inputs:
* (const real *)in The sequence is `in[alpha],...,in[omega]'
*
* (int)alpha These are to be the first and last valid
* (int)omega indices of the `pqf->f[]' struct member.
*
* Output:
* (real)lphdev This is the absolute value of the maximum.
*
* Assumptions:
* (1) Conventional indexing: `alpha <= 0 <= omega'.
*/
extern real
lphdev( /* Center of energy. */
const real *in, /* Sequence of coefficients. */
int alpha, /* First valid `in[]' index. */
int omega) /* Last valid `in[]' index. */
{
real energy, fx, deviation;
int k, x, sgn;
assert(alpha <= 0); /* Conventional indexing. */
assert(0 <= omega); /* Conventional indexing. */
/* First compute the sum of the squares of the sequence elements: */
energy = 0;
for( k=alpha; k0 )
{
sgn= -1;
for( x=1; x <= (omega-alpha)/2; x++ )
{
fx = 0;
for( k=x+alpha; k<=omega-x; k++ )
{
fx += k*in[k-x]*in[k+x];
}
deviation += sgn*fx;
sgn = -sgn;
}
deviation = absval(deviation);
deviation /= energy; /* Normalize. */
deviation *= 2; /* Final factor from the formula. */
}
/* If `energy==0' then `deviation' is trivially 0 */
return(deviation);
}
/***************************************************************
* periodize()
*
* Periodize an array into a shorter-length array.
*
* Calling sequence and basic algorithm:
*
* periodize(FQ, Q, F, ALPHA, OMEGA)
* For K = 0 to Q-1
* Let FQ[K] = 0
* Let J = (ALPHA-K)/Q
* While K+J*Q <= OMEGA
* FQ[K] += F[K+J*Q]
* J += 1
*
* Inputs:
* (real *)fq Preallocated array of length `q'.
* (int)q This is the period of `fq[]'.
* (const real *)f This array holds the original function.
* (int)alpha These are to be the first and last valid
* (int)omega indices of the array `f[]'.
*
* Output:
* (real *)fq The array `fq[]' is assigned as follows:
* fq[k] = f[k+j0*q]+...+f[k+j1*q],
* k = 0, 1, ..., q-1;
* j0 = ceil[(alpha-k)/q];
* j1 = floor[(omega-k)/q].
*
* Assumptions:
* (1) `omega-alpha >= q > 0',
* (2) `alpha <= 0 <= omega'
*/
static void
periodize(
real *fq, /* Preallocated output array. */
int q, /* Length of `fq[]'. */
const real *f, /* Input array. */
int alpha, /* First valid `f[]' index. */
int omega) /* Last valid `f[]' index. */
{
int j, k;
assert(q>0); /* Nontrivial period. */
assert(q<=omega-alpha); /* Periodization needed. */
assert(alpha <= 0); /* Conventional indexing. */
assert(0 <= omega); /* Conventional indexing. */
for(k=0; k