Changeset 368 for trunk/src


Ignore:
Timestamp:
02/05/05 15:55:56 (20 years ago)
Author:
vor010
Message:

SDLineFinder: work around to detect weak and broad lines
as well as to avoid creating sidelobes near strong lines due to imperfections in edge detection

Location:
trunk/src
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/SDLineFinder.cc

    r352 r368  
    430430      if (running_box!=NULL) delete running_box;
    431431      running_box=new RunningBox(spectrum,mask,edge,max_box_nchan);
    432    
     432
     433     
     434      // determine the off-line variance first
     435      // an assumption made: lines occupy a small part of the spectrum
     436
     437      std::vector<float> variances(edge.second-edge.first);
     438      DebugAssert(variances.size(),AipsError);
     439
     440      for (;running_box->haveMore();running_box->next())
     441           variances[running_box->getChannel()-edge.first]=
     442                                running_box->getLinVariance();
     443                               
     444      // in the future we probably should do a proper Chi^2 estimation
     445      // now a simple 80% of smaller values will be used.
     446      // it may degrade the performance of the algorithm for weak lines
     447      // due to a bias of the Chi^2 distribution.
     448      stable_sort(variances.begin(),variances.end());
     449      Float offline_variance=0;
     450      uInt offline_cnt=uInt(0.8*variances.size());     
     451      if (!offline_cnt) offline_cnt=variances.size(); // no much else left,
     452                                    // although it is very inaccurate
     453      for (uInt n=0;n<offline_cnt;++n)
     454           offline_variance+=variances[n];         
     455      offline_variance/=Float(offline_cnt);       
     456           
    433457      // actual search algorithm
    434458      is_detected_before=False;
    435459      Vector<Int> signs(spectrum.nelements(),0);
    436          
    437       for (;running_box->haveMore();running_box->next()) {
     460
     461      ofstream os("dbg.dat");
     462      for (running_box->rewind();running_box->haveMore();
     463                                 running_box->next()) {
    438464           const int ch=running_box->getChannel();
    439465           if (running_box->getNumberOfBoxPoints()>=minboxnchan)
    440466               processChannel(mask[ch] && (fabs(running_box->aboveMean()) >=
    441                   threshold*running_box->getLinVariance()), mask);
     467                  threshold*offline_variance), mask);
    442468           else processCurLine(mask); // just finish what was accumulated before
    443469           const Float buf=running_box->aboveMean();
    444470           if (buf>0) signs[ch]=1;
    445471           else if (buf<0) signs[ch]=-1;
    446            else if (buf==0) signs[ch]=0;           
     472           else if (buf==0) signs[ch]=0;
     473           os<<ch<<" "<<spectrum[ch]<<" "<<running_box->getLinMean()<<" "<<
     474                        threshold*offline_variance<<endl;
    447475      }
    448476      if (lines.size())
     
    551579{
    552580  // detection threshold - the minimal signal to noise ratio
    553   threshold=3.; // 3 sigma is a default
     581  threshold=sqrt(3.); // 3 sigma and 3 channels is a default -> sqrt(3) in
     582                     // a single channel
    554583  box_size=1./5.; // default box size for running mean calculations is
    555584                  // 1/5 of the whole spectrum
     
    621650// search for spectral lines. Number of lines found is returned
    622651int SDLineFinder::findLines() throw(casa::AipsError)
    623 {
     652{ 
    624653  const int minboxnchan=4;
    625654  if (scan.null())
     
    638667
    639668  Bool first_pass=True;
     669  Int avg_factor=1; // this number of adjacent channels is averaged together
     670                    // the total number of the channels is not altered
     671                    // instead, min_nchan is also scaled
     672                    // it helps to search for broad lines
    640673  while (true) {
    641674     // a buffer for new lines found at this iteration
    642      std::list<pair<int,int> > new_lines;
    643 
     675     std::list<pair<int,int> > new_lines;     
    644676     // line find algorithm
    645      LFAboveThreshold lfalg(new_lines,min_nchan, threshold);
     677     LFAboveThreshold lfalg(new_lines,avg_factor*min_nchan, threshold);
    646678
    647679     try {
    648680         lfalg.findLines(spectrum,temp_mask,edge,max_box_nchan);
     681         first_pass=False;
     682         if (!new_lines.size())
     683              throw AipsError("spurious"); // nothing new - use the same
     684                                           // code as for a real exception
    649685     }
    650686     catch(const AipsError &ae) {
    651687         if (first_pass) throw;
    652          break; // nothing new
     688         // nothing new - proceed to the next step of averaging, if any
     689         // (to search for broad lines)
     690         avg_factor*=2; // twice as more averaging
     691         averageAdjacentChannels(temp_mask,avg_factor);
     692         if (avg_factor>8) break; // averaging up to 8 adjacent channels,
     693                                  // stop after that
     694         continue;
    653695     }
    654      first_pass=False;
    655      if (!new_lines.size()) break; // nothing new
    656 
     696     keepStrongestOnly(temp_mask,new_lines,max_box_nchan);
    657697     // update the list (lines) merging intervals, if necessary
    658698     addNewSearchResult(new_lines,lines);
     
    661701  }
    662702  return int(lines.size());
     703}
     704
     705// auxiliary function to average adjacent channels and update the mask
     706// if at least one channel involved in summation is masked, all
     707// output channels will be masked. This function works with the
     708// spectrum and edge fields of this class, but updates the mask
     709// array specified, rather than the field of this class
     710// boxsize - a number of adjacent channels to average
     711void SDLineFinder::averageAdjacentChannels(casa::Vector<casa::Bool> &mask2update,
     712                                   const casa::Int &boxsize)
     713                            throw(casa::AipsError)
     714{
     715  DebugAssert(mask2update.nelements()==spectrum.nelements(), AipsError);
     716  DebugAssert(boxsize!=0,AipsError);
     717 
     718  for (int n=edge.first;n<edge.second;n+=boxsize) {
     719       DebugAssert(n<spectrum.nelements(),AipsError);
     720       int nboxch=0; // number of channels currently in the box
     721       Float mean=0; // buffer for mean calculations
     722       for (int k=n;k<n+boxsize && k<edge.second;++k)
     723            if (mask2update[k]) {  // k is a valid channel
     724                mean+=spectrum[k];
     725                ++nboxch;
     726            }     
     727       if (nboxch<boxsize) // mask these channels
     728           for (int k=n;k<n+boxsize && k<edge.second;++k)
     729                mask2update[k]=False;
     730       else {
     731          mean/=Float(boxsize);
     732           for (int k=n;k<n+boxsize && k<edge.second;++k)
     733                spectrum[k]=mean;
     734       }
     735  }
    663736}
    664737
     
    747820}
    748821
     822// an auxiliary function to remove all lines from the list, except the
     823// strongest one (by absolute value). If the lines removed are real,
     824// they will be find again at the next iteration. This approach 
     825// increases the number of iterations required, but is able to remove
     826// the sidelobes likely to occur near strong lines.
     827// Later a better criterion may be implemented, e.g.
     828// taking into consideration the brightness of different lines. Now
     829// use the simplest solution     
     830// temp_mask - mask to work with (may be different from original mask as
     831// the lines previously found may be masked)
     832// lines2update - a list of lines to work with
     833//                 nothing will be done if it is empty
     834// max_box_nchan - channels in the running box for baseline filtering
     835void SDLineFinder::keepStrongestOnly(const casa::Vector<casa::Bool> &temp_mask,
     836                  std::list<std::pair<int, int> > &lines2update,
     837                  int max_box_nchan)
     838                                   throw (casa::AipsError)
     839{
     840  try {
     841      if (!lines2update.size()) return; // ignore an empty list
     842
     843      // current line
     844      std::list<std::pair<int,int> >::iterator li=lines2update.begin();
     845      // strongest line
     846      std::list<std::pair<int,int> >::iterator strongli=lines2update.begin();
     847      // the flux (absolute value) of the strongest line
     848      Float peak_flux=-1; // negative value - a flag showing uninitialized
     849                          // value
     850      // the algorithm below relies on the list being ordered
     851      Float tmp_flux=-1; // a temporary peak
     852      for (RunningBox running_box(spectrum,temp_mask,edge,max_box_nchan);
     853           running_box.haveMore(); running_box.next()) {
     854
     855           if (li==lines2update.end()) break; // no more lines
     856           const int ch=running_box.getChannel();         
     857           if (ch>=li->first && ch<li->second)
     858               if (temp_mask[ch] && tmp_flux<fabs(running_box.aboveMean()))
     859                   tmp_flux=fabs(running_box.aboveMean());
     860           if (ch==li->second-1) {
     861               if (peak_flux<tmp_flux) { // if peak_flux=-1, this condition
     862                   peak_flux=tmp_flux;   // will be satisfied
     863                   strongli=li;
     864               }
     865               ++li;
     866               tmp_flux=-1;
     867           }
     868      }     
     869      std::list<std::pair<int,int> > res;
     870      res.splice(res.end(),lines2update,strongli);
     871      lines2update.clear();
     872      lines2update.splice(lines2update.end(),res);
     873  }
     874  catch (const AipsError &ae) {
     875      throw;
     876  } 
     877  catch (const exception &ex) {
     878      throw AipsError(String("SDLineFinder::keepStrongestOnly - STL error: ")+ex.what());
     879  }
     880
     881}
     882
    749883//
    750884///////////////////////////////////////////////////////////////////////////////
  • trunk/src/SDLineFinder.h

    r352 r368  
    161161   std::vector<int>   getLineRanges(bool defunits=true)
    162162                                const throw(casa::AipsError);
     163protected:
     164   // auxiliary function to average adjacent channels and update the mask
     165   // if at least one channel involved in summation is masked, all
     166   // output channels will be masked. This function works with the
     167   // spectrum and edge fields of this class, but updates the mask
     168   // array specified, rather than the field of this class
     169   // boxsize - a number of adjacent channels to average
     170   void averageAdjacentChannels(casa::Vector<casa::Bool> &mask2update,
     171                               const casa::Int &boxsize)
     172                               throw(casa::AipsError);
     173   
     174   // an auxiliary function to remove all lines from the list, except the
     175   // strongest one (by absolute value). If the lines removed are real,
     176   // they will be find again at the next iteration. This approach 
     177   // increases the number of iterations required, but is able to remove
     178   // the sidelobes likely to occur near strong lines.
     179   // Later a better criterion may be implemented, e.g.
     180   // taking into consideration the brightness of different lines. Now
     181   // use the simplest solution     
     182   // temp_mask - mask to work with (may be different from original mask as
     183   // the lines previously found may be masked)
     184   // lines2update - a list of lines to work with
     185   //                 nothing will be done if it is empty
     186   // max_box_nchan - channels in the running box for baseline filtering
     187   void keepStrongestOnly(const casa::Vector<casa::Bool> &temp_mask,
     188                          std::list<std::pair<int, int> > &lines2update,
     189                          int max_box_nchan)
     190                                      throw (casa::AipsError);
    163191private:
    164192   casa::CountedConstPtr<SDMemTable> scan; // the scan to work with
Note: See TracChangeset for help on using the changeset viewer.