Wednesday, September 9, 2015

Computing & Plotting 3 Scales of the 1D Ordered Haar Wavelet Transform of a Sinusoid Curve: Programmatic Note 2 on Ripples in Mathematics




Introduction
  
This is a short programmatic note on Ch. 04, pp. 25 - 27, in "Ripples in Mathematics" by A. Jensen & A. la Cour-Harbo. May the beauty and harmony of this text be conveyed to the readers of this post. These notes are written for those who want to use Java as a programming investigation tool of various wavelet algorithms and Octave to plot the results. I have found this combination of tools to be very useful in my investigations, primarily because both Java and Octave are free. You can find my other 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 get the results in a better way.

The problem addressed in this post is formulated on p. 25 in "Ripples in Mathematics." The function y = sin(4*pi*t), where t is in [0, 1] is sampled at 512 equidistant points, which gives a discrete signal s9. The index 9, in the formalism adopted in the book, stands for the power of 2 equal to the number of samples in the signal, i.e., 512 = 2^9. This signal is plotted in Figure 4.1 on p. 26. The 1D ordered HWT is applied to this signal over three different scales, i.e., three iterations. The wavelet coefficients are combined into a 1D array in the following order s6, d6, d7, and d8, where d8 is the 1st scale wavelet coefficients, i.e., the wavelet coefficients obtained after the 1st application of the 1D ordered HWT, d7 are the 2nd scale wavelet coefficients (2nd application of the 1D ordered HWT), d6 are the the 3rd scale wavelet coefficients (3rd application of the 1D ordered HWT), and s6 are the averages obtained after the 3rd application of the 1D ordered HWT. This combined array is plotted in Figure 4.2 on p. 26. Figure 4.3 on p. 27 plots s6, d6, d7, d8 individually.

Computing the Signal and Wavelet Coefficients in Java


I defined a Java class Ripples_F_p25.java that extends my Function.java class. 

public class Ripples_F_p25 extends Function {
   
    public Ripples_F_p25() {}
    @Override
    public double v(double x) { return Math.sin(4*Math.PI*x/512.0); }
}


Then I defined  RipplesMathCh04.java and used my Partition.java to compute the domain of the sin(4*pi*t/512), apply Ripples_F_p25 to it, and display the range. I defined several static methods (see below): fig_4_1_p26() , fig_4_2_p26() , fig_4_3_d8_p27(),  fig_4_3_d7_p27() , fig_4_3_d6_p27() , and fig_4_3_s6_p27().  These methods compute the ranges for Figures 4.1, 4.2, and 4.3 on pages 26 and 27, respectively, in the book. The methods use several methods of my OneDHaar class to compute the normalized forward and inverse 1D ordered HWTs.
  
public class RipplesInMathCh04 {
  
    public enum SIGNAL { D8, D7, D6, S6 };
  
    static double[] sDomain = Partition.partition(0, 511, 1);
    static double[] sRange  = new double[512];
    static Ripples_F_p25 sRipples_F_p25 = new Ripples_F_p25();
  
    static final int D8_START   = 256;
    static final int D8_END     = 511;
    static final int D7_START   = 128;
    static final int D7_END     = 255;
    static final int D6_START   = 64;
    static final int D6_END     = 127;
    static final int S6_START   = 0; 
    static final int S6_END     = 63;
  
    // prints the range values for the plot in Fig. 4.1, p. 26
    // in "Ripples in Mathematics."
    static void fig_4_1_p26() {
      
        for(int i = 0; i < 512; i++)  {
            sRange[i] = sRipples_F_p25.v(sDomain[i]);
        }
      
        display_signal(sRange);
    }
    // prints the range values for the plot in Fig. 4.2, p.26
    // in "Ripples in Mathematics."
    static void fig_4_2_p26() {
      
        for(int i = 0; i < 512; i++)  {
            sRange[i] = sRipples_F_p25.v(sDomain[i]);
        }
      
        OneDHaar.orderedNormalizedFastHaarWaveletTransformForNumIters(sRange, 3);
      
        for(int i = 0; i < 512; i++)  {
            System.out.println(sRange[i]);
        }
    }
  
    // d8 range values for Fig. 4.3, p. 27 in "Ripples in Mathematics."
    static void fig_4_3_d8_p27() {
      
        for(int i = 0; i < 512; i++)  {
            sRange[i] = sRipples_F_p25.v(sDomain[i]);
        }
      
        OneDHaar.orderedNormalizedFastHaarWaveletTransformForNumIters(sRange, 3);
        display_signal_range(sRange, D8_START, D8_END);
    }
  
    // d7 range values for Fig. 4.3, p. 27 in "Ripples in Mathematics."
    static void fig_4_3_d7_p27() {
      
        for(int i = 0; i < 512; i++)  {
            sRange[i] = sRipples_F_p25.v(sDomain[i]);
        }
      
        OneDHaar.orderedNormalizedFastHaarWaveletTransformForNumIters(sRange, 3);
        display_signal_range(sRange, D7_START, D7_END);
    }
  
    // d6 range values for Fig. 4.3, p. 27 in "Ripples in Mathematics."
    static void fig_4_3_d6_p27() {
      
        for(int i = 0; i < 512; i++)  {
            sRange[i] = sRipples_F_p25.v(sDomain[i]);
        }
      
        OneDHaar.orderedNormalizedFastHaarWaveletTransformForNumIters(sRange, 3);
        display_signal_range(sRange, D6_START, D6_END);
    }
  
    // s6 range values for Fig. 4.3, p. 27 in "Ripples in Mathematics."
    static void fig_4_3_s6_p27() {
      
        for(int i = 0; i < 512; i++)  {
            sRange[i] = sRipples_F_p25.v(sDomain[i]);
        }
      
        OneDHaar.orderedNormalizedFastHaarWaveletTransformForNumIters(sRange, 3);
        display_signal_range(sRange, S6_START, S6_END);
    }
}




Plotting Java Numbers in Octave


I copied the numbers computed by the above functions from the Java console and pasted them into two Octave scripts ripples_p26.m  and ripples_p27.m that plot the figures on pp 26 and 27 in the book.  The plots produced by these scripts are given below.