Beispiel #1
0
def process_walk(walk_id, force=False):

    if not model.process_check(walk_id):
        log.error("Walk %s already processed" % walk_id)
        if force:
            log.info("--> forcing...")
            model.remove_sequence(walk_id)
        else:
            return
    log.info("Processing walk %s" % walk_id)

    # fetch data
    data = model.fetch_accels(walk_id)
    data = [(reading['t'], reading['x'], reading['y'], reading['z'])
            for reading in data]

    # let's sample every millisecond, so the time of the last reading is how many samples we need
    data = np.array(data)
    ts = data[:, 0]
    total_samples = int(ts[-1])

    # need at least 10s of data
    # add 2000 for trimming at nd
    if total_samples < 10000 + 2000:
        log.info("No footsteps detected (too short)")
        model.hide(walk_id)
        return

    # resample the values
    xs = sp.resample(ts, data[:, 1], total_samples)
    ys = sp.resample(ts, data[:, 2], total_samples)
    zs = sp.resample(ts, data[:, 3], total_samples)

    # skip for accelerometer startup and for phone out of pocket at end
    skipin, skipout = 0, 2000
    xs = xs[skipin:-skipout]
    ys = ys[skipin:-skipout]
    zs = zs[skipin:-skipout]
    total_samples -= (skipin + skipout)
    log.info("TOTAL SAMPLES %s (%fs)" % (total_samples,
                                         (total_samples / 1000.0)))

    # get 3d magnitude (not RMS) -- orientation shouldnt matter
    ds = np.sqrt(np.power(xs, 2) + np.power(ys, 2) + np.power(zs, 2))

    # prep the raw values for display
    # normalize the values to a given range  (this is Gs)
    MIN = -10.0
    MAX = 10.0
    xs = (xs - MIN) / (MAX - MIN)
    ys = (ys - MIN) / (MAX - MIN)
    zs = (zs - MIN) / (MAX - MIN)
    # smooth them
    xs = sp.smooth(xs, 300)
    ys = sp.smooth(ys, 300)
    zs = sp.smooth(zs, 300)

    # process the magnitude signal
    ds = sp.smooth(ds, 500)
    ds = np.clip(ds, -10.0, 10.0)  # limit the signal to +-10 Gs
    ds = sp.normalize(ds)
    ds = 1 - ds
    ds = sp.compress(ds, 3.0)
    ds = sp.normalize(ds)

    # detect peaks
    peaks, valleys = sp.detect_peaks(ds, lookahead=50, delta=0.10)
    peaks = np.array(peaks)
    valleys = np.array(valleys)
    log.info("PEAKS %s" % len(peaks))
    if not len(peaks):
        log.info("No footsteps detected")
        model.hide(walk_id)
        return

    # get foot separator line
    fxs = [int(peak[0]) for peak in peaks]
    fys = [peak[1] for peak in peaks]
    avs = np.average([peak[1] for peak in peaks])
    fys[0] = avs  # it's going to start with a peak, so we need to bring it up or down accordingly
    fxs.append(total_samples - 1)
    fys.append(avs)
    fs = sp.resample(fxs, fys, total_samples)
    fs = sp.smooth(fs, 3000)

    # print out
    log.info("Saving sequence (%s)..." % walk_id)
    sequence = []
    for p, peak in enumerate(peaks):
        foot = 'right' if peak[1] > fs[int(peak[0])] else 'left'
        t = peak[0]
        t += 250  # turns out the peak hits just before the step
        sequence.append((t, foot))

    # fix triples
    for i in range(len(sequence) - 2):
        if sequence[i][1] == sequence[i + 1][1] == sequence[i + 2][1]:
            sequence[i + 1] = (sequence[i + 1][0],
                               'right') if sequence[i + 1][1] == 'left' else (
                                   sequence[i + 1][0], 'left')

    model.insert_sequence(walk_id, sequence)

    plot(walk_id, xs, ys, zs, ds, peaks, total_samples, fs)
