/**\file splitRangeSpectrum.cc * \author Heresh Fattahi. * */ #include "splitRangeSpectrum.h" #include #include #include #include #include #include #include #include "common.h" using namespace std; const float PI = std::acos(-1); const std::complex I(0, 1); using splitSpectrum::splitRangeSpectrum; typedef std::vector< std::complex > cpxVec; typedef std::vector< float > fltVec; int bandPass(GDALDataset* slcSubDataset, cpxVec &spectrum, cpxVec &spectrumSub, cpxVec &slcSub, int ind1, int ind2, int width, int inysize, int cols, int yoff, fltVec rangeTime, float subBandFrequency) { // Band-pass filetr // Copy the spectrum of the High band and center the High Band to center // frequency of the sub-band (demodulation is applied) // First copy the right half of the sub-band spectrum to elements [0:n/2] // where n = ind2 - ind1 // Since the spectrum obtained with FFTW3 is not normalized, we normalize // it by dividing the real and imaginary parts by the length of the signal // for each line, which is cols. //int kk,jj,ii; //#pragma omp parallel for\ // default(shared) //for (kk = 0; kk< inysize * (ind2 - ind1 - width); kk++) //{ // jj = kk/(ind2 -ind1 - width); // ii = kk % (ind2-ind1-width) + ind1 + width; // spectrumSub[jj*cols + ii - ind1 - width] = spectrum[ii+jj*cols]/(1.0f*cols); //} // Then copy the left part part to elements [N-n/2:N] where N is the length // of the signal (N=cols) //#pragma omp parallel for\ // default(shared) //for (kk=0; kkGetRasterBand(1)->RasterIO( GF_Write, 0, yoff, cols, inysize, (void*) (&slcSub[0]), cols, inysize, GDT_CFloat32, sizeof(std::complex), sizeof(std::complex)*cols, NULL); return(0); } int index_frequency(double B, int N, double f) // deterrmine the index (n) of a given frequency f // B: bandwidth, N: length of a signal // Assumption: for indices 0 to (N-1)/2, frequency is positive // and for indices larger than (N-1)/2 frequency is negative { // index of a given frequency f int n; // frequency interval double df = B/N; if (f < 0) n = round(f/df + N); else n = round(f/df); return n; } float frequency (double B, int N, int n) // calculates frequency at a given index. // Assumption: for indices 0 to (N-1)/2, frequency is positive // and for indices larger than (N-1)/2 frequency is negative { //frequency interval given B as the total bandwidth double f, df = B/N; int middleIndex = ((N-1)/2); if (n > middleIndex) f = (n-N)*df; else f = n*df; return f; } float adjustCenterFrequency(double B, int N, double dc) { // because of quantization, there may not be an index representing dc. We // therefore adjust dc to make sure that there is an index to represent it. // We find the index that is closest to nominal dc and then adjust dc to the // frequency of that index. // B = full band-width // N = length of signal // dc = center frequency of the sub-band int ind; double df = B/N; if (dc < 0){ ind = N+round(dc/df); } else{ ind = round(dc/df); } dc = frequency (B, N, ind); return dc; } void splitRangeSpectrum::setInputDataset(std::string inDataset) { // set input dataset which is the full-band SLC inputDS = inDataset; } void splitRangeSpectrum::setLowbandDataset(std::string inLbDataset, std::string inHbDataset) { // set output datasets which are two SLCs at low-band and high-band // low-band dataset lbDS = inLbDataset; // high-band dataset hbDS = inHbDataset; } void splitRangeSpectrum::setMemorySize(int inMemSize) { // set memory size memsize = inMemSize; } void splitRangeSpectrum::setBlockSize(int inBlockSize) { // set block size (number of lines to be read as one block) blocksize = inBlockSize; } void splitRangeSpectrum::setBandwidth(double fs, double lBW, double hBW) { // set the range sampling rate and the band-width of low-band and high-band SLC rangeSamplingRate = fs; lowBandWidth = lBW; highBandWidth = hBW; } void splitRangeSpectrum::setSubBandCenterFrequencies(double fl, double fh) { // set center frequencies of low-band and high-band SLCs lowCenterFrequency = fl; highCenterFrequency = fh; } //int split_spectrum_process(splitOptions *opts) //{ int splitRangeSpectrum::split_spectrum_process() { // Print user options to screen //opts->print(); // cols: number of columns of the SLC // rows: number of lines of the SLC int cols, rows; int blockysize; int nbands; // Define NULL GDAL datasets for input full-band SLC and out put sub-band SLCs GDALDataset* slcDataset = NULL; GDALDataset* slcLBDataset = NULL; GDALDataset* slcHBDataset = NULL; // Clock variables double t_start, t_end; // Register GDAL drivers GDALAllRegister(); slcDataset = reinterpret_cast( GDALOpenShared( inputDS.c_str(), GA_ReadOnly)); if (slcDataset == NULL) { std::cout << "Cannot open SLC file { " << inputDS << "}" << endl; std::cout << "GDALOpen failed - " << inputDS << endl; std::cout << "Exiting with error code .... (102) \n"; GDALDestroyDriverManager(); return 102; } cols = slcDataset->GetRasterXSize(); rows = slcDataset->GetRasterYSize(); nbands = slcDataset->GetRasterCount(); // Determine blocksizes // Number of vectors = 6 // Memory for one pixel CFloat32 = 8 byte // cols=number of columns in one line blockysize = int((memsize * 1.0e6)/(cols * 8 * 6) ); std::cout << "Computed block size based on memory size = " << blockysize << " lines \n"; // if (blockysize < opts->blocksize) // blockysize = opts->blocksize; std::cout << "Block size = " << blockysize << " lines \n"; int totalblocks = ceil( rows / (1.0 * blockysize)); std::cout << "Total number of blocks to process: " << totalblocks << "\n"; // Start the clock t_start = getWallTime(); // Array for reading complex SLC data std::vector< std::complex > slc(cols*blockysize); // Array for spectrum of full band SLC std::vector< std::complex > spectrum(cols*blockysize); // Array for spectrum of low-band SLC std::vector< std::complex > spectrumLB(cols*blockysize); // Array for spectrum of high-band SLC std::vector< std::complex > spectrumHB(cols*blockysize); // Array for low-band SLC std::vector< std::complex > slcLB(cols*blockysize); //Array for high-band SLC std::vector< std::complex > slcHB(cols*blockysize); //vector for range time std::vector< float > rangeTime(cols); // populating vector of range time for one line for (int ii = 0; ii < cols; ii++) { rangeTime[ii] = ii/rangeSamplingRate; } // Start block-by-block processing int blockcount = 0; int status; // number of threads int nthreads; nthreads = numberOfThreads(); // creating output datasets GDALDriver *poDriver = (GDALDriver*) GDALGetDriverByName("ENVI"); char **mOptions = NULL; mOptions = CSLSetNameValue(mOptions, "INTERLEAVE", "BIL"); mOptions = CSLSetNameValue(mOptions, "SUFFIX", "ADD"); // creating output datasets for low-band SLC slcLBDataset = (GDALDataset*) poDriver->Create(lbDS.c_str(), cols, rows, 1, GDT_CFloat32, mOptions); if (slcLBDataset == NULL) { std::cout << "Could not create meanamp dataset {" << lbDS << "} \n"; std::cout << "Exiting with non-zero error code ... 104 \n"; GDALClose(slcDataset); GDALDestroyDriverManager(); return 104; } // creating output datasets for high-band SLC slcHBDataset = (GDALDataset*) poDriver->Create(hbDS.c_str(), cols, rows, 1, GDT_CFloat32, mOptions); if (slcHBDataset == NULL) { std::cout << "Could not create meanamp dataset {" << lbDS << "} \n"; std::cout << "Exiting with non-zero error code ... 104 \n"; GDALClose(slcDataset); GDALDestroyDriverManager(); return 104; } CSLDestroy(mOptions); float highBand [2]; float lowBand [2]; cout << "sub-band center frequencies after adjustment: " << endl; cout << "low-band: " << lowCenterFrequency << endl; cout << "high-band: " << highCenterFrequency << endl; lowBand[0] = lowCenterFrequency - lowBandWidth/2.0; lowBand[1] = lowBand[0] + lowBandWidth; highBand[0] = highCenterFrequency - highBandWidth/2.0; highBand[1] = highBand[0] + highBandWidth; // defining the pixel number of the high-band int indH1, indH2, widthHB; // index of the lower bound of the high-band indH1 = index_frequency(rangeSamplingRate, cols, highBand[0]); // index of the upper bound of the High Band indH2 = index_frequency(rangeSamplingRate, cols, highBand[1]); // width of the subband (unit pixels) widthHB = (indH2 - indH1)/2; // defining the pixel number of the low-band int indL1, indL2, widthLB; // index of the lower bound of the low-band indL1 = index_frequency(rangeSamplingRate, cols, lowBand[0]); // index of the upper bound of the low-band indL2 = index_frequency(rangeSamplingRate, cols, lowBand[1]); // width of the subband (unit pixels) widthLB = (indL2 - indL1)/2; // Block-by-block processing int fftw_status; fftw_status = fftwf_init_threads(); cout << "fftw_status: " << fftw_status; for (int yoff=0; yoff < rows; yoff += blockysize) { // Increment block counter blockcount++; // Determine number of rows to read int inysize = blockysize; if ((yoff+inysize) > rows) inysize = rows - yoff; // Read a block of the SLC data to cpxdata array status = slcDataset->GetRasterBand(1)->RasterIO( GF_Read, 0, yoff, cols, inysize, (void*) (&slc[0]), cols, inysize, GDT_CFloat32, sizeof(std::complex), sizeof(std::complex)*cols, NULL); // creating the forward 1D fft plan for inysize lines of SLC data. // Each fft is applied on multiple lines of SLC data. fftwf_plan_with_nthreads(nthreads); fftwf_plan plan = fftwf_plan_many_dft(1, &cols, inysize, (fftwf_complex *) (&slc[0]), &cols, 1, cols, (fftwf_complex *) (&spectrum[0]), &cols, 1, cols, FFTW_FORWARD, FFTW_ESTIMATE); // execute the fft plan fftwf_execute(plan); fftwf_destroy_plan(plan); // bandpass the spectrum for low-band, demodulate to center the sub-band // spectrum, and normalize the sub-band spectrum bandPass(slcLBDataset, spectrum, spectrumLB, slcLB, indL1, indL2, widthLB, inysize, cols, yoff, rangeTime, lowCenterFrequency); // bandpass the spectrum for high-band, demodulate to center the sub-band // spectrum, and normalize the sub-band spectrum bandPass(slcHBDataset, spectrum, spectrumHB, slcHB, indH1, indH2, widthHB, inysize, cols, yoff, rangeTime, highCenterFrequency); } t_end = getWallTime(); std::cout << "splitSpectrum processing time: " << (t_end-t_start)/60.0 << " mins \n"; //close the datasets GDALClose(slcDataset); GDALClose(slcLBDataset); GDALClose(slcHBDataset); return (0); };