November 21, 2014
Hot Topics:

A General-Purpose LMS Adaptive Engine in Java

  • November 29, 2005
  • By Richard G. Baldwin
  • Send Email »
  • More Articles »

Complete Program Listings

Complete listings of the programs discussed in this lesson are shown in the listings below.
 
/*File AdaptEngine01.java
Copyright 2005, R.G.Baldwin

General purpose LMS adaptive algorithm.

An object of this class is a general purpose adaptive 
engine that implements the classical LMS adaptive 
algorithm.

The adaptive algorithm is implemented by the instance 
method belonging to the object named adapt.

Each time the adapt method is called, it receives one 
sample from each of two different time series.  One time 
series is considered to be the data that is to be filtered.
The other time series is considered to be a target.

The purpose of the adapt method is to adaptively create a 
convolution filter which, when applied to the data time 
series, will transform it into the target time series.

Each time the method is called, it performs a dot product 
between the current version of the filter and the contents 
of a delay line in which historical data samples have been 
saved. The result of that dot product is compared with the 
target sample to produce an error value. The error value is
produced by subtracting the value of the target sample from
the result of the dot product. The error value is then used
in a classical LMS adaptive algorithm to adjust the filter 
coefficients.

The objective is to produce a set of filter coefficients 
that will drive the error to zero over time.

This adaptive engine can be used as the solution to a 
variety of different signal processing problems, depending 
on the selection of time series that are provided as data 
and target.

The constructor for the class receives two parameters:
filterLength
feedbackGain

The filter length is used to construct two arrays.  One 
array is used later to contain the filter coefficients.

The other array is used later as a tapped delay line to 
contain the historical data samples and to precess them by
one element each time the method is called.

The feedback gain is used in the LMS adaptive algorithm to
compute the new filter coefficients.

Tested using J2SE 5.0 and WinXP.
**********************************************************/

class AdaptEngine01{
  
  double[] filterArray;//filter coefficients stored here
  double[] dataArray;//historical data is stored here
  double feedbackGain;//used in LMS adaptive algorithm
  
  //Constructor
  public AdaptEngine01(int filterLength,
                       double feedbackGain){
    //Construct the two arrays and save the feedback gain.
    filterArray = new double[filterLength];
    dataArray = new double[filterLength];
    this.feedbackGain = feedbackGain;
  }//end constructor
  //-----------------------------------------------------//
  
  //This method implements a classical LMS adaptive
  // algorithm to create and to apply a convolution filter.
  // The filter output, the error, and a reference to the
  // array containing the filter coefficients are 
  // encapsulated in an object of type AdaptiveResult and
  // returned to the calling method.
  AdaptiveResult adapt(double rawData,double target){
                        
    //Insert the incoming data value into the data delay
    // line.
    flowLine(dataArray,rawData);
  
    //Apply the current filter coefficients to the data.
    double output = dotProduct(filterArray,dataArray);
    //Compute the error.
    double err = output - target;

    //Use the error to update the filter coefficients.
    for(int ctr = 0;ctr < filterArray.length;ctr++){
      filterArray[ctr] -= err*dataArray[ctr]*feedbackGain;
    }//end for loop.

    //Construct and return an object containing the filter
    // output, the error, and a reference to the array
    // object containing the current filter coefficients.
    return new AdaptiveResult(filterArray,output,err);
  }//end adapt
  //-----------------------------------------------------//
  
  //This method simulates a tapped delay line. It receives
  // a reference to an array and a value.  It discards the
  // value at index 0 of the array, moves all the other
  // values by one element toward 0, and inserts the new
  // value at the top of the array.
  void flowLine(double[] line,double val){
    for(int cnt = 0;cnt < (line.length - 1);cnt++){
      line[cnt] = line[cnt+1];
    }//end for loop
    line[line.length - 1] = val;
  }//end flowLine
  //-----------------------------------------------------//
  