def generate():

    # load data into t and count arrays per species
    species = OrderedDict()
    start_t = util.timestamp(util.parse_date(str(config['start'])))
    end_t = util.timestamp(util.parse_date(str(config['end'])))
    max_count = 0
    with open("data.csv") as f:
        data = csv.reader(f)
        for r, row in enumerate(data):
            if r == 0:
                continue
            plot = row[1]
            name = row[2]
            if len(config['species_list']
                   ) and name not in config['species_list']:
                continue
            dt = datetime.datetime(int(row[3]), 1,
                                   1) + datetime.timedelta(int(row[4]) - 1)
            t = util.timestamp(dt)
            if t < start_t or t > end_t:
                continue
            count = 0 if row[5] == "NA" else int(row[5])
            if count > max_count:
                max_count = count
            if name not in species:
                species[name] = {'ts': [start_t, t - 1], 'counts': [0, 0]}
            species[name]['ts'].append(t)
            species[name]['counts'].append(count)
    species = OrderedDict(sorted(species.items()))
    print("--> loaded")

    # add a zero count at the start and end of every year
    yts = [
        util.timestamp(datetime.datetime(y, 1, 1)) for y in range(1974, 2017)
    ]
    for name in species:
        ts = species[name]['ts']
        for yt in yts:
            i = 0
            while i < len(ts) and ts[i] < yt:
                i += 1
            if i > 0:
                end_season_t = ts[i - 1]
                if i < len(ts):
                    start_season_t = ts[i]
                    ts.insert(i, start_season_t - config['tail'])
                    species[name]['counts'].insert(i, 0)
                ts.insert(i, end_season_t + config['tail'])
                species[name]['counts'].insert(i, 0)
        species[name]['ts'].append(end_t)
        species[name]['counts'].append(0)
    print("--> onsets added")

    # create and draw signals
    signals = []
    names = []
    i = 0
    for name, data in species.items():
        print("Processing %s..." % name)

        # create signal from bloom counts
        signal = sp.resample(data['ts'], data['counts'])
        if config['normalize']:
            signal = sp.normalize(signal)
        else:
            signal = sp.normalize(signal, 0, max_count)
        signal = sp.smooth(signal, size=8)
        signal = sp.limit(
            signal,
            max(signal))  # get rid of noise below 0 for onset detection

        # add spikes for peaks
        if config['peak_spikes']:
            peaks, valleys = sp.detect_peaks(signal, lookahead=50)
            peak_signal = np.zeros(len(signal))
            for peak in peaks:
                peak_signal[peak[0]] = 1.0
            signal += peak_signal

        # add spikes for onsets
        if config['onset_spikes']:
            onsets = sp.detect_onsets(signal)
            onset_signal = np.zeros(len(signal))
            for onset in onsets:
                onset_signal[onset] = 0.5
                onset_signal[onset + 1] = 0.4
                onset_signal[onset + 2] = 0.25
            signal += onset_signal

        # limit
        signal = sp.limit(signal, 1.0)
        signal *= 0.9  # hack, just controlling gain
        signals.append(signal)

        names.append(name)

        i += 1

    return signals, names
def generate():

    # load data into t and count arrays per species
    species = OrderedDict()
    start_t = util.timestamp(util.parse_date(str(config['start'])))
    end_t = util.timestamp(util.parse_date(str(config['end'])))
    max_count = 0
    with open("data.csv") as f:
        data = csv.reader(f)
        for r, row in enumerate(data):
            if r == 0:
                continue
            plot = row[1]        
            name = row[2]        
            if len(config['species_list']) and name not in config['species_list']:
                continue
            dt = datetime.datetime(int(row[3]), 1, 1) + datetime.timedelta(int(row[4]) - 1)
            t = util.timestamp(dt)
            if t < start_t or t > end_t:
                continue
            count = 0 if row[5] == "NA" else int(row[5]) 
            if count > max_count:
                max_count = count
            if name not in species:
                species[name] = {'ts': [start_t, t - 1], 'counts': [0, 0]}
            species[name]['ts'].append(t)
            species[name]['counts'].append(count)
    species = OrderedDict(sorted(species.items()))
    print("--> loaded")


    # add a zero count at the start and end of every year
    yts = [util.timestamp(datetime.datetime(y, 1, 1)) for y in range(1974, 2017)]
    for name in species:
        ts = species[name]['ts']
        for yt in yts:
            i = 0        
            while i < len(ts) and ts[i] < yt:
                i += 1
            if i > 0:
                end_season_t = ts[i-1]
                if i < len(ts):
                    start_season_t = ts[i]
                    ts.insert(i, start_season_t - config['tail'])
                    species[name]['counts'].insert(i, 0)
                ts.insert(i, end_season_t + config['tail'])
                species[name]['counts'].insert(i, 0)
        species[name]['ts'].append(end_t)
        species[name]['counts'].append(0)
    print("--> onsets added")


    # create and draw signals
    signals = []
    names = []
    i = 0
    for name, data in species.items():
        print("Processing %s..." % name)

        # create signal from bloom counts
        signal = sp.resample(data['ts'], data['counts'])
        if config['normalize']:
            signal = sp.normalize(signal)
        else:
            signal = sp.normalize(signal, 0, max_count)    
        signal = sp.smooth(signal, size=8)
        signal = sp.limit(signal, max(signal))  # get rid of noise below 0 for onset detection

        # add spikes for peaks
        if config['peak_spikes']:
            peaks, valleys = sp.detect_peaks(signal, lookahead=50)
            peak_signal = np.zeros(len(signal))    
            for peak in peaks:
                peak_signal[peak[0]] = 1.0
            signal += peak_signal

        # add spikes for onsets
        if config['onset_spikes']:
            onsets = sp.detect_onsets(signal)
            onset_signal = np.zeros(len(signal))    
            for onset in onsets:
                onset_signal[onset] = 0.5
                onset_signal[onset+1] = 0.4
                onset_signal[onset+2] = 0.25
            signal += onset_signal

        # limit
        signal = sp.limit(signal, 1.0)
        signal *= 0.9   # hack, just controlling gain
        signals.append(signal)   

        names.append(name)
   
        i += 1

    return signals, names
