Applet has opened a second browser window to display tutorial - 
   close the window to return to the applet menus.
If tutorial was entered from the HTML list - use GO-BACK to 
   reurn to the list. 
------------------------------------------------------------
        Processing Algorithm for Viewing

The viewable code contains the classes used to calculate
white noise described in the on-line tutorial.  It lacks 
the main shell applet from which it is called.  You can 
request the fully runnable version of the java file by 
e-mail (jgiannini@psu.edu).
------------------------------------------------------
//===================================
// Interface for global constants
//===================================
interface GlobalConstants
{
    // Max size of arrays
    static final int TOTAL_POINTS = 512;
    static final int NO_SEGMENTS = 8;
    static final int NO_TRANSFORM_POINTS = TOTAL_POINTS/NO_SEGMENTS;
    static final int NO_PSD_POINTS = 1+(NO_TRANSFORM_POINTS/2);
    static final int FINAL_PSD_POINTS = 1+(TOTAL_POINTS/2);
    static final int AVE_PTS = 32;

}  // end Interface GlobalConstnats -----------------------

//===================================
// Classes to Implement GFO Algorithm
//===================================

class GFOAlgo implements GlobalConstants
{
    // local array to hold transform input
    private double[] input_real = new double[NO_TRANSFORM_POINTS];
    private double[] input_imag = new double[NO_TRANSFORM_POINTS];
    private double[] output_real = new double[NO_TRANSFORM_POINTS];
    private double[] output_imag = new double[NO_TRANSFORM_POINTS];
    private double[] PSD = new double[NO_PSD_POINTS];
    private double[] ave_PSD = new double[NO_PSD_POINTS];
    private double[] final_PSD = new double[FINAL_PSD_POINTS];
    private double[] transform_freq = new double[FINAL_PSD_POINTS];
    private double altimeter_PSD = 0.0;
    private double altimeter_noise = 0.0;
    private TransformUtilities transform_utilities;
    private Applet main_applet;

    GFOAlgo(Applet in_applet)
    {
        main_applet = in_applet;
        transform_utilities = new TransformUtilities();

        for(int i=0;i<NO_TRANSFORM_POINTS;i++)	// N=64
        {
	      input_real[i]= 0.0;
	      input_imag[i]= 0.0;
	      output_real[i]= 0.0;
	      output_imag[i]= 0.0;
        } // end for i initializing transform

        for(int i=0;i<NO_PSD_POINTS;i++)	 // N/2 + 1 = 33
        {
            PSD[i] = 0.0;
            ave_PSD[i] = 0.0;
        } // end for i initializing PSD

        for(int i=0;i<FINAL_PSD_POINTS; i++)	// TOTAL_POINTS/2 + 1 = 257
        {
            final_PSD[i]= 0.0;
            transform_freq[i]= 0.0;
        }

    }  // end constructor GFOAlgo()