  //This method receives two arrays and treats the first N 
  // elements in each of the two arrays as a pair of
  // vectors.  It computes and returns the vector dot
  // product of the two vectors.  If the length of one
  // array is greater than the length of the other array,
  // it considers the number of dimensions of the vectors
  // to be equal to the length of the smaller array.
  double dotProduct(double[] v1,double[] v2){
    double result = 0;
    if((v1.length) <= (v2.length)){
      for(int cnt = 0;cnt < v1.length;cnt++){
        result += v1[cnt]*v2[cnt];
      }//emd for loop
      return result;
    }else{
      for(int cnt = 0;cnt < v2.length;cnt++){
        result += v1[cnt]*v2[cnt];
      }//emd for loop
      return result;
    }//end else
  }//end dotProduct
  //-----------------------------------------------------//
}//end class AdaptEngine01
//=======================================================//

//This class is used to encapsulate the adaptive results
// into an object for return to the calling method.
class AdaptiveResult{
  public double[] filterArray;
  public double output;
  public double err;
  
  //Constructor
  public AdaptiveResult(double[] filterArray,
                        double output,
                        double err){
    this.filterArray = filterArray;
    this.output = output;
    this.err = err;
  }//end constructor
}//end class AdaptiveResult
//=======================================================//

Listing 15

 

/*File Adapt06.java
Copyright 2005, R.G.Baldwin

The purpose of this program is to illustrate the use of the
general-purpose LMS adaptive engine named AdaptEngine01.

This is the simplest program that I was able to devise to 
illustrate the use of the adaptive engine. This program 
adaptively designs a convolution filter transforms a cosine
function into a sine function having the same amplitude and
frequency.

There are no input parameters.  Just compile and run.

The following time series are plotted in color showing the 
convergence of the adaptive algorithm:

black: input to the filter - the cosine function
red: output from the filter
blue: adaptive target - a sine function
green: error

The filter has two coefficients, each of which is 
initialized to a value of 0.

The final values of the two filter coefficients are
listed on the command-line screen. For the sinusoidal
frequencies used by the program, when the program is
allowed to run for 1000 iterations, the values for the two 
coefficients converge to:

1.4142064344006575
-0.9999927187203118

You might recognize that is the square root of two and
minus 1.  For other frequencies, the coefficients
converge to different values.

This program requires the following classes in addition
to Adapt06:

Adapt06.class
AdaptEngine01.class
AdaptiveResult.class
PlotALot05.class

Tested using J2SE 5.0 and WinXP. J2SE 5.0 or later is 
required.
**********************************************************/
import static java.lang.Math.*;//J2SE 5.0 req

class Adapt06{
  public static void main(String[] args){

    double feedbackGain = 0.0002;
    int numberIterations = 1000;
    int filterLength = 2;
 
    //Instantiate an object of the class and execute the
    // adaptive algorithm using the specified feedbackGain.
    new Adapt06().process(feedbackGain,
                          numberIterations,
                          filterLength);
  }//end main
  //-----------------------------------------------------//
  
  void process(double feedbackGain,
               int numberIterations,
               int filterLength){

    //Instantiate object of the adaptive engine to provide 
    //adaptive behavior for the program.
    AdaptEngine01 adapter = 
              new AdaptEngine01(filterLength,feedbackGain);

    //Instantiate a plotting object for four data channels.
    // This object will be used to plot the time series
    // data.
    PlotALot05 plotObj = new PlotALot05(
                           "Time Series",460,155,25,5,4,4);

    //Declare and initialize working variables.
    double output = 0;
    double err = 0;
    double target = 0;
    double input = 0;
    double dataScale = 20;//Default data scale
    
    //Do the iterative adaptive process
    AdaptiveResult result = null;
    for(int cnt = 0;cnt < numberIterations;cnt++){
      //Generate the data to be filtered and the adaptive
      // target on the fly.
      input = dataScale * cos(2*cnt*PI/8);
      target = dataScale * sin(2*cnt*PI/8);

      //Execute the adaptive behavior.
      result = adapter.adapt(input,target);
      
      //Get the results of the adaptive behavior for
      // plotting.
      err = result.err;
      output = result.output;

      //Feed the time series data to the plotting object.
      plotObj.feedData(input,output,target,err);
                  
    }//end for loop
    
    //Cause the data to be plotted.
    plotObj.plotData();
    
    //List the values of the filter coefficients.
    System.out.println("nFinal filter coefficients:");
    double[] filter = result.filterArray;
    for(int cnt = 0;cnt < filter.length;cnt++){
      System.out.println(filter[cnt]);
    }//end for loop
    
  }//end process method
  //-----------------------------------------------------//

}//end class Adapt06

