module: ofdm_channel_estimator
description: The distortion from input of IFFT (vec_in1) to the output of FFT (vec_in2) is estimated via pilot symbol 
             on each subchannel. (here we assume that the first num_pilots of transmitted symbols are pilot symbols)
             This estimation is H=in1/in2
             This block is executed only when estimate = 1
             When num_pilots used for estimation > 1, channel estimation=average of the channel estimation by each pilot symbol
parameters: int num_channels , int num_pilots, int estimate
inputs: double clk_frame, Vector vec_in1_i, Vector vec_in1_q, Vector vec_in2_i, Vector vec_in2_q, IntVector vec_bit_settings
outputs: Vector vec_h_i, Vector vec_h_q, Vector vec_h_mag, Vector vec_h_phase
classes: EdgeDetect clk_frame_edge(), List list_mag(), List list_phase()
static_variables: Vector vec_in1_phase, Vector vec_in1_mag, Vector vec_in2_mag, Vector vec_in2_phase
                  int flag_pilot, int num_pilots_count, Vector vec_tmp_phase, Vector vec_tmp_mag, Vector vec_sum_phase, Vector vec_sum_mag
set_output_vector_lengths:
    vec_h_i=num_channels
    vec_h_q=num_channels
    vec_h_mag=num_channels
    vec_h_phase=num_channels
init:
    num_pilots_count = 0;
    if (vec_bit_settings.get_length() != num_channels) 
       {
       printf("error in 'ofdm_channel_estimator': the length\n");
       printf("    of vec_bit_settings does not equal num_channels\n");
       printf("    in this case, vec_bit_settings has length %d\n", 
                    vec_bit_settings.get_length());
       printf("    and num_channels = %d\n",num_channels);
       exit(1);
       }
    if (vec_in1_i.get_length() != vec_in2_i.get_length())
        {
         printf("error in 'ofdm_channel_estimator': the length of the\n");
         printf("       two input vectors are not the same\n");
         printf("    in this case vec_in1_i has length =%d, and vec_in2_i has length=%d\n",
                     vec_in1_i.get_length(), vec_in2_i.get_length());
         exit(1);
        } 
    vec_in1_mag.set_length(num_channels);
    vec_in1_phase.set_length(num_channels);
    vec_in2_mag.set_length(num_channels);
    vec_in2_phase.set_length(num_channels);
    vec_tmp_mag.set_length(num_channels);
    vec_tmp_phase.set_length(num_channels);
    vec_sum_mag.set_length(num_channels);
    vec_sum_phase.set_length(num_channels);
   flag_pilot = 0;
code:
if (estimate == 1)
{  
int i;
  if (clk_frame_edge.inp(clk_frame))
  {
     if (flag_pilot == 0)
     {
        for (i = 0; i<num_channels; i++)     
         {
	        if (vec_bit_settings.get_elem(i) != 0)
	        {
            vec_in1_phase.set_elem( i, atan2(vec_in1_q.get_elem(i), vec_in1_i.get_elem(i)) );
            vec_in1_mag.set_elem( i, sqrt(pow(vec_in1_i.get_elem(i),2) + pow(vec_in1_q.get_elem(i),2)) );
            vec_in2_phase.set_elem( i, atan2(vec_in2_q.get_elem(i), vec_in2_i.get_elem(i)) );
            vec_in2_mag.set_elem( i, sqrt(pow(vec_in2_i.get_elem(i),2) + pow(vec_in2_q.get_elem(i),2)) );
            vec_tmp_phase.set_elem(i, vec_sum_phase.get_elem(i));
            vec_tmp_mag.set_elem(i, vec_sum_mag.get_elem(i));
            vec_h_phase.set_elem( i, vec_in2_phase.get_elem(i) - vec_in1_phase.get_elem(i) );
            vec_h_mag.set_elem( i, vec_in2_mag.get_elem(i)/vec_in1_mag.get_elem(i) );
            if (vec_h_phase.get_elem(i) < 0.0)
                    vec_sum_phase.set_elem(i, vec_tmp_phase.get_elem(i) + vec_h_phase.get_elem(i) + 2*pi);
            else 
                     vec_sum_phase.set_elem(i, vec_tmp_phase.get_elem(i) + vec_h_phase.get_elem(i));
            vec_sum_mag.set_elem(i, vec_tmp_mag.get_elem(i) + vec_h_mag.get_elem(i));
            vec_h_i.set_elem( i, vec_h_mag.get_elem(i) * cos(vec_h_phase.get_elem(i)) );
            vec_h_q.set_elem( i, vec_h_mag.get_elem(i) * sin(vec_h_phase.get_elem(i)) );
            }
	        else // when no data is set, channel estimation is set to mag_h = 1 and phase_h=0
	        {
	        vec_h_phase.set_elem(i, 0);
	        vec_h_mag.set_elem(i, 1);
	        vec_h_i.set_elem(i, 1);
	        vec_h_q.set_elem(i, 0);
	        }	
        } // end of for loop above
         if (num_pilots == 1)
            {
            flag_pilot = 1;
            for (i = 0; i<vec_h_mag.get_length(); i++)
                {   
                list_mag.inp(vec_h_mag.get_elem(i));
                list_phase.inp(vec_h_phase.get_elem(i));                       
                }
            list_mag.save("ch_estimator_h_mag.dat");
            list_phase.save("ch_estimator_h_phase.dat");   
            }
         else
         { 
            num_pilots_count ++;
            if ( num_pilots == num_pilots_count)
            {
                flag_pilot = 1; 
                for (i = 0; i<num_channels; i++)     
                {
	                if (vec_bit_settings.get_elem(i) != 0)
	                {
                        vec_tmp_phase.set_elem(i, vec_sum_phase.get_elem(i));
                        vec_tmp_mag.set_elem(i, vec_sum_mag.get_elem(i));
                        vec_h_phase.set_elem(i, vec_tmp_phase.get_elem(i)/num_pilots );
                        vec_h_mag.set_elem( i, vec_tmp_mag.get_elem(i)/num_pilots );
                        vec_h_i.set_elem( i, vec_h_mag.get_elem(i) * cos(vec_h_phase.get_elem(i)) );
                        vec_h_q.set_elem( i, vec_h_mag.get_elem(i) * sin(vec_h_phase.get_elem(i)) );
                    }
                    else
	                {
	                    vec_h_phase.set_elem(i, 0);
	                    vec_h_mag.set_elem(i, 1);
	                    vec_h_i.set_elem(i, 1);
	                    vec_h_q.set_elem(i, 0);
	                }	
	                list_mag.inp(vec_h_mag.get_elem(i));
                    list_phase.inp(vec_h_phase.get_elem(i));            
               }
             list_mag.save("ch_estimator_h_mag.dat");
             list_phase.save("ch_estimator_h_phase.dat");   
           }
        }   
      }    //end of flag_pilot==0 statement
   }  //end of clk_frame_edge statement
}  //end of estimate==1 statement  