Beispiel #4
0
def process_walk(walk_id, force=False):

    if not model.process_check(walk_id):
        log.error("Walk %s already processed" % walk_id)        
        if force:
            log.info("--> forcing...")
            model.remove_sequence(walk_id)
        else:
            return
    log.info("Processing walk %s" % walk_id)

    # fetch data
    data = model.fetch_accels(walk_id)
    data = [(reading['t'], reading['x'], reading['y'], reading['z']) for reading in data]

    # let's sample every millisecond, so the time of the last reading is how many samples we need
    data = np.array(data)
    ts = data[:,0]
    total_samples = int(ts[-1])

    # need at least 10s of data
    # add 2000 for trimming at nd
    if total_samples < 10000 + 2000: 
        log.info("No footsteps detected (too short)")
        model.hide(walk_id)        
        return

    # resample the values
    xs = sp.resample(ts, data[:,1], total_samples)
    ys = sp.resample(ts, data[:,2], total_samples)
    zs = sp.resample(ts, data[:,3], total_samples)

    # skip for accelerometer startup and for phone out of pocket at end 
    skipin, skipout = 0, 2000
    xs = xs[skipin:-skipout]
    ys = ys[skipin:-skipout]
    zs = zs[skipin:-skipout]
    total_samples -= (skipin + skipout)
    log.info("TOTAL SAMPLES %s (%fs)" % (total_samples, (total_samples / 1000.0)))

    # get 3d magnitude (not RMS) -- orientation shouldnt matter
    ds = np.sqrt(np.power(xs, 2) + np.power(ys, 2) + np.power(zs, 2))    

    # prep the raw values for display
    # normalize the values to a given range  (this is Gs)
    MIN = -10.0
    MAX = 10.0
    xs = (xs - MIN) / (MAX - MIN)
    ys = (ys - MIN) / (MAX - MIN)
    zs = (zs - MIN) / (MAX - MIN)
    # smooth them
    xs = sp.smooth(xs, 300)
    ys = sp.smooth(ys, 300)
    zs = sp.smooth(zs, 300)

    # process the magnitude signal
    ds = sp.smooth(ds, 500)
    ds = np.clip(ds, -10.0, 10.0)   # limit the signal to +-10 Gs
    ds = sp.normalize(ds)
    ds = 1 - ds
    ds = sp.compress(ds, 3.0)
    ds = sp.normalize(ds)

    # detect peaks
    peaks, valleys = sp.detect_peaks(ds, lookahead=50, delta=0.10)
    peaks = np.array(peaks)
    valleys = np.array(valleys)
    log.info("PEAKS %s" % len(peaks))
    if not len(peaks):
        log.info("No footsteps detected")
        model.hide(walk_id)
        return

    # get foot separator line
    fxs = [int(peak[0]) for peak in peaks]
    fys = [peak[1] for peak in peaks]
    avs = np.average([peak[1] for peak in peaks])
    fys[0] = avs    # it's going to start with a peak, so we need to bring it up or down accordingly
    fxs.append(total_samples-1)
    fys.append(avs)
    fs = sp.resample(fxs, fys, total_samples)
    fs = sp.smooth(fs, 3000)

    # print out
    log.info("Saving sequence (%s)..." % walk_id)
    sequence = []
    for p, peak in enumerate(peaks):
        foot = 'right' if peak[1] > fs[int(peak[0])] else 'left'
        t = peak[0]
        t += 250   # turns out the peak hits just before the step
        sequence.append((t, foot))

    # fix triples
    for i in range(len(sequence) - 2):
        if sequence[i][1] == sequence[i+1][1] == sequence[i+2][1]:
            sequence[i+1] = (sequence[i+1][0], 'right') if sequence[i+1][1] == 'left' else (sequence[i+1][0], 'left')

    model.insert_sequence(walk_id, sequence)

    plot(walk_id, xs, ys, zs, ds, peaks, total_samples, fs)
