Friday, April 1, 2016

Removing Fast Variations from 1D Signals with CDF(4, 4) and HWT: Programmatic Note 16 on Ripples in Mathematics




Problem
  
This is my programmatic note 16 on Ch. 04, p. 31-34, in "Ripples in Mathematics" by A. Jensen & A. la Cour-Harbo. These notes document my programmatic journey, sometimes easy, sometimes painful, but always joyful, through this great text. My notes are for those who want to use Java as a programming investigation tool of various wavelet algorithms and Octave for plotting the results. You can find my previous notes by searching my blog on "ripples in mathematics." If you are on the same journey, let me know of any bugs in my code or improvements you have found that let us all, fellow travelers on the wavelet road, get better and more beautiful results.

In this note, I will consider a programmatic approach to removing fast variations from 1D signals. One way to remove fast variations is to use the multi-resolution analysis. The higher the number of iterations, the smoother the signal reconstruction from the scale coefficients. Another way is to process the signal to keep the fast variations and then subtract the fast variations from the original signal. This latter approach is the subject of this post.

Keeping Fast and Slow Variations


I added a static method genericKeepFastVarsInSignal() which implements the following method. Given a 1D signal of size n and number of scales, i.e., num_scales, a DWT is applied for that number of scales. A signal reconstruction is obtained from the scaler values of the signal transform after the final scale. Finally, the signal reconstruction is subtracted from the original signal to remove fast variations .

public static void genericKeepFastVarsInSignal(double[] signal, ApplyDWT.DWT dwt, int num_iters) {
        // signal_transform holds the DWT transform of signal_tranform of ApplyDWT.DWT
        double[] signal_transform           = new double[signal.length];
        // - signal_with_filtered_range holds the slow variations filtered from the signal
        // transform in the required range [range_start, range_end];
        // - the reconstructed signal is reconstructed from filtered_range_from_signal_transform.
        double[] filtered_range_from_signal_transform = new double[signal.length];
       
        // 0. copy signal into signal_transform.
        System.arraycopy(signal, 0, signal_transform, 0, signal_transform.length);
        // 1. apply forward DWT to signal.
        forwardDWTForNumIters(signal_transform, dwt, num_iters);
        // 2. filter the required range from signal transform into filtered_range_from_signal_transform;
        //    filtered_range_from_signal_transform contains slow variations.
        final int range_end = (signal.length/((int)Math.pow(2, num_iters)) - 1);
        //System.out.println("range end == " + range_end);
        filterSignalRange(signal_transform, filtered_range_from_signal_transform, 0, range_end);
        // 3. reconstruct signal from slow variations for the same number of iterations
        inverseDWTForNumIters(filtered_range_from_signal_transform, dwt, num_iters);
        // 4. subtract the reconstructed signal from the original signal to keep the fast variations;
        //    fast variations = original signal - signal reconstructed from slow variations.
        subtractSignals(signal, filtered_range_from_signal_transform);
        filtered_range_from_signal_transform = null;
        signal_transform = null;

}


Once there is a way to keep fast variations in the signal, it is possible to write a method that gets the fast variations from the signal and then subtracts them from the original signal, thereby keeping the slower variations.


public static void genericKeepSlowVarsInSignal(double[] signal, ApplyDWT.DWT dwt, int num_iters) {
        double[] signal_copy = new double[signal.length];
        System.arraycopy(signal, 0, signal_copy, 0, signal.length);
        genericKeepFastVarsInSignal(signal_copy, dwt, num_iters);
        ApplyDWT.subtractSignals(signal, signal_copy);

}

Experiments


I wrote several methods to apply this analysis to the function graphed in Fig. 4.12 on p. 33 in Ripples shown in Figure 1.

Figure 1. Fig. 4.12 on p. 33 in Ripples

Here are the three methods I added to RipplesInMathCh04.java.

static void keep_slow_vars_in_fig_4_12_aux(double[] signal, ApplyDWT.DWT dwt, int num_iters) {
        ApplyDWT.genericKeepSlowVarsInSignal(signal, dwt, num_iters);
}
   
 static void keep_slow_vars_in_fig_4_12_cdf44(int num_iters) {
        fig_4_12_p33();
        keep_slow_vars_in_fig_4_12_aux(sRangeFig_4_12_p33, ApplyDWT.DWT.CDF44, num_iters);
        System.out.println("======");
        display_signal(sRangeFig_4_12_p33);
 }
    

static void keep_slow_vars_in_fig_4_12_hwt(int num_iters) {
        fig_4_12_p33();
        keep_slow_vars_in_fig_4_12_aux(sRangeFig_4_12_p33, ApplyDWT.DWT.HWT, num_iters);
        System.out.println("======");
        display_signal(sRangeFig_4_12_p33);

}



Figures 2 and 3 show the graphs obtained by keeping the slow variations with CDF(2, 2).  Figure 2 gives the graph from the values computed with keep_slow_vars_in_fig_4_12_cdf44(2). Figure 3 gives the graph from the values computed with keep_slow_vars_in_fig_4_12_cdf44(5).

Figure 2. Values from keep_slow_vars_in_fig_4_12_cdf44(2) graphed with Octave

Figure 3. Values from keep_slow_vars_in_fig_4_12_cdf44(5) graphed with Octave

Figures 4 and 5 show the graphs obtained by keeping the slow variations with HWT. Figure 4 gives the graph from the values computed with keep_slow_vars_in_fig_4_12_hwt(2). Figure 5 gives the graph from the values computed with keep_slow_vars_in_fig_4_12_hwt(5)

Figure 4. Values from keep_slow_vars_in_fig_4_12_hwt(5) graphed with Octave


Figure 5. Values from keep_slow_vars_in_fig_4_12_hwt(5) graphed with Octave