    public void compute_transform(DataMgr in_data_mgr)
    {
        double PSD_sum = 0.0;
        int data_index = 0;
        double series_sum = 0.0;
        double tail_PSD = 0.0;

        main_applet.showStatus("in compute_transform");

        for(int i=0;i<NO_PSD_POINTS;i++)	 // N/2 + 1 = 33
        {
            PSD[i] = 0.0;
            ave_PSD[i] = 0.0;
        } // end for i initializing PSD

        for(int i=0;i<NO_SEGMENTS;i++)
        {
            for(int j=0;j<NO_TRANSFORM_POINTS;j++)
            { 
                data_index= i*NO_TRANSFORM_POINTS + j;
                input_real[j] = 
	               in_data_mgr.transform_input.read_alt_h(data_index);
                // input_imag[i] = 0.0 for all i
            }

            transform_utilities.discrete_transform(input_real,
		          input_imag,output_real,output_imag,in_data_mgr);
 
            // do the PSD
            transform_utilities.PSD(output_real,output_imag,PSD);
            for(int k=0;k<NO_PSD_POINTS;k++)
	               ave_PSD[k] = ave_PSD[k] + PSD[k]/(double)NO_SEGMENTS;
	  
        } // end for i = number segments

        PSD_sum = 0.0;
        for(int i=0;i<NO_PSD_POINTS;i++) 	//convert back to diff
	          PSD_sum = PSD_sum + (ave_PSD[i]/0.5);
        // check transform using Parseval's Theorem
        series_sum = 0.0;
        for(int i=0;i<TOTAL_POINTS;i++)
        {	
            series_sum = series_sum +
                    in_data_mgr.transform_input.read_alt_h(i)* 
                            in_data_mgr.transform_input.read_alt_h(i);
        }
        series_sum = series_sum/(double)NO_SEGMENTS;

        // fit the GEOSAT PSD to ave_PSD
        transform_utilities.Fit_Geosat_PSD(ave_PSD, final_PSD);

        // fill the frequencies based on SAMPLE_FREQ and NO_TRANSFORM POINTS
        transform_utilities.freqs(transform_freq);

        // now compute altimeter noise
        for(int i=0; i<AVE_PTS; i++)
              tail_PSD = tail_PSD + final_PSD[FINAL_PSD_POINTS-i-1];

        tail_PSD = tail_PSD/(double)AVE_PTS;
        altimeter_noise = Math.sqrt(0.5*tail_PSD);

        in_data_mgr.this_messenger.alt_noise = altimeter_noise;
        in_data_mgr.this_messenger.tail_PSD = tail_PSD;
        for(int i=0; i<FINAL_PSD_POINTS; i++)
        {
            in_data_mgr.this_messenger.spectrum[i] = final_PSD[i];
            in_data_mgr.this_messenger.frequency[i] = transform_freq[i];
        }
    } // end method compute_transform()

    public void algo_delay(int in_time)
    {
        for(int i=0; i<in_time; i++)
        {
            for(int j=0; j<in_time; j++) { ; }
        }
    }

} // end class GFOAlgo --------------------------------------
   