Beispiel #5
0
def main(session_id):
    result = db.branches.find({'session': session_id}).sort([('t', ASCENDING)])
    if not result.count():
        print("NO DATA!")
        exit()

    log.info("Start processing...")

    result = list(result)
    ts = [r['t'] for r in result]
    rms = [r['sample'][3] for r in result]
    duration = ts[-1] - ts[0]
    SAMPLING_RATE = 60 # hz
    log.info("DURATION %fs" % duration)

    signal = sp.resample(ts, rms, duration * SAMPLING_RATE)
    signal = sp.remove_shots(signal)
    signal = sp.normalize(signal)    
    signal = sp.smooth(signal, 15)

    # this number should match some lower frequency bound. ie, put this in hz.
    # the smaller the number, the more it will affect small motion
    # so this should be higher than the slowest motion we care about
    # ie, dont care about motion over 0.5hz, which is 120 samples
    trend = sp.smooth(signal, 120)  
    signal -= trend
    signal += 0.5

    atrend = sp.smooth(signal, 500)



    ## autocorrelation

    auto = sp.autocorrelate(signal)
    # this should be small -- if 60hz, fastest gesture would reasonably be half of that, so 30
    peaks, valleys = sp.detect_peaks(auto, 10)
    peaks = [peak for peak in peaks[1:] if peak[1] > 0.5]
    partials = []
    for peak in peaks:    
        frequency = SAMPLING_RATE / peak[0]
        partial = frequency * 1000
        partials.append([partial, float(peak[1])])
        log.info("%d samps\t%fhz\t%f magnitude\t%f map" % (peak[0], frequency, peak[1], partial))
    log.info(partials)    

    ctx = drawing.Context(2000, 750)
    ctx.plot(auto, stroke=(0.0, 0.0, 0.0, 1.0), thickness=2.0)
    for peak in peaks:
        x = peak[0] / len(auto)
        ctx.line(x, 0.0, x, peak[1], stroke=(1.0, 0.0, 0.0, 1.0))
    ctx.output("graphs")


    ## audio

    audio_signal = sp.make_audio(signal)
    spectrum(audio_signal, SAMPLING_RATE)

    AUDIO_RATE = 11025
    filename = "%s.wav" % util.timestamp()
    sound.write_audio(audio_signal, filename, AUDIO_RATE)
    subprocess.call(["open", filename])
    log.info("AUDIO DURATION %fs" % (duration / (AUDIO_RATE / SAMPLING_RATE)))

    ctx = drawing.Context(2000, 750)
    ctx.plot(signal, stroke=(0.0, 0.0, 0.0, 1.0), thickness=2.0)
    ctx.plot(trend, stroke=(1.0, 0.0, 0.0, 1.0), thickness=2.0)
    ctx.plot(atrend, stroke=(0.0, 0.0, 1.0, 1.0), thickness=2.0)
    ctx.output("graphs")


    log.info("--> done") # around 300ms
    total_time = ts[-1] - ts[0]
    total_samples = int(total_time / 60)     # once per minute

    log.debug("last_t %s" % ts[-1])
    log.debug("total_time %s" % total_time)
    log.debug("total_time_f %s" % strings.format_time(total_time))
    log.debug("total_samples %s" % total_samples)
    sample_length = total_time / total_samples
    log.debug("sample_length %s" % sample_length)

    signal = sp.resample(ts, hrs, total_samples)
    signal = sp.normalize(signal)
    signal = signal - sp.smooth(signal, size=100)   # flatten it out a bit
    threshold = np.average(signal) + (2 * np.std(signal))   # threshold is average plus 2 std deviation
    smoothed_signal = sp.smooth(signal, size=10)
    peaks, valleys = sp.detect_peaks(smoothed_signal, lookahead=10, delta=.001)
    max_peak = max(peaks, key=lambda p: p[1])
    log.info("max_peak %s" % max_peak)
    peaks = [peak for peak in peaks if peak[1] > threshold]

    def draw():
        from housepy import drawing
        log.info("--> done")
        log.info("Plotting...")
        ctx = drawing.Context()
        ctx.plot(signal)
        ctx.plot(smoothed_signal, stroke=(100, 0, 0))
        for peak in peaks:
            ctx.arc(peak[0] / total_samples, peak[1], 10.0 / ctx.width, stroke=(0, 255, 0), thickness=5)
        ctx.line(0, threshold, 1.0, threshold, stroke=(0, 0, 255))
        ctx.output("screenshots")