Listing 16

 

/*File Adapt01a.java.java
Copyright 2005, R.G.Baldwin

This is an upgrade to the program named Adapt01.  The 
purpose of this upgrade is to use the adaptive engine
named AdaptEngine01 to provide the adaptive behavior of the
program and to clearly deliniate the code that controls the
adaptive behavior from the code that simply handles the 
data and displays the results.

As was the case with the earlier program named Adapt01,
this program illustrates one aspect of time-adaptive signal
processing.  However, this version of the program has been
greatly simplified by eliminating all but one of the
command-line parameters.

Two versions of the same sampled time series, one delayed
relative to the other, are presented to the an adaptive 
algorithm. The objective is to adaptively create a 
convolution filter that will delay the first time 
series to cause it to match up in time with the second
time series.  This results in a convolution filter having
a flat amplitude response and a linear phase response.

The user provides the following information as a command
line parameter:

timeDelay - This value causes the second time series to
be delayed relative to the first time series by from 0 to
8 samples.  Negative values and values greater than 8 cause
the program to terminate.

The following time series are plotted in color showing the 
convergence of the adaptive algorithm:
black: input to the filter
red: output from the filter
blue: adaptive target
green: error

In addition, the frequency response of the filter at the 
end of every tenth iteration is computed and displayed when
the adaptive process terminates.  Both the amplitude and 
the phase response of the filter are computed and plotted.
Also, the convolution filter is plotted as a time series on
the same  iterations that the frequency response is 
computed.  Thus, the shape of the convolution filter can be
compared with the frequency response of the filter.

The filter is initialized with values of 0 for all
coefficients.  The ideal solution is a single coefficient 
value of 1 at a location in the filter that matches the 
time delay between the two time series along with a linear
phase response that matches the location of the single
filter coefficient.

Tested using J2SE 5.0 and WinXP. J2SE 5.0 or later is 
required.
**********************************************************/
import static java.lang.Math.*;//J2SE 5.0 req

class Adapt01a{
  public static void main(String[] args){
    //Default value for time delay input parameter.
    int timeDelay = 7;
    
    //Fixed values.
    double feedbackGain = 0.001;
    int numberIterations = 100;
    
    //Deal with command-line parameter.
    if(args.length != 1){
      System.out.println("Usage: java Adapt01a " +
                                              "timeDelay");
    }else{//Command line param was provided.
      //Convert String to int
      timeDelay = Integer.parseInt(args[0]);
      System.out.println("timeDelay: " + timeDelay);
    }//end else
    
    if((timeDelay > 8) || (timeDelay < 0)){
      System.out.println(
                       "Time delay must be >= 0 and <= 8");
      System.out.println("Terminating");
      System.exit(0);
    }//end if
   
    //Instantiate an object of the class and execute the
    // adaptive algorithm using the  specified feedbackGain
    // and other parameters.
    new Adapt01a().process(timeDelay,
                           feedbackGain,
                           numberIterations);
  }//end main
  //-----------------------------------------------------//
  
