- Timestamp:
- 01/31/05 15:48:36 (20 years ago)
- Location:
- trunk
- Files:
-
- 3 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/python/asaplinefind.py
r302 r331 53 53 regardless on the invert option 54 54 """ 55 return self.finder. _getmask(invert)55 return self.finder.getmask(invert) 56 56 def get_ranges(self,defunits=True): 57 57 """ -
trunk/src/SDLineFinder.cc
r297 r331 42 42 using namespace boost::python; 43 43 44 namespace asap { 45 46 // An auxiliary class implementing one pass of the line search algorithm, 47 // which uses a running mean. We define this class here because it is 48 // used in SDLineFinder only. The incapsulation of this code into a separate 49 // class will provide a possibility to add new algorithms with minor changes 50 class LFRunningMean { 51 // The input data to work with. Use reference symantics to avoid 52 // an unnecessary copying 53 const casa::Vector<casa::Float> &spectrum; // a buffer for the spectrum 54 const casa::Vector<casa::Bool> &mask; // associated mask 55 const std::pair<int,int> &edge; // start and stop+1 channels 56 // to work with 57 58 // statistics for running mean filtering 59 casa::Float sum; // sum of fluxes 60 casa::Float sumsq; // sum of squares of fluxes 61 int box_chan_cntr; // actual number of channels in the box 62 int max_box_nchan; // maximum allowed number of channels in the box 63 // (calculated from boxsize and actual spectrum size) 64 65 // temporary line edge channels and flag, which is True if the line 66 // was detected in the previous channels. 67 std::pair<int,int> cur_line; 68 casa::Bool is_detected_before; 69 int min_nchan; // A minimum number of consequtive 70 // channels, which should satisfy 71 // the detection criterion, to be 72 // a detection 73 casa::Float threshold; // detection threshold - the 74 // minimal signal to noise ratio 75 public: 76 // set up the object with the references to actual data 77 // as well as the detection criterion (min_nchan and threshold, see above) 78 // and the number of channels in the running box 79 LFRunningMean(const casa::Vector<casa::Float> &in_spectrum, 80 const casa::Vector<casa::Bool> &in_mask, 81 const std::pair<int,int> &in_edge, 82 int in_max_box_nchan, 83 int in_min_nchan = 3, 84 casa::Float in_threshold = 5); 85 86 // replace the detection criterion 87 void setCriterion(int in_min_nchan, casa::Float in_threshold) throw(); 88 89 // find spectral lines and add them into list 90 void findLines(std::list<pair<int,int> > &lines) throw(casa::AipsError); 91 92 protected: 93 // supplementary function to control running mean calculations. 94 // It adds a specified channel to the running mean box and 95 // removes (ch-maxboxnchan+1)'th channel from there 96 // Channels, for which the mask is false or index is beyond the 97 // allowed range, are ignored 98 void advanceRunningBox(int ch) throw(casa::AipsError); 99 100 101 // test a channel against current running mean & rms 102 // if channel specified is masked out or beyond the allowed indexes, 103 // false is returned 104 casa::Bool testChannel(int ch) const 105 throw(std::exception, casa::AipsError); 106 107 // process a channel: update curline and is_detected before and 108 // add a new line to the list, if necessary using processCurLine() 109 void processChannel(std::list<pair<int,int> > &lines, 110 int ch) throw(casa::AipsError); 111 112 // process the interval of channels stored in curline 113 // if it satisfies the criterion, add this interval as a new line 114 void processCurLine(std::list<pair<int,int> > &lines) throw(casa::AipsError); 115 116 }; 117 } // namespace asap 118 119 /////////////////////////////////////////////////////////////////////////////// 120 // 121 // LFRunningMean - a running mean algorithm for line detection 122 // 123 // 124 125 // set up the object with the references to actual data 126 // as well as the detection criterion (min_nchan and threshold, see above) 127 // and the number of channels in the running box 128 LFRunningMean::LFRunningMean(const casa::Vector<casa::Float> &in_spectrum, 129 const casa::Vector<casa::Bool> &in_mask, 130 const std::pair<int,int> &in_edge, 131 int in_max_box_nchan, 132 int in_min_nchan, casa::Float in_threshold) : 133 spectrum(in_spectrum), mask(in_mask), edge(in_edge), 134 max_box_nchan(in_max_box_nchan), 135 min_nchan(in_min_nchan),threshold(in_threshold) {} 136 137 // replace the detection criterion 138 void LFRunningMean::setCriterion(int in_min_nchan, casa::Float in_threshold) 139 throw() 140 { 141 min_nchan=in_min_nchan; 142 threshold=in_threshold; 143 } 144 145 146 // supplementary function to control running mean calculations. 147 // It adds a specified channel to the running mean box and 148 // removes (ch-max_box_nchan+1)'th channel from there 149 // Channels, for which the mask is false or index is beyond the 150 // allowed range, are ignored 151 void LFRunningMean::advanceRunningBox(int ch) throw(AipsError) 152 { 153 if (ch>=edge.first && ch<edge.second) 154 if (mask[ch]) { // ch is a valid channel 155 ++box_chan_cntr; 156 sum+=spectrum[ch]; 157 sumsq+=square(spectrum[ch]); 158 } 159 int ch2remove=ch-max_box_nchan; 160 if (ch2remove>=edge.first && ch2remove<edge.second) 161 if (mask[ch2remove]) { // ch2remove is a valid channel 162 --box_chan_cntr; 163 sum-=spectrum[ch2remove]; 164 sumsq-=square(spectrum[ch2remove]); 165 } 166 } 167 168 // test a channel against current running mean & rms 169 // if channel specified is masked out or beyond the allowed indexes, 170 // false is returned 171 Bool LFRunningMean::testChannel(int ch) const throw(exception, AipsError) 172 { 173 if (ch<edge.first || ch>=edge.second) return False; 174 if (!mask[ch]) return False; 175 DebugAssert(box_chan_cntr, AipsError); 176 Float mean=sum/Float(box_chan_cntr); 177 Float variance=sqrt(sumsq/Float(box_chan_cntr)-square(mean)); 178 /* 179 if (ch>3900 && ch<4100) 180 cout<<"Tested "<<ch<<" mean="<<mean<<" variance="<<variance<<" sp-mean="<<spectrum[ch]-mean<<endl; 181 */ 182 return fabs(spectrum[ch]-mean)>=threshold*variance; 183 } 184 185 // process a channel: update cur_line and is_detected before and 186 // add a new line to the list, if necessary 187 void LFRunningMean::processChannel(std::list<pair<int,int> > &lines, 188 int ch) throw(casa::AipsError) 189 { 190 try { 191 if (testChannel(ch)) { 192 if (is_detected_before) 193 cur_line.second=ch+1; 194 else { 195 is_detected_before=True; 196 cur_line.first=ch; 197 cur_line.second=ch+1; 198 } 199 } else processCurLine(lines); 200 } 201 catch (const AipsError &ae) { 202 throw; 203 } 204 catch (const exception &ex) { 205 throw AipsError(String("SDLineFinder::processChannel - STL error: ")+ex.what()); 206 } 207 } 208 209 // process the interval of channels stored in cur_line 210 // if it satisfies the criterion, add this interval as a new line 211 void LFRunningMean::processCurLine(std::list<pair<int,int> > &lines) 212 throw(casa::AipsError) 213 { 214 try { 215 if (is_detected_before) { 216 if (cur_line.second-cur_line.first>min_nchan) { 217 // it was a detection. We need to change the list 218 Bool add_new_line=False; 219 if (lines.size()) { 220 for (int i=lines.back().second;i<cur_line.first;++i) 221 if (mask[i]) { // one valid channel in between 222 // means that we deal with a separate line 223 add_new_line=True; 224 break; 225 } 226 } else add_new_line=True; 227 if (add_new_line) 228 lines.push_back(cur_line); 229 else lines.back().second=cur_line.second; 230 } 231 is_detected_before=False; 232 } 233 } 234 catch (const AipsError &ae) { 235 throw; 236 } 237 catch (const exception &ex) { 238 throw AipsError(String("SDLineFinder::processCurLine - STL error: ")+ex.what()); 239 } 240 } 241 242 // find spectral lines and add them into list 243 void LFRunningMean::findLines(std::list<pair<int,int> > &lines) 244 throw(casa::AipsError) 245 { 246 const int minboxnchan=4; 247 248 // fill statistics for initial box 249 box_chan_cntr=0; // no channels are currently in the box 250 sum=0; // initialize statistics 251 sumsq=0; 252 int initial_box_ch=edge.first; 253 for (;initial_box_ch<edge.second && box_chan_cntr<max_box_nchan; 254 ++initial_box_ch) 255 advanceRunningBox(initial_box_ch); 256 257 if (initial_box_ch==edge.second) 258 throw AipsError("LFRunningMean::findLines - too much channels are masked"); 259 260 // actual search algorithm 261 is_detected_before=False; 262 263 if (box_chan_cntr>=minboxnchan) 264 // there is a minimum amount of data. We can search in the 265 // half of the initial box 266 for (int n=edge.first;n<initial_box_ch-max_box_nchan/2;++n) 267 processChannel(lines,n); 268 269 // now the box can be moved. n+max_box_nchan/2 is a new index which haven't 270 // yet been included in the running mean. 271 for (int n=initial_box_ch-max_box_nchan/2;n<edge.second;++n) { 272 advanceRunningBox(n+max_box_nchan/2); // update running mean & variance 273 if (box_chan_cntr>=minboxnchan) // have enough data to process 274 processChannel(lines,n); 275 else processCurLine(lines); // just finish what was accumulated before 276 } 277 } 278 279 // 280 /////////////////////////////////////////////////////////////////////////////// 281 282 44 283 // SDLineFinder - a class for automated spectral line search 45 284 … … 123 362 " use set_scan"); 124 363 DebugAssert(mask.nelements()==scan->nChan(), AipsError); 125 lines.resize(0); // search from the scratch 126 127 max_box_nchan=int(scan->nChan()*box_size); // number of channels in running 128 // box 129 364 int max_box_nchan=int(scan->nChan()*box_size); // number of channels in running 365 // box 130 366 if (max_box_nchan<2) 131 367 throw AipsError("SDLineFinder::findLines - box_size is too small"); 132 368 133 369 scan->getSpectrum(spectrum); 134 135 // fill statistics for initial box 136 box_chan_cntr=0; // no channels are currently in the box 137 sum=0; // initialize statistics 138 sumsq=0; 139 int initial_box_ch=edge.first; 140 for (;initial_box_ch<edge.second && box_chan_cntr<max_box_nchan; 141 ++initial_box_ch) 142 advanceRunningBox(initial_box_ch); 143 144 if (initial_box_ch==edge.second) 145 throw AipsError("SDLineFinder::findLines - too much channels are masked"); 146 147 // actual search algorithm 148 is_detected_before=False; 149 150 if (box_chan_cntr>=minboxnchan) 151 // there is a minimum amount of data. We can search in the 152 // half of the initial box 153 for (int n=edge.first;n<initial_box_ch-max_box_nchan/2;++n) 154 processChannel(n); 155 156 // now the box can be moved. n+max_box_nchan/2 is a new index which haven't 157 // yet been included in the running mean. 158 for (int n=initial_box_ch-max_box_nchan/2;n<edge.second;++n) { 159 advanceRunningBox(n+max_box_nchan/2); // update running mean & variance 160 if (box_chan_cntr>=minboxnchan) // have enough data to process 161 processChannel(n); 162 else processCurLine(); // just finish what was accumulated before 163 } 370 371 lines.resize(0); // search from the scratch 372 Vector<Bool> temp_mask(mask); 373 size_t cursz; 374 do { 375 cursz=lines.size(); 376 // line find algorithm 377 LFRunningMean lfalg(spectrum,temp_mask,edge,max_box_nchan,min_nchan,threshold); 378 lfalg.findLines(lines); 379 temp_mask=getMask(); 380 } while (cursz!=lines.size()); 164 381 return int(lines.size()); 165 382 } 166 383 167 // supplementary function to control running mean calculations.168 // It adds a specified channel to the running mean box and169 // removes (ch-max_box_nchan+1)'th channel from there170 // Channels, for which the mask is false or index is beyond the171 // allowed range, are ignored172 void SDLineFinder::advanceRunningBox(int ch) throw(AipsError)173 {174 if (ch>=edge.first && ch<edge.second)175 if (mask[ch]) { // ch is a valid channel176 ++box_chan_cntr;177 sum+=spectrum[ch];178 sumsq+=square(spectrum[ch]);179 }180 int ch2remove=ch-max_box_nchan;181 if (ch2remove>=edge.first && ch2remove<edge.second)182 if (mask[ch2remove]) { // ch2remove is a valid channel183 --box_chan_cntr;184 sum-=spectrum[ch2remove];185 sumsq-=square(spectrum[ch2remove]);186 }187 }188 189 // test a channel against current running mean & rms190 // if channel specified is masked out or beyond the allowed indexes,191 // false is returned192 Bool SDLineFinder::testChannel(int ch) throw(exception, AipsError)193 {194 if (ch<edge.first || ch>=edge.second) return False;195 if (!mask[ch]) return False;196 DebugAssert(box_chan_cntr, AipsError);197 Float mean=sum/Float(box_chan_cntr);198 Float variance=sqrt(sumsq/Float(box_chan_cntr)-square(mean));199 /*200 if (ch>3900 && ch<4100)201 cout<<"Tested "<<ch<<" mean="<<mean<<" variance="<<variance<<" sp-mean="<<spectrum[ch]-mean<<endl;202 */203 return fabs(spectrum[ch]-mean)>=threshold*variance;204 }205 206 // process a channel: update cur_line and is_detected before and207 // add a new line to the list, if necessary208 void SDLineFinder::processChannel(int ch) throw(casa::AipsError)209 {210 try {211 if (testChannel(ch)) {212 if (is_detected_before)213 cur_line.second=ch+1;214 else {215 is_detected_before=True;216 cur_line.first=ch;217 cur_line.second=ch+1;218 }219 } else processCurLine();220 }221 catch (const AipsError &ae) {222 throw;223 }224 catch (const exception &ex) {225 throw AipsError(String("SDLineFinder::processChannel - STL error: ")+ex.what());226 }227 }228 229 // process the interval of channels stored in cur_line230 // if it satisfies the criterion, add this interval as a new line231 void SDLineFinder::processCurLine() throw(casa::AipsError)232 {233 try {234 if (is_detected_before) {235 if (cur_line.second-cur_line.first>min_nchan) {236 // it was a detection. We need to change the list237 Bool add_new_line=False;238 if (lines.size()) {239 for (int i=lines.back().second;i<cur_line.first;++i)240 if (mask[i]) { // one valid channel in between241 // means that we deal with a separate line242 add_new_line=True;243 break;244 }245 } else add_new_line=True;246 if (add_new_line)247 lines.push_back(cur_line);248 else lines.back().second=cur_line.second;249 }250 is_detected_before=False;251 }252 }253 catch (const AipsError &ae) {254 throw;255 }256 catch (const exception &ex) {257 throw AipsError(String("SDLineFinder::processCurLine - STL error: ")+ex.what());258 }259 }260 384 261 385 // get the mask to mask out all lines that have been found (default) … … 341 465 } 342 466 } 467 468 // concatenate two lists preserving the order. If two lines appear to 469 // be adjacent, they are joined into the new one 470 void SDLineFinder::addNewSearchResult(const std::list<pair<int, int> > &newlines) 471 throw(AipsError) 472 { 473 try { 474 for (std::list<pair<int,int> >::const_iterator cli=newlines.begin(); 475 cli!=newlines.end();++cli) { 476 // search for a right place for the new line 477 //TODO 478 } 479 } 480 catch (const AipsError &ae) { 481 throw; 482 } 483 catch (const exception &ex) { 484 throw AipsError(String("SDLineFinder::addNewSearchResult - STL error: ")+ex.what()); 485 } 486 487 } -
trunk/src/SDLineFinder.h
r297 r331 85 85 std::vector<int> getLineRanges(bool defunits=true) 86 86 const throw(casa::AipsError); 87 88 87 protected: 89 // supplementary function to control running mean calculations. 90 // It adds a specified channel to the running mean box and 91 // removes (ch-maxboxnchan+1)'th channel from there 92 // Channels, for which the mask is false or index is beyond the 93 // allowed range, are ignored 94 void advanceRunningBox(int ch) throw(casa::AipsError); 95 96 97 // test a channel against current running mean & rms 98 // if channel specified is masked out or beyond the allowed indexes, 99 // false is returned 100 casa::Bool testChannel(int ch) throw(std::exception, casa::AipsError); 101 102 // process a channel: update curline and is_detected before and 103 // add a new line to the list, if necessary using processCurLine() 104 void processChannel(int ch) throw(casa::AipsError); 105 106 // process the interval of channels stored in curline 107 // if it satisfies the criterion, add this interval as a new line 108 void processCurLine() throw(casa::AipsError); 109 88 // concatenate two lists preserving the order. If two lines appear to 89 // be adjacent, they are joined into the new one 90 void addNewSearchResult(const std::list<std::pair<int, int> > &newlines) 91 throw(casa::AipsError); 110 92 private: 111 93 casa::CountedConstPtr<SDMemTable> scan; // the scan to work with … … 124 106 std::list<std::pair<int, int> > lines; // container of start and stop+1 125 107 // channels of the spectral lines 126 // statistics for running mean filtering127 casa::Float sum; // sum of fluxes128 casa::Float sumsq; // sum of squares of fluxes129 int box_chan_cntr; // actual number of channels in the box130 int max_box_nchan; // maximum allowed number of channels in the box131 // (calculated from boxsize and actual spectrum size)132 108 // a buffer for the spectrum 133 109 mutable casa::Vector<casa::Float> spectrum; 134 110 135 // temporary line edge channels and flag, which is True if the line136 // was detected in the previous channels.137 std::pair<int,int> cur_line;138 casa::Bool is_detected_before;139 111 }; 140 112 } // namespace asap
Note:
See TracChangeset
for help on using the changeset viewer.