class TransformUtilities  implements GlobalConstants
{
    static final double[] Geosat_PSD =
    { 
        1104.0,1041.5, 974.5, 909.5, 844.5, 779.4, 714.4, 654.4, 604.4,//0-8
        549.4, 504.4, 464.4, 434.4, 399.4, 369.4, 344.4, 324.4,// 9-16
        305.4, 288.4, 272.4, 257.4, 243.4, 230.4, 218.4, 207.4,//17-24
        196.4, 187.4, 178.4, 169.4, 159.4, 149.4, 137.4, 126.4,// 25-32
        116.4, 107.4,  99.4,  92.4,  86.4,  80.4,  75.4,  71.4,// 33- 40
        68.2, 65.1, 62.0, 58.9, 55.8, 52.7, 49.6, 46.6,  //41-48
        44.1, 41.6, 39.4, 37.4, 35.5, 33.7, 32.3, 31.1,  // 49-56
        30.1, 29.3, 28.5, 27.7, 26.9, 26.1, 25.3, 24.5,  // 57-64
        23.7, 22.9, 22.1, 21.4, 20.6, 19.9, 19.1, 18.3,  // 65-72
        17.5, 16.8, 16.0, 15.3, 14.6, 13.9, 13.2, 12.6,  // 73-80
        12.0, 11.5, 11.0, 10.6, 10.2,  9.8,  9.4,  9.0,  // 81-88
        8.45, 8.30, 8.15, 8.00, 7.85, 7.70, 7.55, 7.41,  // 89-96
        7.27, 7.13, 6.99, 6.85, 6.71, 6.58, 6.45, 6.32,  // 97-104
        6.19, 6.07, 5.95, 5.83, 5.71, 5.59, 5.47, 5.35,  // 105-112
        5.23, 5.11, 4.99, 4.87, 4.75, 4.63, 4.51, 4.39,  // 113-120
        4.27, 4.15, 4.03, 3.91, 3.79, 3.67, 3.55, 3.45,  // 121-128
        3.35, 3.25, 3.15, 3.10, 3.05, 2.95, 2.90, 2.80,  // 129-136
        2.70, 2.60, 2.50, 2.40, 2.30, 2.20, 2.10, 2.00,  // 137- 144
        1.90, 1.83, 1.76, 1.70, 1.64, 1.59, 1.55, 1.52,  // 145-152
        1.49, 1.47, 1.45, 1.43, 1.41, 1.39, 1.37, 1.35, // 153-160
        1.34, 1.33, 1.32, 1.31, 1.31, 1.30, 1.29, 1.28, // 161-168
        1.26, 1.25, 1.23, 1.21, 1.20, 1.18, 1.17, 1.15,  // 169-176
        1.14, 1.12, 1.11, 1.09, 1.08, 1.07, 1.05, 1.04, // 177-184
        1.02, 1.01, 1.00, 0.99, 0.98, 0.96, 0.95, 0.93, // 185-192
        0.92, 0.90, 0.89, 0.88, 0.87, 0.85, 0.84, 0.82, // 193-200
        0.81, 0.79, 0.78, 0.76, 0.75, 0.73, 0.72, 0.70,  // 201-208
        0.69, 0.67, 0.66, 0.64, 0.63, 0.61, 0.60, 0.58,  // 209-216
        0.57, 0.56, 0.54, 0.53, 0.52, 0.51, 0.49, 0.47,  // 217-224
        0.46, 0.44, 0.43, 0.41, 0.40, 0.38, 0.37, 0.35,  // 225-232
        0.34, 0.32, 0.31, 0.29, 0.28, 0.26, 0.25, 0.24, // 233-240
        0.22, 0.20, 0.19, 0.17, 0.16, 0.14, 0.13, 0.11, // 241-248
        0.10, 0.08, 0.07, 0.05, 0.04, 0.03, 0.01, 0.001   // 249-256
    };	 // GEOSAT reference spectrum

    TransformUtilities() { ; }

    public void discrete_transform(double[] in_input_real,
	             double[] in_input_imag, double[] in_output_real,
	             double[] in_output_imag, DataMgr in_data_mgr)
    {
        int N = NO_TRANSFORM_POINTS;
	  
        // first the bit reversal part of the FFT
        int j= 0;
        int m= 0;
        double tempr = 0.0;
        double tempi = 0.0;
        double[] transform_real = new double[N];
        double[] transform_imag = new double[N];

        for(int i=0; i<N; i++)
        {
            transform_real[i] = in_input_real[i];
            transform_imag[i] = in_input_imag[i];
        } // end for i

        for(int i=0; i<N; i++)
        {
            if(j>i)
            {
                tempr = transform_real[j];
                transform_real[j] = transform_real[i];
                transform_real[i] = tempr;

                tempi = transform_imag[j];
                transform_imag[j] = transform_imag[i];
                transform_imag[i] = tempi;
            } // end if	  
		   
            m = N/2; 
		   
            while(m>=1 && j>(m-1))
            {
                j = j-m;
                m = m/2;
            }
            j = j+m;
 
        } // end for bit reversal

        // now the Danielson-Lanczos section of the routine
        int m_max= 1;
        int i_step = 0;
        double theta = 0.0;
        double w_temp = 0.0;
        double wpr = 0.0, wpi = 0.0;
        double wr = 1.0, wi = 0.0;
        int temp_i = 0, temp_j=0;

        while(N > m_max)
        {
            i_step = 2*m_max;
            theta= Math.PI/m_max;
            w_temp= Math.sin(0.5*theta);
            wpr = -2.0 * w_temp * w_temp;
            wpi = Math.sin(theta);
            wr= 1.0;
            wi= 0.0;
            for(m=0; m<m_max; m=m+1)
            {
                for(int i=m; i<N; i=i+i_step)  
                {
                    j = i + m_max;
                    tempr = wr*transform_real[j] - wi*transform_imag[j];
                    tempi = wr*transform_imag[j] + wi*transform_real[j];
                    transform_real[j] = transform_real[i] - tempr;
                    transform_imag[j] = transform_imag[i] - tempi;
                    transform_real[i] = transform_real[i] + tempr;
                    transform_imag[i] = transform_imag[i] + tempi;
                } // end for i

                w_temp = wr;
                wr = wr*wpr - wi*wpi + wr;
                wi = wi*wpr + w_temp*wpi + wi;
            } // end for m

            m_max = i_step;
        } // end while

        // output the data
        for(int i=0; i<N; i++)
        {
            in_output_real[i] = transform_real[i];
            in_output_imag[i] = transform_imag[i];
        } // end for i output data[]

    } // end of method descrete_transform()