  void process(int timeDelay,
               double feedbackGain,
               int numberIterations){

    int filterLength = 9;
    
    //Instantiate object of the adaptive engine to provide 
    //adaptive behavior for the program.
    AdaptEngine01 adapter = 
              new AdaptEngine01(filterLength,feedbackGain);
    
    //The filter array is created and maintained within the
    // adaptive engine object. A reference to the array is 
    // returned by the adapt method.
    double[] filter;
    
    //Create array object that will be used as delay line.
    double[] rawData = new double[9];
    
    //Instantiate a plotting object for four data channels.
    // This object will be used to plot the time series
    // data.
    PlotALot05 plotObj = new PlotALot05(
                           "Time Series",398,250,25,5,4,4);
            
    //Instantiate a plotting object for two channels of 
    // filter frequency response data.  One channel is used
    // to plot the amplitude response in db and the other 
    // channel is used to plot the phase on a scale that
    // extends from -180 degrees to +180 degrees.
    PlotALot03 freqPlotObj = 
                   new PlotALot03("Freq",264,487,20,2,0,0);
    
    //Instantiate a plotting object to display the filter
    // as a short time series at intervals during the
    // adaptive  process.
    //Note that the minimum allowable width for a Frame is
    // 112 pixels under WinXP. Therefore, the following
    // display doesn't synchronize properly for filter
    // lengths less than 25 coefficients.  However, the 
    // code that feeds the filter data to the plotting
    // object later in the program extends the length of
    // the filter to cause it to synchronize and to plot
    // one set of filter coefficients on each axis.
    PlotALot01 filterPlotObj = new PlotALot01(
            "Filter",(filterLength * 4) + 8,487,40,4,0,0);

    //Declare and initialize working variables.
    double output = 0;
    double err = 0;
    double target = 0;
    double input = 0;
    double dataScale = 20;//Default data scale
    
    //Do the iterative adaptive process
    for(int cnt = 0;cnt < numberIterations;cnt++){
      
      //Add new input data to the delay line containing the
      // raw input data.  Raw data values are uniformly 
      // distributed from -10.0 to +10.0.
      flowLine(rawData,dataScale*(random() - 0.5));
      
      //Get the raw input data from the end of the delay
      // line.
      input = rawData[8];
      
      //Get the target data from one of nine available taps
      // on the delay line.
      target = rawData[8 - timeDelay];
      
      //Execute the adaptive behavior.
      AdaptiveResult result = adapter.adapt(input,target);
      
      //Get the results of the adaptive behavior for
      // plotting and frequency response analysis.
      filter = result.filterArray;
      err = result.err;
      output = result.output;

      //Feed the time series data to the plotting object.
      plotObj.feedData(input,output,target,err);
                  
      //Compute and plot the frequency response and plot
      // the filter as a time series every 10 iterations.
      if(cnt%10 == 0){
        displayFreqResponse(filter,
                            freqPlotObj,
                            128,
                            filter.length - 1);
      
        //Plot the filter coefficient values. Scale the
        // coefficient values by 30 to make them compatible
        // with the  plotting software.
        for(int ctr = 0;ctr < filter.length;ctr++){
          filterPlotObj.feedData(30*filter[ctr]);
        }//end for loop

        //Extend the filter with a value of 2.5 for
        // plotting purposes only to cause it to
        // synchronize with one filter being plotted on
        // each axis.
        if(filter.length <= 26){
          for(int count = 0;count < (26 - filter.length);
                                                  count++){
            filterPlotObj.feedData(2.5);
          }//end for loop
        }//end if
      }//end if on cnt%10
                  
    }//end for loop
    
    //Cause all the data to be plotted in the
    // screen locations specified.
    plotObj.plotData();
    filterPlotObj.plotData(0,201);
    freqPlotObj.plotData(112,201);
    
  }//end process
  //-----------------------------------------------------//
  
  //This method simulates a tapped delay line.
  // It receives a reference to an array and
  // a value.  It discards the value at
  // index 0 of the array, moves all the other
  // values by one element toward 0, and 
  // inserts the new value at the top of the
  // array.
  void flowLine(double[] line,double val){
    for(int cnt = 0;cnt < (line.length - 1);
                                          cnt++){
      line[cnt] = line[cnt+1];
    }//end for loop
    line[line.length - 1] = val;
  }//end flowLine
  //-----------------------------------------------------//

