Ejemplo n.º 1
0
def interpolateToSecond(timeData: TimeData, inplace: bool = True) -> TimeData:
    """Interpolate data to be on the second

    Some formats of time data (e.g. SPAM) do not start on the second with their sampling. This method interpolates so that sampling starts on the second and improves interoperability with other recording formats. 

    Parameters
    ----------
    timeData : TimeData
        Time data to interpolate onto the second
    inplace :  bool, optional
        Whether to do the interpolation inplace or not. Default is True.
    
    Returns
    -------
    TimeData
        Time data interpolated to start on the second
    """
    startTimeInterp, numSamplesInterp, dataInterp = interpolateToSecondData(
        timeData.data, timeData.sampleFreq, timeData.startTime
    )
    if not inplace:
        timeData = timeData.copy()
    timeData.numSamples = numSamplesInterp
    timeData.startTime = startTimeInterp
    # calculate end timeEnd
    timeData.stopTime = timeData.startTime + timedelta(
        seconds=(1.0 / timeData.sampleFreq) * (timeData.numSamples - 1)
    )
    timeData.data = dataInterp
    timeData.addComment(
        "Time data interpolated to nearest second. New start time {}, new end time {}, new number of samples {} ".format(
            timeData.startTime, timeData.stopTime, timeData.numSamples
        )
    )
    return timeData
Ejemplo n.º 2
0
def resample(timeData: TimeData, resampFreq: float, inplace: bool = True) -> TimeData:
    """Resample time data
    
    Parameters
    ----------
    timeData : TimeData
        timeData to filter
    resampFreq : float
        The frequency to resample to
    inplace : bool, optional
        Whether to manipulate the data inplace        

    Returns
    -------
    TimeData
        Filtered time data
    """
    origFreq = timeData.sampleFreq
    if not inplace:
        timeData = timeData.copy()
    timeData.data = resampleData(timeData.data, timeData.sampleFreq, resampFreq)
    # update the time info
    timeData.sampleFreq = resampFreq
    timeData.numSamples = timeData.data[timeData.chans[0]].size
    timeData.stopTime = timeData.startTime + timedelta(
        seconds=(1.0 / timeData.sampleFreq) * (timeData.numSamples - 1)
    )
    timeData.addComment(
        "Time data resampled from {:.6f} Hz to {:.6f} Hz".format(origFreq, resampFreq)
    )
    return timeData
Ejemplo n.º 3
0
    def write(self, headers: Dict, chanHeaders: List, chanMap: Dict,
              timeData: TimeData, **kwargs):
        """Write out the header file

        Parameters
        ----------
        headers : Dict
            Dictionary of headers
        chanHeaders : List
            List of channel headers
        chanMap : Dict
            Maps channel to index for chanHeaders    
        timeData : TimeData
            Time series data as TimeData object        
        """
        # set global headers for keyword arguments
        headers = self.setGlobalHeadersFromKeywords(headers, kwargs)
        # set channel headers for keyword arguments
        chanHeaders = self.setChanHeadersFromKeywords(chanHeaders, kwargs)

        # now overwrite the options by checking the TimeData object
        # number of samples and sample frequency
        # Current method favours the time data object
        chans = sorted(list(timeData.chans))
        dataSizes = []
        for c in chans:
            dataSizes.append(timeData.data[c].size)
        if min(dataSizes) != max(dataSizes):
            self.printWarning(
                "Channels do not have the same number of samples: {} - {}".
                format(", ".join(chans), ", ".join(dataSizes)))
            self.printWarning(
                "Only the smallest number of samples will be written out")
        numSamples = min(dataSizes)
        if headers["num_samples"] != numSamples:
            self.printWarning(
                "Number of samples {} in headers does not match number of samples in TimeData object {}. TimeData info will be used."
                .format(headers["num_samples"], numSamples))
            headers["num_samples"] = numSamples
        timeData.numSamples = numSamples
        # sample freq
        if headers["sample_freq"] != timeData.sampleFreq:
            self.printWarning(
                "Sample frequency of {} Hz in headers does not match {} Hz in TimeData object"
                .format(headers["sample_freq"], timeData.sampleFreq))
            self.printWarning(
                "Sample frequency in TimeData object will be used")
            headers["sample_freq"] = timeData.sampleFreq

        # deal with start and end time and create datetime objects
        # the start time does not change on resampling, only the end time
        datetimeStart = datetime.strptime(
            "{} {}".format(headers["start_date"], headers["start_time"]),
            "%Y-%m-%d %H:%M:%S.%f",
        )
        datetimeStop = datetime.strptime(
            "{} {}".format(headers["stop_date"], headers["stop_time"]),
            "%Y-%m-%d %H:%M:%S.%f",
        )
        # now let's compare to the time data
        if datetimeStart != timeData.startTime:
            self.printWarning(
                "Start in headers {} does not match that in TimeData object {}. TimeData start time will be used"
                .format(datetimeStart, timeData.startTime))
            datetimeStart = timeData.startTime
        if datetimeStop != timeData.stopTime:
            self.printWarning(
                "Stop in headers {} does not match that in TimeData object {}. TimeData stop time will be used"
                .format(datetimeStop, timeData.stopTime))
            datetimeStop = timeData.stopTime
        # now recalculate datetime using the number of samples and compare again
        datetimeRecalc = self.calcStopDateTime(timeData.sampleFreq, numSamples,
                                               datetimeStart)
        if datetimeRecalc != datetimeStop:
            self.printWarning(
                "Note, discrepancy between stop time in given headers and those calculated from data"
            )
            self.printWarning(
                "Causes of this might be resampling or interpolation processes and the limiting of data"
            )
            self.printWarning(
                "If no resampling, interpolation or limiting of data has been performed, please check all times"
            )
            self.printWarning(
                "Stop time {} calculated from data will be used instead of that in data {}"
                .format(datetimeRecalc, datetimeStop))
            datetimeStop = datetimeRecalc
        headers["start_date"] = datetimeStart.strftime("%Y-%m-%d")
        headers["start_time"] = datetimeStart.strftime("%H:%M:%S.%f")
        headers["stop_date"] = datetimeStop.strftime("%Y-%m-%d")
        headers["stop_time"] = datetimeStop.strftime("%H:%M:%S.%f")

        # now update all the chan headers and limit data to numSamples
        for c in chans:
            timeData.data[c] = timeData.data[c][:numSamples]
            cIndex = chanMap[c]
            chanHeaders[cIndex]["num_samples"] = headers["num_samples"]
            chanHeaders[cIndex]["sample_freq"] = headers["sample_freq"]
            chanHeaders[cIndex]["start_date"] = headers["start_date"]
            chanHeaders[cIndex]["start_time"] = headers["start_time"]
            chanHeaders[cIndex]["stop_date"] = headers["stop_date"]
            chanHeaders[cIndex]["stop_time"] = headers["stop_time"]

        # finally, check the number of measurement channels
        headers["meas_channels"] = len(chans)

        # now write out the headers and save to class variables
        self.writeHeaders(headers, chans, chanMap, chanHeaders)
        self.headers = headers
        self.chans = chans
        self.chanMap = chanMap
        self.chanHeaders = chanHeaders
        # write out comment file
        self.writeComments(timeData.comments)
        # write out the data files
        self.writeDataFiles(chans, timeData)