    public void PSD(double[] in_output_real,
		         double[] in_output_imag, double[] in_PSD)
    {
        double scale_factor = 1.0/(double) NO_TRANSFORM_POINTS;

        for(int i=0;i<NO_TRANSFORM_POINTS;i++)
        {
            if(i==0)
            {
                in_PSD[0] = scale_factor *
		               (in_output_real[0]*in_output_real[0] +
		                    in_output_imag[0]*in_output_imag[0]);
            } // end if i=0
            if( (i>0)&&(i<(NO_PSD_POINTS-1)) )
            {
                int j = NO_TRANSFORM_POINTS - i;
                in_PSD[i] = scale_factor *
		            ( (in_output_real[i]*in_output_real[i] +
		                     in_output_imag[i]*in_output_imag[i])
			       + (in_output_real[j]*in_output_real[j] +
		                     in_output_imag[j]*in_output_imag[j]) );
            } // end if 0<i<511
    	      if(i==(NO_PSD_POINTS-1))
            {
                in_PSD[i] = scale_factor *
		            ( in_output_real[i]*in_output_real[i] +
		                    in_output_imag[i]*in_output_imag[i] );
            } // end if i=511
        } // end for
   
        // this is difference spectrum, 
        //divide by 2 to get noise spectrum
        for(int i=0;i<NO_PSD_POINTS;i++)
                in_PSD[i] = 0.5*in_PSD[i];

    }  // end of method PSD()
  
    public void Fit_Geosat_PSD(double[] in_ave_PSD, double[] in_final_PSD)
    {
        double[] measured_PSD = new double[FINAL_PSD_POINTS];
        double high_freq_error = 0.0;
        double peak_error = 0.0;

        for(int i=0;i<FINAL_PSD_POINTS;i++)
	          measured_PSD[i] = 0.0;

        measured_PSD[0] = in_ave_PSD[0];
        for(int i=0; i<NO_PSD_POINTS-1; i++)
        {
            for(int j=0; j<NO_SEGMENTS; j++)
		        measured_PSD[(i*NO_SEGMENTS)+j+1] = in_ave_PSD[i+1];
        }

        // determine correction
        // find peak error
        for(int i=209; i<257; i++) 
        {
            if((measured_PSD[i]-Geosat_PSD[i])>peak_error)
		        peak_error = measured_PSD[i]-Geosat_PSD[i]; 
        }
	  
        high_freq_error = peak_error;
        // apply correction
        for(int i=1; i<257; i++)  
	          in_final_PSD[i] = high_freq_error + Geosat_PSD[i]; 
		
    } // end method Fit_Geosat_PSD()

    public void freqs(double[] in_transform_freq)
    {
        double sample_rate = 1.0;  // per sec
        double del_freq = 1.0/(TOTAL_POINTS*sample_rate);

        for(int i=0; i<FINAL_PSD_POINTS; i++)
	          in_transform_freq[i] = del_freq * (double)i;

    } // end of method freqs()

} // end of class TransformUtilities -----------------------

//========================================
// end classes to implement GFO Algorithm
//========================================