  //This method receives a reference to a double
  // array containing a convolution filter 
  // along with a reference to a plotting object
  // capable of plotting two channels of data.
  // It also receives a value specifying the
  // number of frequencies at which a DFT is
  // to be performed on the filter, along with
  // the sample number that represents the zero
  // time location in the filter.  The method
  // uses this information to perform a DFT on
  // the filter from zero to the folding 
  // frequency.  It feeds the amplitude spectrum
  // and the phase spectrum to the plotting
  // object for plotting.
  void displayFreqResponse(double[] filter,
                           PlotALot03 plot,
                           int len,
                           int zeroTime){

    //Create the arrays required by the Fourier 
    // Transform.
    double[] timeDataIn = new double[len];
    double[] realSpect = new double[len];
    double[] imagSpect = new double[len];
    double[] angle = new double[len];
    double[] magnitude = new double[len];
    
    //Copy the filter into the timeDataIn array.
    System.arraycopy(filter,0,timeDataIn,0,
                                  filter.length);

    //Compute DFT of the filter from zero to the
    // folding frequency and save it in the
    // output arrays.
    ForwardRealToComplex01.transform(timeDataIn,
                                     realSpect,
                                     imagSpect,
                                     angle,
                                     magnitude,
                                     zeroTime,
                                     0.0,
                                     0.5);
                                     

    //Plot the magnitude data.  Convert to 
    // normalized decibels before plotting.
    
    //Eliminate or change all values that are
    // incompatible with log10 method.
    for(int cnt = 0;cnt < magnitude.length;
                                          cnt++){
      if((magnitude[cnt] == Double.NaN) || 
                          (magnitude[cnt] <= 0)){
        magnitude[cnt] = 0.0000001;
      }else if(magnitude[cnt] == 
                       Double.POSITIVE_INFINITY){
        magnitude[cnt] = 9999999999.0;
      }//end else if
    }//end for loop
    
    //Now convert magnitude data to log base 10
    for(int cnt = 0;cnt < magnitude.length;
                                          cnt++){
      magnitude[cnt] = log10(magnitude[cnt]);
    }//end for loop
    
    //Note that from this point forward, all
    // references to magnitude are referring to
    // log base 10 data, which can be thought of
    // as scaled decibels.

    //Find the absolute peak value
    double peak = -9999999999.0;
    for(int cnt = 0;cnt < magnitude.length;
                                          cnt++){
      if(peak < abs(magnitude[cnt])){
        peak = abs(magnitude[cnt]);
      }//end if
    }//end for loop

    //Normalize to 50 times the peak value and
    // shift up the screen by 50 units to make
    // the values compatible with the plotting
    // program.  Recall that adding a constant to
    // log values is equivalent to scaling the
    // original data.
    for(int cnt = 0;cnt < magnitude.length;
                                          cnt++){
      magnitude[cnt] = 
                     50*magnitude[cnt]/peak + 50;
    }//end for loop

    //Now feed the normalized decibel data to the
    // plotting object.  The angle data rangers
    // from -180 to +180.  Scale it down by a
    // factor of 20 to make it compatible with
    // the plotting format being used.
    for(int cnt = 0;cnt < magnitude.length;
                                          cnt++){
      plot.feedData(
                   magnitude[cnt],angle[cnt]/20);
    }//end for loop
    
  }//end displayFreqResponse
  //-------------------------------------------//
}//end class Adapt01a

Listing 17

 

