def ingest_data(self, data, modeled=True, length_fit=False):
        self.BM = BodyModel(data)
        if length_fit:
            self.BM.fit()
        self.data = data
        if modeled:
            n = normalize_data({'kin': self.BM.data})['kin']
            X = np.column_stack((n[key] for key in KL))
            self.model_data = normalize_rows(X)

        times = self.data['Time']
        newtimes = np.linspace(times[0], times[-1], 1000)

        self.times = times
        self.newtimes = newtimes

        floor = self.floor if self.floor else 0.5 * (np.mean(self.data['FootRight'].T[2]) + np.mean(self.data['FootLeft'].T[2]))
        #if (floor == None): floor = 0.5 * (np.mean(self.data['FootRight'].T[2]) + np.mean(self.data['FootLeft'].T[2]))
        vl = VL(self.BM.data, floor=floor)
        modeled_vl = vl + VLm(self.model_data) if modeled else vl
        subsampled_vl = UnivariateSpline(times, modeled_vl, s=0)(newtimes)
        self.smoothed_VL = UnivariateSpline(newtimes, sav_gol.savgol_filter(subsampled_vl, 31, 3), s=0) # smooth pretty hard to stop wobbling, overest?

        hl = HL(self.BM.data)
        modeled_hl = hl + HLm(self.model_data) if modeled else hl
        subsampled_hl = UnivariateSpline(times, modeled_hl, s=0)(newtimes)
        self.smoothed_HL = UnivariateSpline(newtimes, sav_gol.savgol_filter(subsampled_hl, 31, 3), s=0) # smooth pretty hard to stop wobbling, overest?

        aa = AA(self.BM.data)
        modeled_aa = aa + AAm(self.model_data) if modeled else aa
        subsampled_aa = UnivariateSpline(times, modeled_aa, s=0)(newtimes)
        self.smoothed_AA = UnivariateSpline(newtimes, sav_gol.savgol_filter(subsampled_aa, 31, 3), s=0) # smooth pretty hard to stop wobbling, overest?

        self.find_F()
        # self.find_origins()
        # self.find_ends()
        self.find_V()
        self.find_H()
        self.find_D()
        self.find_A()
