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
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 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")
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)