/*File Adapt02a.java.java
Copyright 2005, R.G.Baldwin

This program is an update of the program named Adapt01. The
purpose of the update is to delegate the adaptive behavior
of the program to an object of the class named 
AdaptEngine02, clearly deliniating between that portion of 
the program that provides adaptive behavior and that 
portion that simply does data handling and displays 
results.

This program has been simplified relative to the program
named Adapt02 by eliminating all command-line parameters.

This program illustrates one aspect of time-adaptive signal
processing.  

This program implements a time-adaptive whitening filter 
using a predictive approach. The program input is a time 
series consisting of a wide band signal plus two sinusoidal
noise functions. The program adaptively creates a filter 
that attempts to eliminate the sinusoidal noise while 
preserving the wide band signal.

The following time series are displayed when the program 
runs:

-err: This is the negative of the output from the whitening
filter.  Ideally this time series contains the wide band 
signal with the sinusoidal noise having been removed.

signal: The raw wideband signal consisting of samples taken
from a random noise generator.

sineNoise: The raw noise consisting of the sum of two
sinusoidal functions.

input: The sum of the signal plus the sinusoidal noise.

output: The output produced by applying the prediction 
filter to the input signal plus noise.

target: The target signal that is used to control the 
adaptive process. This is the next sample beyond the 
samples that are processed by the prediction filter. In
other words, the prediction filter attempts to predict this
value. Thus, the adaptive process attempts to cause  the 
output from the prediction filter to match the next sample 
in the incoming signal plus noise.  This is an attempt to 
predict a future value based solely on the current and past
values.

Although not required by the adaptive process, the 
frequency response of the whitening filter is computed and 
displayed once every 100 iterations.  Ideally the amplitude
response is flat with very narrow notches at the 
frequencies of the interfering sinusoidal noise components.
Both the amplitude and phase response are displayed. This 
makes it possible to see the notches develop in the 
frequency response of the whitening filter as it converges.
It also makes it possible to see how the phase behaves at
the notches.

The individual whitening filters on which the frequency 
response is computed are also displayed as time series.

USAGE: Just compile and run the program.  There are no
user inputs.  The program uses fixed values for the 
following:

feedbackGain: The gain factor that is used in the feedback 
loop to adjust the coefficient values in the 
prediction/whitening filter. (A whitening filter is a 
prediction filter with a -1 appended to its end.)

numberIterations: The is the number of iterations that the 
program executes before stopping and displaying all of the 
graphic results.

pFilterLength: This is the number of coefficients 
in the prediction filter.

signalScale: A scale factor that is applied to the wide 
band signel provided by the random noise generator. The 
random noise generator produces uniformaly distributed 
values ranging from -0.5 to +0.5.

noiseScale: A scale factor that is applied to each of the 
sinusoidal noise functions before they are added to the 
signal. The raw sinusoids vary from -1.0 to +1.0.

Tested using J2SE 5.0 and WinXP.  J2SE 5.0 or later is 
required.
**********************************************************/
import static java.lang.Math.*;//J2SE 5.0 req

class Adapt02a{
  public static void main(String[] args){
    //Default parameter values
    double feedbackGain = 0.00001;
    int numberIterations = 600;
    int pFilterLength = 26;
    double signalScale = 20;
    double noiseScale = 20;

    //Instantiate a new object of the Adapt02a class
    // and invoke the method named process on that object.
    new Adapt02a().process(feedbackGain,
                          numberIterations,
                          pFilterLength,
                          signalScale,
                          noiseScale);
  }//end main
  //-----------------------------------------------------//
  
