Changeset 1826 for trunk/python/simplelinefinder.py
- Timestamp:
- 08/03/10 11:41:13 (14 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/python/simplelinefinder.py
r1823 r1826 1 1 import math 2 from asap import asaplog2 from asap.logging import asaplog 3 3 4 4 class StatCalculator: … … 7 7 self.s2=0. 8 8 self.cnt=0 9 9 10 10 def mean(self): 11 11 if self.cnt<=0: 12 12 raise RuntimeError, "At least one data point has to be defined" 13 13 return self.s/float(self.cnt) 14 14 15 15 def variance(self): 16 16 if self.cnt<=1: 17 17 raise RuntimeError, "At least two data points has to be defined" 18 18 return math.sqrt((self.s2/self.cnt)-(self.s/self.cnt)**2+1e-12) 19 19 20 20 def rms(self): 21 21 """ … … 25 25 raise RuntimeError, "At least one data point has to be defined" 26 26 return math.sqrt(self.s2/self.cnt) 27 27 28 28 def add(self, pt): 29 29 self.s = self.s + pt … … 36 36 A simplified class to search for spectral features. The algorithm assumes that the bandpass 37 37 is taken out perfectly and no spectral channels are flagged (except some edge channels). 38 It works with a list or tuple rather than a scantable and returns the channel pairs. 38 It works with a list or tuple rather than a scantable and returns the channel pairs. 39 39 There is an optional feature to attempt to split the detected lines into components, although 40 it should be used with caution. This class is largely intended to be used with scripts. 41 40 it should be used with caution. This class is largely intended to be used with scripts. 41 42 42 The fully featured version of the algorithm working with scantables is called linefinder. 43 43 ''' 44 44 45 45 def __init__(self): 46 46 ''' 47 Initialize the class. 47 Initialize the class. 48 48 ''' 49 49 self._median = None 50 50 self._rms = None 51 51 52 52 def writeLog(self, str): 53 53 """ 54 54 Write user defined string into log file 55 """ 55 """ 56 56 asaplog.push(str) 57 57 58 58 def invertChannelSelection(self, nchan, chans, edge = (0,0)): 59 59 """ 60 This method converts a tuple with channel ranges to a tuple which covers all channels 60 This method converts a tuple with channel ranges to a tuple which covers all channels 61 61 not selected by the original tuple (optionally edge channels can be discarded) 62 63 nchan - number of channels in the spectrum. 62 63 nchan - number of channels in the spectrum. 64 64 chans - tuple (with even number of elements) containing start and stop channel for all selected ranges 65 65 edge - one number or two element tuple (separate values for two ends) defining how many channels to reject … … 69 69 """ 70 70 if nchan<=1: 71 raise RuntimeError, "Number of channels is supposed to be at least 2, you have %i"% nchan 71 raise RuntimeError, "Number of channels is supposed to be at least 2, you have %i"% nchan 72 72 if len(chans)%2!=0: 73 73 raise RuntimeError, "chans is supposed to be a tuple with even number of elements" … … 106 106 spc - tuple with the spectrum (first is the vector of abcissa values, second is the spectrum itself) 107 107 vel_range - a 2-element tuple with start and stop velocity of the range 108 108 109 109 return: a 2-element tuple with channels 110 110 Note, if supplied range is completely outside the spectrum, an empty tuple will be returned … … 145 145 """ 146 146 A helper method to compare x and y by absolute value (to do sorting) 147 147 148 148 x - first value 149 149 y - second value 150 150 151 151 return -1,0 or 1 depending on the result of comparison 152 152 """ … … 157 157 else: 158 158 return 0 159 159 160 160 def rms(self): 161 161 """ … … 167 167 raise RuntimeError, "call find_lines before using the rms method" 168 168 return self._rms 169 169 170 170 def median(self): 171 171 """ … … 176 176 raise RuntimeError, "call find_lines before using the median method" 177 177 return self._median 178 178 179 179 def _mergeIntervals(self, lines, spc): 180 180 """ 181 181 A helper method to merge intervals. 182 182 183 183 lines - list of tuples with first and last channels of all intervals 184 184 spc - spectrum (to be able to test whether adjacent intervals have the … … 196 196 raise RuntimeError, "this shouldn't have happened!" 197 197 lines.pop(toberemoved[i]) 198 198 199 199 def _splitIntervals(self,lines,spc,threshold=3,minchan=3): 200 200 """ … … 203 203 Noise is dealt with by taking into account only those extrema, where a difference with 204 204 respect to surrounding spectral points exceeds threshold times rms (stored inside this 205 class, so the main body of the line detection should be executed first) and there are 206 at least minchan such points. 205 class, so the main body of the line detection should be executed first) and there are 206 at least minchan such points. 207 207 """ 208 208 if minchan<1: … … 219 219 if wasIncreasing != None: 220 220 if isIncreasing != wasIncreasing: 221 derivSignReversals.append((ch,isIncreasing)) 221 derivSignReversals.append((ch,isIncreasing)) 222 222 wasIncreasing = isIncreasing 223 223 if len(derivSignReversals)==0: … … 237 237 newlines.append((startchan,line[1])) 238 238 return newlines 239 239 240 240 def find_lines(self,spc,threshold=3,edge=0,minchan=3, tailsearch = True, splitFeatures = False): 241 241 """ … … 243 243 taken out perfectly and no channels are flagged within the spectrum. A detection 244 244 is reported if consequtive minchan number of channels is consistently above or 245 below the median value. The threshold is given in terms of the rms calculated 246 using 80% of the lowest data points by the absolute value (with respect to median) 247 245 below the median value. The threshold is given in terms of the rms calculated 246 using 80% of the lowest data points by the absolute value (with respect to median) 247 248 248 spc - a list or tuple with the spectrum, no default 249 249 threshold - detection threshold, default is 3 sigma, see above for the definition … … 254 254 tailsearch - if True (default), the algorithm attempts to widen each line until 255 255 its flux crosses the median. It merges lines if necessary. Set this 256 option off if you need to split the lines according to some criterion 256 option off if you need to split the lines according to some criterion 257 257 splitFeatures - if True, the algorithm attempts to split each detected spectral feature into 258 258 a number of spectral lines (just one local extremum). The default action is 259 259 not to do it (may give an adverse results if the noise is high) 260 260 261 261 This method returns a list of tuples each containing start and stop 0-based channel 262 262 number of every detected line. Empty list if nothing has been detected. 263 263 264 264 Note. The median and rms about this median is stored inside this class and can 265 265 be obtained with rms and median methods. … … 270 270 raise RuntimeError, "edge is too high (%i), you rejected all channels (%i)" % (edge, len(spc)) 271 271 if threshold<=0: 272 raise RuntimeError, "threshold parameter of find_lines should be positive, you have %s" % threshold 272 raise RuntimeError, "threshold parameter of find_lines should be positive, you have %s" % threshold 273 273 if minchan<=0: 274 274 raise RuntimeError, "minchan parameter of find_lines should be positive, you have %s" % minchan 275 276 # temporary storage to get statistics, apply edge rejection here 275 276 # temporary storage to get statistics, apply edge rejection here 277 277 tmpspc = spc[edge:len(spc)-edge+1] 278 278 if len(tmpspc)<2: 279 raise RuntimeError, "Too many channels are rejected. Decrease edge parameter or provide a longer spectrum." 279 raise RuntimeError, "Too many channels are rejected. Decrease edge parameter or provide a longer spectrum." 280 280 tmpspc.sort() 281 281 self._median=tmpspc[len(tmpspc)/2] … … 286 286 sc = StatCalculator() 287 287 for i in tmpspc[:-int(0.2*len(tmpspc))]: 288 sc.add(i) 288 sc.add(i) 289 289 self._rms=sc.rms() 290 291 self.writeLog("Spectral line detection with edge=%i, threshold=%f, minchan=%i and tailsearch=%s" % (edge,threshold, minchan, tailsearch)) 292 self.writeLog("statistics: median=%f, rms=%f" % (self._median, self._rms)) 293 290 291 self.writeLog("Spectral line detection with edge=%i, threshold=%f, minchan=%i and tailsearch=%s" % (edge,threshold, minchan, tailsearch)) 292 self.writeLog("statistics: median=%f, rms=%f" % (self._median, self._rms)) 293 294 294 #actual line detection 295 295 lines=[] … … 319 319 if nchan>=minchan: 320 320 lines.append((startchan,len(spc)-edge-1)) 321 321 322 322 if tailsearch: 323 323 for i in range(len(lines)): … … 325 325 curRange = list(lines[i]) 326 326 for x in range(curRange[0],edge,-1): 327 isAbove=(spc[x] > self._median) 327 isAbove=(spc[x] > self._median) 328 328 if wasAbove == None: 329 329 wasAbove = isAbove … … 332 332 break 333 333 for x in range(curRange[1],len(spc)-edge): 334 isAbove=(spc[x] > self._median) 334 isAbove=(spc[x] > self._median) 335 335 if isAbove!=wasAbove: 336 336 curRange[1]=x-1 337 337 break 338 338 lines[i]=tuple(curRange) 339 self._mergeIntervals(lines,spc) 339 self._mergeIntervals(lines,spc) 340 340 if splitFeatures: 341 341 return self._splitIntervals(lines,spc,threshold,minchan) 342 return lines 342 return lines
Note: See TracChangeset
for help on using the changeset viewer.