- Timestamp:
- 02/05/05 15:55:56 (20 years ago)
- Location:
- trunk/src
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/SDLineFinder.cc
r352 r368 430 430 if (running_box!=NULL) delete running_box; 431 431 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 433 457 // actual search algorithm 434 458 is_detected_before=False; 435 459 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()) { 438 464 const int ch=running_box->getChannel(); 439 465 if (running_box->getNumberOfBoxPoints()>=minboxnchan) 440 466 processChannel(mask[ch] && (fabs(running_box->aboveMean()) >= 441 threshold* running_box->getLinVariance()), mask);467 threshold*offline_variance), mask); 442 468 else processCurLine(mask); // just finish what was accumulated before 443 469 const Float buf=running_box->aboveMean(); 444 470 if (buf>0) signs[ch]=1; 445 471 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; 447 475 } 448 476 if (lines.size()) … … 551 579 { 552 580 // 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 554 583 box_size=1./5.; // default box size for running mean calculations is 555 584 // 1/5 of the whole spectrum … … 621 650 // search for spectral lines. Number of lines found is returned 622 651 int SDLineFinder::findLines() throw(casa::AipsError) 623 { 652 { 624 653 const int minboxnchan=4; 625 654 if (scan.null()) … … 638 667 639 668 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 640 673 while (true) { 641 674 // 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; 644 676 // line find algorithm 645 LFAboveThreshold lfalg(new_lines, min_nchan, threshold);677 LFAboveThreshold lfalg(new_lines,avg_factor*min_nchan, threshold); 646 678 647 679 try { 648 680 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 649 685 } 650 686 catch(const AipsError &ae) { 651 687 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; 653 695 } 654 first_pass=False; 655 if (!new_lines.size()) break; // nothing new 656 696 keepStrongestOnly(temp_mask,new_lines,max_box_nchan); 657 697 // update the list (lines) merging intervals, if necessary 658 698 addNewSearchResult(new_lines,lines); … … 661 701 } 662 702 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 711 void 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 } 663 736 } 664 737 … … 747 820 } 748 821 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 835 void 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 749 883 // 750 884 /////////////////////////////////////////////////////////////////////////////// -
trunk/src/SDLineFinder.h
r352 r368 161 161 std::vector<int> getLineRanges(bool defunits=true) 162 162 const throw(casa::AipsError); 163 protected: 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); 163 191 private: 164 192 casa::CountedConstPtr<SDMemTable> scan; // the scan to work with
Note:
See TracChangeset
for help on using the changeset viewer.