  //This is the primary adaptive processing and plotting
  // method for the program.
  void process(double feedbackGain,
               int numberIterations,
               int pFilterLength,
               double signalScale,
               double noiseScale){

    double[] pFilter;
    
    //Instantiate an object to handle the adaptive behavior
    // of the program.
    AdaptEngine01 adapter = new AdaptEngine01(
                               pFilterLength,feedbackGain);

    //Create the initial whiteningFilter and initialize it.
    double[] whiteningFilter = 
                   new double[pFilterLength + 1];

    //Set the final value in the whitening filter to -1.
    whiteningFilter[whiteningFilter.length - 1] = -1;
    
    //Create an array to serve as a two-sample delay line
    // for the raw data.  The data value at zero index will
    // be the data is to be filtered.  The data value at
    // index value 1 will be the predictive target.
    double[] rawData = new double[2];
  
    //Instantiate a plotting object for six channels of
    // time-serie data.
    PlotALot07 timePlotObj = 
                  new PlotALot07("Time",468,200,25,10,4,4);
            
    //Instantiate a plotting object for two channels of
    // filter frequency response data.  One channel is for
    // the amplitude and the other channel is the phase.
    PlotALot03 freqPlotObj = 
                   new PlotALot03("Freq",264,487,35,2,0,0);
    
    //Instantiate a plotting object to display the
    // whitening filter at specific time intervals during
    // the adaptive process.
    PlotALot01 filterPlotObj = new PlotALot01("Filter",
            (whiteningFilter.length * 4) + 8,487,70,4,0,0);
   
    //Declare and initialize working variables.
    double output = 0;
    double err = 0;
    double target = 0;
    double input = 0;
    double signal = 0;
    double sineNoise = 0;
    
    //Perform the specified number of iterations.
    for(int cnt = 0;cnt < numberIterations;cnt++){
      //Get the next sample of wideband signal.
      signal = signalScale*(Math.random() - 0.5);
      
      //Get the next sample of sinusoidal noise consisting
      // of two sinusoids at different frequencies.
      sineNoise = noiseScale*(Math.sin(2*cnt*PI/8) +
                              Math.sin(2*cnt*PI/3));

      //Insert the signal plus noise into the raw data
      // delay line.
      flowLine(rawData,signal + sineNoise);
      
      //Execute the adaptive behavior.
      AdaptiveResult result = adapter.adapt(rawData[0],
                                               rawData[1]);

      //Get and save adaptive results for plotting and
      // spectral analysis
      output = result.output;
      err = result.err;
      pFilter = result.filterArray;
      
      //Feed the time series data to the plotting object.
      timePlotObj.feedData(-err,signal,sineNoise,
                             rawData[0],output,rawData[1]);
      
      //Compute and plot the frequency response and plot
      // the whitening filter every 100 iterations.
      if(cnt%100 == 0){
        //Create a whitening filter from the data in the
        // prediction filter by copying the prediction
        // filter into the bottom elements of the whitening
        // filter. Recall that the last element in the
        // whitening filter already has a value of -1.
        System.arraycopy(pFilter,
                         0,
                         whiteningFilter,
                         0,
                         pFilter.length);

        displayFreqResponse(whiteningFilter,freqPlotObj,
                           128,whiteningFilter.length - 1);

        //Display the whitening filter coefficient values.
        for(int ctr = 0;ctr < whiteningFilter.length;
                                                    ctr++){
          filterPlotObj.feedData(40*whiteningFilter[ctr]);
        }//end for loop
      }//End display of frequency response and whitening
       // filter
    }//End for loop,
    
    //Cause all the data to be plotted.
    timePlotObj.plotData();
    freqPlotObj.plotData(0,201);
    filterPlotObj.plotData(265,201);
    
  }//end process method
  //-----------------------------------------------------//
  
  //This method simulates a tapped delay line. It receives
  // a reference to an array and a value.  It discards the
  // value at index 0 of the array, moves all the other
  // values by one element toward 0, and inserts the new
  // value at the top of the array.
  void flowLine(double[] line,double val){
    for(int cnt = 0;cnt < (line.length - 1);cnt++){
      line[cnt] = line[cnt+1];
    }//end for loop
    line[line.length - 1] = val;
  }//end flowLine
  //-----------------------------------------------------//
 