class LiftingEquation(object):
    def __init__(self, data=None, modeled=True, length_fit=False, floor=-2):
        self.floor = floor
        self.V = None # VerticalLocation at upper limit of reach
        self.H = None
        self.D = None # vertical distance traveled
        self.A = None
        self.F = None # lifts per minute
        self.origins = None # lift start times
        self.ends = None # lift end times
        self.BM = None # body model: fit to lengths
        self.data = None
        self.smoothed_VL = None
        self.times = None
        self.newtimes = None
        if not data is None:
            self.ingest_data(data, modeled=modeled, length_fit=length_fit)

    def ingest_data(self, data, modeled=True, length_fit=False):
        self.BM = BodyModel(data)
        if length_fit:
            self.BM.fit()
        self.data = data
        if modeled:
            n = normalize_data({'kin': self.BM.data})['kin']
            X = np.column_stack((n[key] for key in KL))
            self.model_data = normalize_rows(X)

        times = self.data['Time']
        newtimes = np.linspace(times[0], times[-1], 1000)

        self.times = times
        self.newtimes = newtimes

        floor = self.floor if self.floor else 0.5 * (np.mean(self.data['FootRight'].T[2]) + np.mean(self.data['FootLeft'].T[2]))
        #if (floor == None): floor = 0.5 * (np.mean(self.data['FootRight'].T[2]) + np.mean(self.data['FootLeft'].T[2]))
        vl = VL(self.BM.data, floor=floor)
        modeled_vl = vl + VLm(self.model_data) if modeled else vl
        subsampled_vl = UnivariateSpline(times, modeled_vl, s=0)(newtimes)
        self.smoothed_VL = UnivariateSpline(newtimes, sav_gol.savgol_filter(subsampled_vl, 31, 3), s=0) # smooth pretty hard to stop wobbling, overest?

        hl = HL(self.BM.data)
        modeled_hl = hl + HLm(self.model_data) if modeled else hl
        subsampled_hl = UnivariateSpline(times, modeled_hl, s=0)(newtimes)
        self.smoothed_HL = UnivariateSpline(newtimes, sav_gol.savgol_filter(subsampled_hl, 31, 3), s=0) # smooth pretty hard to stop wobbling, overest?

        aa = AA(self.BM.data)
        modeled_aa = aa + AAm(self.model_data) if modeled else aa
        subsampled_aa = UnivariateSpline(times, modeled_aa, s=0)(newtimes)
        self.smoothed_AA = UnivariateSpline(newtimes, sav_gol.savgol_filter(subsampled_aa, 31, 3), s=0) # smooth pretty hard to stop wobbling, overest?

        self.find_F()
        # self.find_origins()
        # self.find_ends()
        self.find_V()
        self.find_H()
        self.find_D()
        self.find_A()

    def find_F(self):
        # currently a kludge: do some simple fourier stuff
        # coming up: HMM or something like that to recognize the lifting motions
        # then count the in the period of interest
        # and use the lift characterization (maybe plus some local max/min) to find starts/ends
        times = self.data['Time']
        subtimes = np.linspace(times[0], times[-1], 1000)
        Zs = np.array(self.data['HandRight']).T[2] + np.array(self.data['HandLeft']).T[2]
        subZ = UnivariateSpline(times, Zs, s=0.5)(subtimes)
        Fs = subZ - np.mean(subZ)
        FF = rfft(Fs)
        mgft = np.abs(FF)
        i = np.argmax(mgft)
        self.F = fftfreq(len(Fs), (times[-1] - times[0]) / 60000.0)[i] # cycles per minute for dominant component
        filtered = irfft([FF[i] if i <= self.F else 0 for i in range(len(FF))])
        self.filtered = filtered
        self.origins = subtimes[argrelmin(filtered)]  # will need to pay attention to accidental near peaks
        self.ends = subtimes[argrelmax(filtered)]
        self.refine_origins()
        self.refine_ends()

    def refine_origins(self):
        if (self.origins is None): self.find_F()
        vls = self.smoothed_VL(self.times)
        raw_mins = self.times[argrelmin(vls)]
        self.origins = raw_mins[np.array([np.argmin(np.abs(raw_mins - orig)) for orig in self.origins])]

    def refine_ends(self):
        if (self.origins is None): self.find_F()
        vls = self.smoothed_VL(self.times)
        raw_maxs = self.times[argrelmax(vls)]
        self.ends = raw_maxs[np.array([np.argmin(np.abs(raw_maxs - en)) for en in self.ends])]
    
    def lows(self):
        vls = self.smoothed_VL(self.times)
        raw_mins = self.times[argrelmin(vls)]
        return raw_mins[np.array([np.argmin(np.abs(raw_mins - orig)) for orig in self.origins])]
    
    def highs(self):
        vls = self.smoothed_VL(self.times)
        raw_maxs = self.times[argrelmax(vls)]
        return raw_maxs[np.array([np.argmin(np.abs(raw_maxs - en)) for en in self.ends])]

    def find_V(self):
        self.V = np.mean(self.smoothed_VL(self.origins))

    def find_D(self):
        self.D = np.mean(self.smoothed_VL(self.ends)) - np.mean(self.smoothed_VL(self.origins))

    def find_H(self):
        self.H = np.mean(self.smoothed_HL(self.origins))

    def find_A(self):
        self.A = np.mean(self.smoothed_AA(self.origins))

    def HM(self):
        return 25.0 / max(25.0, 100 * self.H)

    def VM(self):
        return 1 - (0.003 * np.abs(max(0, min(175, 100 * self.V)) - 75))

    def DM(self):
        return 0.82 + 4.5 / min(max(25.0, 100 * self.D), 175)

    def AM(self):
        return 1 - 0.0032 * self.A if self.A < 135 else 0

    def FM(self, duration): # frequency multiplier, ave lifts per min over 15 mins
    # read about durations, etc.
        i = np.argmin(np.abs(self.F - FREQUENCIES))
        mult = duration_multiplier(duration, i, self.V)
        return FM_BASE_COLS[duration][i] * mult

    def CM(self, coupling): # coupling multiplier
        if self.V >= 30 * 2.54:
            return COUPLINGS[coupling][1]
        else:
            return COUPLINGS[coupling][0]

    def RWL(self, duration, coupling):
        return LC * self.HM() * self.VM() * self.DM() * \
               self.AM() * self.FM(duration) * self.CM(coupling)

    def print_all(self, duration=2, coupling='Fair'):
        print "V at origin: {0}".format(self.V)
        print "H: {0}".format(self.H)
        print "D: {0}".format(self.D)
        print "A: {0}".format(self.A)
        print "F: {0}".format(self.F)
        print "RWL: {0}".format(self.RWL(duration=duration, coupling=coupling))