@@ -170,261 +170,6 @@ def calc_sample_time(sampFr, startTime, posn):
170170 """
171171 return round (startTime + NcsSectionsFactory .get_micros_per_samp_for_freq (sampFr ) * posn )
172172
173- @staticmethod
174- def _parseGivenActualFrequency (ncsMemMap , ncsSects , chanNum , reqFreq , blkOnePredTime ):
175- """
176- Parse sections in memory mapped file when microsPerSampUsed and sampFreqUsed are known,
177- filling in an NcsSections object.
178-
179- Parameters
180- ----------
181- ncsMemMap:
182- memmap of Ncs file
183- ncsSections:
184- NcsSections with actual sampFreqUsed correct, first NcsSection with proper startSect
185- and startTime already added.
186- chanNum:
187- channel number that should be present in all records
188- reqFreq:
189- rounded frequency that all records should contain
190- blkOnePredTime:
191- predicted starting time of second record in block
192-
193- Returns
194- -------
195- NcsSections object with block locations marked
196- """
197-
198- # New code numpy vector based (speedup X50)
199- delta = (ncsMemMap ["timestamp" ][1 :] - ncsMemMap ["timestamp" ][:- 1 ]).astype (np .int64 )
200- delta_prediction = ((ncsMemMap ["nb_valid" ][:- 1 ] / ncsSects .sampFreqUsed ) * 1e6 ).astype (np .int64 )
201- gap_inds = np .flatnonzero ((delta - delta_prediction ) != 0 )
202- gap_inds += 1
203- sections_limits = [ 0 ] + gap_inds .tolist () + [len (ncsMemMap )]
204-
205- for i in range (len (gap_inds ) + 1 ):
206- start = sections_limits [i ]
207- stop = sections_limits [i + 1 ]
208- ncsSects .sects .append (
209- NcsSection (
210- startRec = start ,
211- startTime = ncsMemMap ["timestamp" ][start ],
212- endRec = stop - 1 ,
213- endTime = ncsMemMap ["timestamp" ][stop - 1 ] + np .uint64 (ncsMemMap ["nb_valid" ][stop - 1 ] / ncsSects .sampFreqUsed * 1e6 ),
214- n_samples = np .sum (ncsMemMap ["nb_valid" ][start :stop ])
215- )
216- )
217-
218- return ncsSects
219-
220- @staticmethod
221- def _buildGivenActualFrequency (ncsMemMap , actualSampFreq , reqFreq ):
222- """
223- Build NcsSections object for file given actual sampling frequency.
224-
225- Requires that frequency in each record agrees with requested frequency. This is
226- normally obtained by rounding the header frequency; however, this value may be different
227- from the rounded actual frequency used in the recording, since the underlying
228- requirement in older Ncs files was that the number of microseconds per sample in the
229- records is the inverse of the sampling frequency stated in the header truncated to
230- whole microseconds.
231-
232- Parameters
233- ----------
234- ncsMemMap:
235- memmap of Ncs file
236- actualSampFreq:
237- actual sampling frequency used
238- reqFreq:
239- frequency to require in records
240-
241- Returns
242- -------
243- NcsSections object
244- """
245- # check frequency in first record
246- if ncsMemMap ["sample_rate" ][0 ] != reqFreq :
247- raise IOError ("Sampling frequency in first record doesn't agree with header." )
248- chanNum = ncsMemMap ["channel_id" ][0 ]
249-
250- ncsSects = NcsSections ()
251- ncsSects .sampFreqUsed = actualSampFreq
252- ncsSects .microsPerSampUsed = NcsSectionsFactory .get_micros_per_samp_for_freq (actualSampFreq )
253-
254- # check if file is one block of records, which is often the case, and avoid full parse
255- lastBlkI = ncsMemMap .shape [0 ] - 1
256- ts0 = ncsMemMap ["timestamp" ][0 ]
257- nb0 = ncsMemMap ["nb_valid" ][0 ]
258- predLastBlockStartTime = NcsSectionsFactory .calc_sample_time (
259- actualSampFreq , ts0 , NcsSection ._RECORD_SIZE * lastBlkI
260- )
261- lts = ncsMemMap ["timestamp" ][lastBlkI ]
262- lnb = ncsMemMap ["nb_valid" ][lastBlkI ]
263- if (
264- ncsMemMap ["channel_id" ][lastBlkI ] == chanNum
265- and ncsMemMap ["sample_rate" ][lastBlkI ] == reqFreq
266- and lts == predLastBlockStartTime
267- ):
268- lastBlkEndTime = NcsSectionsFactory .calc_sample_time (actualSampFreq , lts , lnb )
269- n_samples = NcsSection ._RECORD_SIZE * lastBlkI
270- curBlock = NcsSection (0 , ts0 , lastBlkI , lastBlkEndTime , n_samples )
271-
272- ncsSects .sects .append (curBlock )
273- return ncsSects
274-
275-
276- else :
277- # otherwise need to scan looking for data gaps
278- blkOnePredTime = NcsSectionsFactory .calc_sample_time (actualSampFreq , ts0 , nb0 )
279- # curBlock = NcsSection(0, ts0, -1, -1, -1)
280- # ncsSects.sects.append(curBlock)
281- ncsSects = NcsSectionsFactory ._parseGivenActualFrequency (ncsMemMap , ncsSects , chanNum , reqFreq , blkOnePredTime )
282- return ncsSects
283-
284- @staticmethod
285- def _parseForMaxGap (ncsMemMap , ncsSects , maxGapLen ):
286- """
287- Parse blocks of records from file, allowing a maximum gap in timestamps between records
288- in sections. Estimates frequency being used based on timestamps.
289-
290- Parameters
291- ----------
292- ncsMemMap:
293- memmap of Ncs file
294- ncsSects:
295- NcsSections object with sampFreqUsed set to nominal frequency to use in computing time
296- for samples (Hz)
297- maxGapLen:
298- maximum difference within a block between predicted time of start of record and
299- recorded time
300-
301- Returns
302- -------
303- NcsSections object with sampFreqUsed and microsPerSamp set based on estimate from
304- largest block
305- """
306-
307- chanNum = ncsMemMap ["channel_id" ][0 ]
308- recFreq = ncsMemMap ["sample_rate" ][0 ]
309-
310- # check for consistent channel_ids and sampling rates
311- ncsMemMap ["channel_id" ]
312- if not (ncsMemMap ["channel_id" ] == chanNum ).all ():
313- raise IOError ("Channel number changed in records within file" )
314-
315- if not all (ncsMemMap ["sample_rate" ] == recFreq ):
316- raise IOError ("Sampling frequency changed in records within file" )
317-
318- # find most frequent number of samples
319- exp_nb_valid = np .argmax (np .bincount (ncsMemMap ["nb_valid" ]))
320- # detect records with incomplete number of samples
321- gap_rec_ids = list (np .where (ncsMemMap ["nb_valid" ] != exp_nb_valid )[0 ])
322-
323- rec_duration = 1e6 / ncsSects .sampFreqUsed * ncsMemMap ["nb_valid" ]
324- pred_times = np .rint (ncsMemMap ["timestamp" ] + rec_duration ).astype (np .int64 )
325- max_pred_times = pred_times + maxGapLen
326- # data records that start later than the predicted time (including the
327- # maximal accepted gap length) are considered delayed and a gap is
328- # registered.
329- delayed_recs = list (np .where (max_pred_times [:- 1 ] < ncsMemMap ["timestamp" ][1 :])[0 ])
330- gap_rec_ids .extend (delayed_recs )
331-
332- # cleaning extracted gap ids
333- # last record can not be the beginning of a gap
334- last_rec_id = len (ncsMemMap ["timestamp" ]) - 1
335- if last_rec_id in gap_rec_ids :
336- gap_rec_ids .remove (last_rec_id )
337-
338- # gap ids can only be listed once
339- gap_rec_ids = sorted (set (gap_rec_ids ))
340-
341- # create recording segments from identified gaps
342- ncsSects .sects .append (NcsSection (0 , ncsMemMap ["timestamp" ][0 ], - 1 , - 1 , - 1 ))
343- for gap_rec_id in gap_rec_ids :
344- curr_sec = ncsSects .sects [- 1 ]
345- curr_sec .endRec = gap_rec_id
346- curr_sec .endTime = pred_times [gap_rec_id ]
347- n_samples = np .sum (ncsMemMap ["nb_valid" ][curr_sec .startRec : gap_rec_id + 1 ])
348- curr_sec .n_samples = n_samples
349-
350- next_sec = NcsSection (gap_rec_id + 1 , ncsMemMap ["timestamp" ][gap_rec_id + 1 ], - 1 , - 1 , - 1 )
351- ncsSects .sects .append (next_sec )
352-
353- curr_sec = ncsSects .sects [- 1 ]
354- curr_sec .endRec = len (ncsMemMap ["timestamp" ]) - 1
355- curr_sec .endTime = pred_times [- 1 ]
356- n_samples = np .sum (ncsMemMap ["nb_valid" ][curr_sec .startRec :])
357- curr_sec .n_samples = n_samples
358-
359- # calculate the estimated frequency of the block with the most samples
360- max_blk_idx = np .argmax ([bl .endRec - bl .startRec for bl in ncsSects .sects ])
361- max_blk = ncsSects .sects [max_blk_idx ]
362-
363- maxBlkFreqEstimate = (
364- (max_blk .n_samples - ncsMemMap ["nb_valid" ][max_blk .endRec ])
365- * 1e6
366- / (ncsMemMap ["timestamp" ][max_blk .endRec ] - max_blk .startTime )
367- )
368-
369- ncsSects .sampFreqUsed = maxBlkFreqEstimate
370- ncsSects .microsPerSampUsed = NcsSectionsFactory .get_micros_per_samp_for_freq (maxBlkFreqEstimate )
371- # free memory that is unnecessarily occupied by the memmap
372- # (see https://github.com/numpy/numpy/issues/19340)
373- del ncsMemMap
374- return ncsSects
375-
376- @staticmethod
377- def _buildForMaxGap (ncsMemMap , nomFreq ):
378- """
379- Determine sections of records in memory mapped Ncs file given a nominal frequency of
380- the file, using the default values of frequency tolerance and maximum gap between blocks.
381-
382- Parameters
383- ----------
384- ncsMemMap:
385- memmap of Ncs file
386- nomFreq:
387- nominal sampling frequency used, normally from header of file
388-
389- Returns
390- -------
391- NcsSections object
392- """
393- nb = NcsSections ()
394-
395- numRecs = ncsMemMap .shape [0 ]
396- if numRecs < 1 :
397- return nb
398-
399- chanNum = ncsMemMap ["channel_id" ][0 ]
400- ts0 = ncsMemMap ["timestamp" ][0 ]
401-
402- lastBlkI = numRecs - 1
403- lts = ncsMemMap ["timestamp" ][lastBlkI ]
404- lcid = ncsMemMap ["channel_id" ][lastBlkI ]
405- lnb = ncsMemMap ["nb_valid" ][lastBlkI ]
406- lsr = ncsMemMap ["sample_rate" ][lastBlkI ]
407-
408- # check if file is one block of records, with exact timestamp match, which may be the case
409- numSampsForPred = NcsSection ._RECORD_SIZE * lastBlkI
410- predLastBlockStartTime = NcsSectionsFactory .calc_sample_time (nomFreq , ts0 , numSampsForPred )
411- freqInFile = math .floor (nomFreq )
412- if lts - predLastBlockStartTime == 0 and lcid == chanNum and lsr == freqInFile :
413- endTime = NcsSectionsFactory .calc_sample_time (nomFreq , lts , lnb )
414- curBlock = NcsSection (0 , ts0 , lastBlkI , endTime , numSampsForPred )
415- nb .sects .append (curBlock )
416- nb .sampFreqUsed = (numSampsForPred + lnb ) / (endTime - ts0 ) * 1e6
417- nb .microsPerSampUsed = NcsSectionsFactory .get_micros_per_samp_for_freq (nb .sampFreqUsed )
418-
419- # otherwise parse records to determine blocks using default maximum gap length
420- else :
421- nb .sampFreqUsed = nomFreq
422- nb .microsPerSampUsed = NcsSectionsFactory .get_micros_per_samp_for_freq (nb .sampFreqUsed )
423- maxGapToAllow = round (NcsSectionsFactory ._maxGapSampFrac * 1e6 / nomFreq )
424- nb = NcsSectionsFactory ._parseForMaxGap (ncsMemMap , nb , maxGapToAllow )
425-
426- return nb
427-
428173 @staticmethod
429174 def _buildNcsGeneric (ncsMemMap , sampFreq , gapTolerance = 0 ):
430175 """
0 commit comments