00001 #include <stdio.h> 00002 #include <stdlib.h> 00003 #include <math.h> 00004 #include <fftw3.h> 00005 00006 //#include "cheetah.h" 00007 #include "TestData.H" 00008 #include "FFTBinPrediction.H" 00009 00010 double sign(double val) { 00011 if (val < 0) 00012 return -1.0; 00013 else if (val > 0) 00014 return 1.0; 00015 return 0.0; 00016 } 00017 00018 // Globals 00019 const double SPEED_SOUND_WATER = 1482; // [m/s] 00020 const double SENSOR_SPACING = 0.024; // [m] 00021 00022 // Cheetah Settings 00023 //Cheetah handle; 00024 int port, bitrate; 00025 //uint8_t mode = 0; 00026 00027 // Peak Detection 00028 double maxIndex1, maxValue1; 00029 double maxIndex2, maxValue2; 00030 double maxIndex3, maxValue3; 00031 00032 // FFT 00033 const int N_FFT = 512; 00034 00035 // Data 00036 //uint8_t data_in[N_FFT * 3]; 00037 //uint8_t data_out[2]; 00038 short data_in[N_FFT * 3]; 00039 short data_out[2]; 00040 int ret; 00041 int input, ready_bit, valid_data_point; 00042 int target_frequency, halfwidth; 00043 double weighted_sum; 00044 double angle_estimate; 00045 00046 int main (int argc, char const *argv[]) { 00047 if (argc < 3) { 00048 fprintf(stderr, "usage: async PORT BITRATE [Target Freq. in Hz] [halfwidth]\n"); 00049 return 1; 00050 } 00051 00052 port = atoi(argv[1]); 00053 bitrate = atoi(argv[2]); 00054 00055 if (argc >= 4) 00056 target_frequency = atoi(argv[3]); 00057 else 00058 target_frequency = 30000; 00059 double target_wavelength = (double)SPEED_SOUND_WATER / (double)target_frequency; 00060 00061 //if (argc >= 5) 00062 // halfwidth = atoi(argv[4]); 00063 //else 00064 halfwidth = 3; 00065 //double *gaussian_weights; 00066 //gaussian_weights = new double[2 * halfwidth + 1]; 00067 // double gaussian_weights[] = {0.006, 0.061, 0.242, 0.383, 0.242, 0.061, 0.006}; 00068 00069 // // Open the device 00070 // handle = ch_open(port); 00071 // 00072 // if (handle <= 0) { 00073 // fprintf(stderr, "Unable to open Cheetah device on port %d\n", port); 00074 // fprintf(stderr, "Error code = %d (%s)\n", handle, ch_status_string(handle)); 00075 // exit(1); 00076 // } 00077 // fprintf(stderr, "Opened Cheetah device on port %d\n", port); 00078 // 00079 // fprintf(stderr, "Host interface is %s\n", 00080 // (ch_host_ifce_speed(handle)) ? "high speed" : "full speed"); 00081 // 00082 // // Ensure that the SPI subsystem is configured. 00083 // ch_spi_configure(handle, CheetahSpiPolarity(mode >> 1), CheetahSpiPhase(mode & 1), CH_SPI_BITORDER_MSB, 0x0); 00084 // fprintf(stderr, "SPI configuration set to mode %d, %s shift, SS[2:0] active low\n", mode, "MSB"); 00085 // 00086 // // Power the target using the Cheetah adapter's power supply. 00087 // ch_target_power(handle, CH_TARGET_POWER_ON); 00088 // ch_sleep_ms(100); 00089 // 00090 // // Set the bitrate. 00091 // bitrate = ch_spi_bitrate(handle, bitrate); 00092 // fprintf(stderr, "Bitrate set to %d kHz\n", bitrate); 00093 // 00094 // // Make a simple queue to just assert OE. 00095 // ch_spi_queue_clear(handle); 00096 // ch_spi_queue_oe(handle, 1); 00097 // ch_spi_batch_shift(handle, 0, 0); 00098 00099 // Queue the batch, which is a sequence of SPI packets (back-to-back) each of length 2. 00100 fprintf(stderr, "Beginning to queue SPI packets..."); 00101 data_out[0] = 0xff; 00102 data_out[1] = 0xff; 00103 // ch_spi_queue_clear(handle); 00104 // 00105 // for (int i = 0; i < N_FFT * 3; ++i) { 00106 // // Convert Slave 1 00107 // ch_spi_queue_ss(handle, 0xF); 00108 // ch_spi_queue_array(handle, 2, data_out); 00109 // ch_spi_queue_ss(handle, 0xE); 00110 // 00111 // // Convert Slave 2 00112 // ch_spi_queue_ss(handle, 0xF); 00113 // ch_spi_queue_array(handle, 2, data_out); 00114 // ch_spi_queue_ss(handle, 0xD); 00115 // 00116 // // Convert Slave 3 00117 // ch_spi_queue_ss(handle, 0xF); 00118 // ch_spi_queue_array(handle, 2, data_out); 00119 // ch_spi_queue_ss(handle, 0xB); 00120 // } 00121 fprintf(stderr, " Done\n"); 00122 00123 // Calculate Sampling Frequency and Target Bin 00124 // For affine bin prediction, use m = 10.59, b = -1193.82 and a 00125 // window-halfwidth of 5. 00126 FFTBinAffinePrediction bin_predictor(bitrate, N_FFT, target_frequency, 10.59, -1193.82, halfwidth); 00127 fprintf(stderr, "Target Bin: %d\n", bin_predictor.getTargetBin()); 00128 00129 // Define the Data Vectors 00130 //double *data1, *data2, *data3; 00131 fftw_complex *fft1, *fft2, *fft3; 00132 fftw_plan fft_plan1, fft_plan2, fft_plan3; 00133 00134 // Allocate Memory for the Data Vectors 00135 //data1 = (double *) fftw_malloc ( sizeof ( double ) * N_FFT ); 00136 //data2 = (double *) fftw_malloc ( sizeof ( double ) * N_FFT ); 00137 //data3 = (double *) fftw_malloc ( sizeof ( double ) * N_FFT ); 00138 fft1 = (double (*)[2]) fftw_malloc ( sizeof ( fftw_complex ) * (( N_FFT / 2 ) + 1) ); 00139 fft2 = (double (*)[2]) fftw_malloc ( sizeof ( fftw_complex ) * (( N_FFT / 2 ) + 1) ); 00140 fft3 = (double (*)[2]) fftw_malloc ( sizeof ( fftw_complex ) * (( N_FFT / 2 ) + 1) ); 00141 fft_plan1 = fftw_plan_dft_r2c_1d(N_FFT, data1, fft1, FFTW_ESTIMATE); 00142 fft_plan2 = fftw_plan_dft_r2c_1d(N_FFT, data2, fft2, FFTW_ESTIMATE); 00143 fft_plan3 = fftw_plan_dft_r2c_1d(N_FFT, data3, fft3, FFTW_ESTIMATE); 00144 00145 // // Submit the first batch 00146 // ch_spi_async_submit(handle); 00147 00148 // while (1) { 00149 // Submit another batch, while the previous one is in 00150 // progress. The application may even clear the current 00151 // batch queue and queue a different set of SPI 00152 // transactions before submitting this batch 00153 // asynchronously. 00154 // ch_spi_async_submit(handle); 00155 00156 // The application can now perform some other functions 00157 // while the Cheetah is both finishing the previous batch 00158 // and shifting the current batch as well. In order to 00159 // keep the Cheetah's pipe full, this entire loop must 00160 // complete AND another batch must be submitted 00161 // before the current batch completes. 00162 //ch_sleep_ms(1); 00163 00164 // Collect the previous batch 00165 // The length of the batch, N_FFT * 6, come from the fact that 3 ADCs 00166 // are batched and the return data requires 2 bytes. (2 * 3 = 6) 00167 // ret = ch_spi_async_collect(handle, N_FFT * 6, data_in); 00168 00169 // for (int j = 0; j < N_FFT * 6; j += 6) { 00170 // // SS2 Data 00171 // input = (data_in[j] << 8) + data_in[j+1]; 00172 // ready_bit = input & 0x4000; 00173 // valid_data_point = (input & 0x3ffc) >> 2; 00174 // data2[j/6] = valid_data_point; 00175 // 00176 // // SS3 Data 00177 // input = (data_in[j+2] << 8) + data_in[j+3]; 00178 // ready_bit = input & 0x4000; 00179 // valid_data_point = (input & 0x3ffc) >> 2; 00180 // data3[j/6] = valid_data_point; 00181 // 00182 // // SS1 Data 00183 // input = (data_in[j+4] << 8) + data_in[j+5]; 00184 // ready_bit = input & 0x4000; 00185 // valid_data_point = (input & 0x3ffc) >> 2; 00186 // data1[j/6] = valid_data_point; 00187 // } 00188 00189 // Perform FFT on current input data 00190 fftw_execute(fft_plan1); 00191 fftw_execute(fft_plan2); 00192 fftw_execute(fft_plan3); 00193 00194 // // Check the ADC on SS0 for a peak. 00195 // weighted_sum = 0; 00196 maxValue1 = 0; 00197 maxIndex1 = 0; 00198 maxValue2 = 0; 00199 maxIndex2 = 0; 00200 maxValue3 = 0; 00201 maxIndex3 = 0; 00202 // for (int i = bin_predictor.getTargetBin() - bin_predictor.getHalfwidth(); i < bin_predictor.getTargetBin() + bin_predictor.getHalfwidth() + 1; ++i) { 00203 for (int i = 10; i < N_FFT / 2; ++i) { 00204 // /*fprintf(stderr, "%1.3f * %10.2f + \n", gaussian_weights[i - (bin_predictor.getTargetBin() - bin_predictor.getHalfwidth())], sqrt( 00205 // pow(fft1[i][0],2.0) + 00206 // pow(fft1[i][1],2.0)));*/ 00207 // weighted_sum += gaussian_weights[i - (bin_predictor.getTargetBin() - bin_predictor.getHalfwidth())] * 00208 // sqrt(pow(fft1[i][0],2.0) + pow(fft1[i][1],2.0)); 00209 00210 if (fft1[i][0] * fft1[i][0] + fft1[i][1] * fft1[i][1] > maxValue1) { 00211 maxValue1 = fft1[i][0] * fft1[i][0] + fft1[i][1] * fft1[i][1]; //sqrt(pow(fft1[i][0],2.0) + pow(fft1[i][1],2.0)); 00212 maxIndex1 = i; 00213 } 00214 if (fft2[i][0] * fft2[i][0] + fft2[i][1] * fft2[i][1] > maxValue2) { 00215 maxValue2 = fft2[i][0] * fft2[i][0] + fft2[i][1] * fft2[i][1]; //sqrt(pow(fft2[i][0],2.0) + pow(fft2[i][1],2.0)); 00216 maxIndex2 = i; 00217 } 00218 if (fft3[i][0] * fft3[i][0] + fft3[i][1] * fft3[i][1] > maxValue3) { 00219 maxValue3 = fft3[i][0] * fft3[i][0] + fft3[i][1] * fft3[i][1]; //sqrt(pow(fft3[i][0],2.0) + pow(fft3[i][1],2.0)); 00220 maxIndex3 = i; 00221 } 00222 } 00223 fprintf(stderr, "Signal 1 Peak: %1.0f, %10.2f\n", maxIndex1, maxValue1); 00224 fprintf(stderr, "Signal 2 Peak: %1.0f, %10.2f\n", maxIndex2, maxValue2); 00225 fprintf(stderr, "Signal 3 Peak: %1.0f, %10.2f\n", maxIndex3, maxValue3); 00226 double phase1 = atan2((double)fft1[(int)maxIndex1][1], (double)fft1[(int)maxIndex1][0]); 00227 double phase2 = atan2((double)fft2[(int)maxIndex2][1], (double)fft2[(int)maxIndex2][0]); 00228 double phase3 = atan2((double)fft3[(int)maxIndex3][1], (double)fft3[(int)maxIndex3][0]); 00229 00230 double delta1 = phase2 - phase1; 00231 double delta2 = phase3 - phase2; 00232 double delta3 = phase1 - phase3; 00233 00234 fprintf(stderr, "Deltas: %4.4f, %4.4f, %4.4f\n", delta1, delta2, delta3); 00235 00236 int min_index = 3; 00237 if (fabs(delta2) < fabs(delta1) && fabs(delta2) < fabs(delta3)) 00238 min_index = 2; 00239 if (fabs(delta1) < fabs(delta2) && fabs(delta1) < fabs(delta3)) 00240 min_index = 1; 00241 00242 fprintf(stderr, "Min Index: %d\n", min_index); 00243 00244 // testing case 00245 //min_index = 1; 00246 double delta_tmp; 00247 switch (min_index) { 00248 case 1: 00249 delta_tmp = delta1; 00250 if (delta3 > delta2) 00251 delta_tmp = -1.0 * delta1 + sign(delta_tmp) * 2.0 * M_PI; 00252 angle_estimate = delta_tmp * (double)(((double)target_wavelength / 2.0) / SENSOR_SPACING) * 180.0 / M_PI / 2.0; 00253 break; 00254 case 2: 00255 delta_tmp = delta2; 00256 if (delta1 > delta3) 00257 delta_tmp = -1.0 * delta2 + 2.0 * M_PI; 00258 angle_estimate = (delta_tmp - 5.0 / 6.0 * M_PI) * ((target_wavelength / 2.0) / SENSOR_SPACING) * 180.0 / M_PI / 2.0; 00259 break; 00260 case 3: 00261 delta_tmp = delta3; 00262 if (delta2 > delta1) 00263 delta_tmp = -1.0 * delta3 - 2.0 * M_PI; 00264 //fprintf(stderr, "%4.8f\n", (double)SPEED_SOUND_WATER); 00265 //fprintf(stderr, "%4.8f\n", (double)target_frequency); 00266 //fprintf(stderr, "%4.8f\n", (double)SPEED_SOUND_WATER / (double)target_frequency); 00267 //fprintf(stderr, "%4.8f\n", (double)target_wavelength); 00268 //fprintf(stderr, "%4.8f\n", ((double)target_wavelength / 2.0)); 00269 //fprintf(stderr, "%4.8f\n", (((double)target_wavelength / 2.0) / SENSOR_SPACING)); 00270 //fprintf(stderr, "%4.8f\n", 180.0 / M_PI / 2.0); 00271 //fprintf(stderr, "%4.8f\n", (((double)target_wavelength / 2.0) / SENSOR_SPACING) * 180.0 / M_PI / 2.0); 00272 angle_estimate = (delta_tmp + 5.0 / 6.0 * M_PI ) * (((double)target_wavelength / 2.0) / SENSOR_SPACING) * 180.0 / M_PI / 2.0; 00273 break; 00274 default: 00275 fprintf(stderr, "ERROR: Invalid min_index for phase difference.\n"); 00276 } 00277 00278 //phase_difference *= ((target_wavelength / 2.0) / SENSOR_SPACING) * 180.0 / M_PI / 2.0; 00279 fprintf(stderr, "Detected Angle: %4.4f degrees\n", angle_estimate); 00280 // weighted_sum *= 2 * bin_predictor.getHalfwidth() + 1; 00281 00282 //fprintf(stderr, "%8.2f\n", weighted_sum); 00283 //fprintf(stderr, "DC: %10.2f\n", sqrt(pow(fft1[0][0],2.0) + pow(fft1[0][1],2.0))); 00284 00285 // // Weighted Gaussian Test 00286 // if (weighted_sum >= 0.01 * sqrt(pow(fft1[0][0],2.0) + pow(fft1[0][1],2.0))) 00287 // fprintf(stderr, "Peak detected!\n"); 00288 00289 // // Ensures communication is successful 00290 // if (ret < 0) fprintf(stderr, "status error: %s\n", ch_status_string(ret)); 00291 // fflush(stderr); 00292 00293 // The current batch is now shifting out on the SPI 00294 // interface. The application can again do some more tasks 00295 // here but this entire loop must finish so that a new 00296 // batch is armed before the current batch completes. 00297 //ch_sleep_ms(1); 00298 // } 00299 00300 // Clean up allocated memory 00301 fftw_destroy_plan(fft_plan1); 00302 fftw_destroy_plan(fft_plan2); 00303 fftw_destroy_plan(fft_plan3); 00304 // fftw_free(data1); 00305 // fftw_free(data2); 00306 // fftw_free(data3); 00307 fftw_free(fft1); 00308 fftw_free(fft2); 00309 fftw_free(fft3); 00310 //delete gaussian_weights; 00311 00312 return 0; 00313 }