Beispiel #7
0
def process_walk(walk_id, force=False):

    if not model.process_check(walk_id):
        log.error("Walk %s already processed" % walk_id)        
        if force:
            log.info("--> forcing...")
            model.remove_sequence(walk_id)
        else:
            return
    log.info("Processing walk %s" % walk_id)

    data = model.fetch_accels(walk_id)
    data = [(reading['t'], reading['x'], reading['y'], reading['z']) for reading in data]
    # log.debug(data)

    # let's sample every millisecond, so the time of the last reading is how many samples we need
    data = np.array(data)
    # log.debug(data)
    ts = data[:,0]
    total_samples = ts[-1]
    log.info("TOTAL SAMPLES %s (%fs)" % (total_samples, (total_samples / 1000.0)))

    # resample the values
    xs = sp.resample(ts, data[:,1], total_samples)
    ys = sp.resample(ts, data[:,2], total_samples)
    zs = sp.resample(ts, data[:,3], total_samples)

    # skip 0.5s for intro
    skip = 500
    xs = xs[skip:]
    ys = ys[skip:]
    zs = zs[skip:]
    total_samples -= skip


    # # for testing
    # log.debug(total_samples)
    # xs = xs[(30 * 1000):(50 * 1000)]
    # ys = ys[(30 * 1000):(50 * 1000)]
    # zs = zs[(30 * 1000):(50 * 1000)]
    # total_samples = len(xs)
    # log.debug(total_samples)


    # get 3d vector
    ds = np.sqrt(np.power(xs, 2) + np.power(ys, 2) + np.power(zs, 2))

    # normalize the values to a given range (this is gs, I believe)
    MIN = -20.0
    MAX = 20.0
    xs = (xs - MIN) / (MAX - MIN)
    ys = (ys - MIN) / (MAX - MIN)
    zs = (zs - MIN) / (MAX - MIN)
    ds = (ds - MIN) / (MAX - MIN)

    # low-pass filter
    ds = sp.smooth(ds, 300)
    # ds = sp.normalize(ds)
    # av = np.average(ds)

    # detect peaks
    # lookahead should be the minimum time of a step, maybe .3s, 300ms
    peaks, valleys = sp.detect_peaks(ds, lookahead=150, delta=0.10)
    if len(peaks) and peaks[0][0] == 0:
        peaks = peaks[1:]
    peaks = np.array(peaks)
    valleys = np.array(valleys)
    log.info("PEAKS %s" % len(peaks))
    log.info("VALLEYS %s" % len(valleys))

    if not (len(peaks) and len(valleys)):
        log.info("No footsteps detected")
        return

    peaks = valleys

    # start = np.min((np.min(peaks[:,0]), np.min(valleys[:,0])))
    start = np.min(peaks[:,0])
    log.debug("START %s" % start)
    xs = xs[start:]
    ys = ys[start:]
    zs = zs[start:]
    ds = ds[start:]
    peaks = [(peak[0] - start, peak[1]) for peak in peaks]
    valleys = [(valley[0] - start, valley[1]) for valley in valleys]
    total_samples -= start

    # get foot separator line
    fxs = [peak[0] for peak in peaks]
    fys = [peak[1] for peak in peaks]
    avs = np.average([peak[1] for peak in peaks])
    fxs.append(total_samples-1)
    fys.append(avs)
    fs = sp.resample(fxs, fys, total_samples)
    fs = sp.smooth(fs, 3000)

    # print out
    log.info("Saving sequence (%s)..." % walk_id)
    sequence = []
    for p, peak in enumerate(peaks):
        foot = 'right' if peak[1] > fs[peak[0]] else 'left'
        sequence.append((peak[0], foot))
    model.insert_sequence(walk_id, sequence)

    plot(walk_id, xs, ys, zs, ds, peaks, valleys, total_samples, fs)