  void displayFreqResponse(
     double[] filter,PlotALot03 plot,int len,int zeroTime){

    //Create the arrays required by the Fourier Transform.
    double[] timeDataIn = new double[len];
    double[] realSpect = new double[len];
    double[] imagSpect = new double[len];
    double[] angle = new double[len];
    double[] magnitude = new double[len];
    
    //Copy the filter into the timeDataIn array
    System.arraycopy(filter,0,timeDataIn,0,filter.length);

    //Compute DFT of the filter from zero to the folding
    // frequency and save it in the output arrays.
    ForwardRealToComplex01.transform(timeDataIn,
                                     realSpect,
                                     imagSpect,
                                     angle,
                                     magnitude,
                                     zeroTime,
                                     0.0,
                                     0.5);

    //Display the magnitude data. Convert to normalized
    // decibels first.
    //Eliminate or change any values that are incompatible
    // with log10 method.
    for(int cnt = 0;cnt < magnitude.length;cnt++){
      if((magnitude[cnt] == Double.NaN) || 
                                    (magnitude[cnt] <= 0)){
        //Replace the magnitude by a very small positive
        // value.
        magnitude[cnt] = 0.0000001;
      }else if(magnitude[cnt] == Double.POSITIVE_INFINITY){
        //Replace the magnitude by a very large positive
        // value.
        magnitude[cnt] = 9999999999.0;
      }//end else if
    }//end for loop
    
    //Now convert magnitude data to log base 10
    for(int cnt = 0;cnt < magnitude.length;cnt++){
      magnitude[cnt] = log10(magnitude[cnt]);
    }//end for loop
  
    //Note that from this point forward, all references to
    // magnitude are referring to log base 10 data, which
    // can be thought of as scaled decibels.

    //Find the absolute peak value.  Begin with a negative
    // peak value with a large magnitude and replace it
    // with the largest magnitude value.
    double peak = -9999999999.0;
    for(int cnt = 0;cnt < magnitude.length;cnt++){
      if(peak < abs(magnitude[cnt])){
        peak = abs(magnitude[cnt]);
      }//end if
    }//end for loop

    //Normalize to 50 times the peak value and shift up the
    // page by 50 units to make the values compatible with
    // the plotting program.  Recall that adding a
    // constant to log values is equivalent to scaling the
    // original data.
    for(int cnt = 0;cnt < magnitude.length;cnt++){
      magnitude[cnt] = 50*magnitude[cnt]/peak + 50;
    }//end for loop

    //Now feed the normalized decibel data to the plotting
    // system.
    for(int cnt = 0;cnt < magnitude.length;cnt++){
      plot.feedData(magnitude[cnt],angle[cnt]/20);
    }//end for loop
    
  }//end displayFreqResponse
  //-----------------------------------------------------//
}//end class Adapt02a

Listing 18


Copyright 2005, Richard G. Baldwin.  Reproduction in whole or in part in any form or medium without express written permission from Richard Baldwin is prohibited.

About the author

Richard Baldwin is a college professor (at Austin Community College in Austin, TX) and private consultant whose primary focus is a combination of Java, C#, and XML. In addition to the many platform and/or language independent benefits of Java and C# applications, he believes that a combination of Java, C#, and XML will become the primary driving force in the delivery of structured information on the Web.

Richard has participated in numerous consulting projects and he frequently provides onsite training at the high-tech companies located in and around Austin, Texas.  He is the author of Baldwin's Programming Tutorials, which have gained a worldwide following among experienced and aspiring programmers. He has also published articles in JavaPro magazine.

In addition to his programming expertise, Richard has many years of practical experience in Digital Signal Processing (DSP).  His first job after he earned his Bachelor's degree was doing DSP in the Seismic Research Department of Texas Instruments.  (TI is still a world leader in DSP.)  In the following years, he applied his programming and DSP expertise to other interesting areas including sonar and underwater acoustics.

Richard holds an MSEE degree from Southern Methodist University and has many years of experience in the application of computer technology to real-world problems.

Baldwin@DickBaldwin.com





Page 2 of 2



Comment and Contribute

 


(Maximum characters: 1200). You have characters left.

 

 


Enterprise Development Update

Don't miss an article. Subscribe to our newsletter below.

Sitemap | Contact Us

Rocket Fuel