mirror of
https://github.com/google/pebble.git
synced 2025-07-03 05:46:21 +00:00
Import of the watch repository from Pebble
This commit is contained in:
commit
3b92768480
10334 changed files with 2564465 additions and 0 deletions
438
tools/activity/fft.py
Normal file
438
tools/activity/fft.py
Normal file
|
@ -0,0 +1,438 @@
|
|||
# Copyright 2024 Google LLC
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
#################################################################################################
|
||||
# Test FFT algorithm
|
||||
#
|
||||
# This is used to experiment with various step-tracking algorithms. It is a python implementation
|
||||
# of an FFT as described in:
|
||||
# "Real-valued Fast Fourier Transform Algorithm", from IEEE Transactions on Acoustics,
|
||||
# Speech, and Signal Processing, Vol. ASSP-35, No. 6, June 1987
|
||||
#
|
||||
# The firmware uses this same algorithm, but implemented in C in the prv_fft_2radix_real()
|
||||
# method of kraepelin_algorithm.c
|
||||
##################################################################################################
|
||||
|
||||
import argparse
|
||||
import os
|
||||
import sys
|
||||
import logging
|
||||
import math
|
||||
|
||||
|
||||
###########################################################################################
|
||||
g_walk_10_steps = [
|
||||
[-362, -861, 69],
|
||||
[-309, -899, 45],
|
||||
[-266, -904, 21],
|
||||
[-242, -848, -134],
|
||||
[-272, -839, 34],
|
||||
[-207, -919, 14],
|
||||
[-244, -879, 93],
|
||||
[-238, -856, 91],
|
||||
[-185, -883, 37],
|
||||
[-217, -855, -156],
|
||||
[-200, -883, 25],
|
||||
[-154, -927, 42],
|
||||
[-179, -935, 71],
|
||||
[-184, -956, 32],
|
||||
[-129, -999, 99],
|
||||
[-195, -950, -112],
|
||||
[-222, -969, -164],
|
||||
[-351, -996, -190],
|
||||
[-277, -1218, -259],
|
||||
[-212, -1018, -250],
|
||||
[-209, -812, -142],
|
||||
[-182, -680, -200],
|
||||
[-257, -642, -169],
|
||||
[-269, -797, -289],
|
||||
[-142, -1107, -330],
|
||||
[-185, -909, -300],
|
||||
[-229, -706, -155],
|
||||
[-171, -750, -161],
|
||||
[-181, -811, -218],
|
||||
[-173, -845, -149],
|
||||
[-118, -887, -126],
|
||||
[-150, -871, -100],
|
||||
[-164, -908, -146],
|
||||
[-175, -958, -161],
|
||||
[-231, -952, -113],
|
||||
[-273, -1006, -205],
|
||||
[-321, -1047, -351],
|
||||
[-321, -1064, -300],
|
||||
[-262, -945, -210],
|
||||
[-298, -770, -124],
|
||||
[-338, -772, 95],
|
||||
[-325, -818, -179],
|
||||
[-329, -780, -153],
|
||||
[-280, -796, -151],
|
||||
[-230, -755, -100],
|
||||
[-234, -759, 44],
|
||||
[-248, -807, 90],
|
||||
[-217, -872, 79],
|
||||
[-204, -887, 74],
|
||||
[-189, -939, 78],
|
||||
[-220, -1014, -129],
|
||||
[-147, -1107, -129],
|
||||
[-274, -1013, -158],
|
||||
[-301, -1007, -258],
|
||||
[-351, -1131, -346],
|
||||
[-118, -1086, -355],
|
||||
[-290, -716, -213],
|
||||
[-288, -720, -290],
|
||||
[-235, -825, -344],
|
||||
[-179, -819, -243],
|
||||
[-228, -670, -185],
|
||||
[-125, -790, -145],
|
||||
[-145, -795, -207],
|
||||
[-152, -809, 76],
|
||||
[-98, -871, -115],
|
||||
[-89, -855, -111],
|
||||
[-116, -879, 84],
|
||||
[-161, -945, -172],
|
||||
[-147, -1017, -173],
|
||||
[-278, -1012, -146],
|
||||
[-268, -1049, -247],
|
||||
[-279, -1026, -260],
|
||||
[-286, -958, -187],
|
||||
[-288, -890, -167],
|
||||
[-359, -873, -168],
|
||||
[-324, -904, -147],
|
||||
[-263, -804, -134],
|
||||
[-214, -712, 37],
|
||||
[-189, -698, 29],
|
||||
[-183, -755, 74],
|
||||
[-182, -841, 98],
|
||||
[-115, -894, 73],
|
||||
[-149, -857, 57],
|
||||
[-93, -927, -68],
|
||||
[-145, -988, -120],
|
||||
[-112, -1095, -112],
|
||||
[-201, -1059, -146],
|
||||
[-278, -1104, -206],
|
||||
[-284, -1204, -213],
|
||||
[-214, -966, -254],
|
||||
[-272, -730, -140],
|
||||
[-233, -785, -252],
|
||||
[-259, -813, -272],
|
||||
[-156, -840, -205],
|
||||
[-163, -765, -110],
|
||||
[-165, -741, 97],
|
||||
[-164, -791, 86],
|
||||
[-99, -849, -69],
|
||||
[-99, -820, -81],
|
||||
[-94, -842, -37],
|
||||
[-142, -881, -109],
|
||||
[-153, -978, -155],
|
||||
[-212, -934, 71],
|
||||
[-341, -947, 99],
|
||||
[-406, -1039, -283],
|
||||
[-265, -1146, -206],
|
||||
[-296, -979, -163],
|
||||
[-345, -864, 98],
|
||||
[-216, -907, 38],
|
||||
[-242, -809, 47],
|
||||
[-154, -736, 52],
|
||||
[-137, -700, -101],
|
||||
[-184, -743, -136],
|
||||
[-191, -850, 86],
|
||||
[-206, -883, 85],
|
||||
[-194, -875, 48],
|
||||
[-148, -937, 46],
|
||||
[-193, -983, 31],
|
||||
[-176, -1062, 43],
|
||||
[-251, -1006, -114],
|
||||
[-284, -1036, -192],
|
||||
[-374, -1181, -248],
|
||||
[-167, -1177, -271],
|
||||
[-253, -794, -128],
|
||||
[-285, -651, -129],
|
||||
[-228, -757, -227],
|
||||
[-260, -843, -201],
|
||||
[-189, -899, -253],
|
||||
[-212, -800, -136],
|
||||
[-218, -728, -136],
|
||||
[-177, -761, -129],
|
||||
[-165, -806, -137],
|
||||
[-157, -839, -122],
|
||||
[-116, -899, -104],
|
||||
[-191, -874, 77],
|
||||
[-174, -911, 95],
|
||||
[-193, -971, -147],
|
||||
[-255, -961, -127],
|
||||
[-222, -1052, -124],
|
||||
[-333, -1021, -223],
|
||||
[-245, -1018, -215],
|
||||
[-269, -850, 91],
|
||||
[-318, -754, -120],
|
||||
[-335, -878, -199],
|
||||
[-322, -986, -224],
|
||||
[-192, -902, -179],
|
||||
[-177, -712, 86],
|
||||
[-196, -673, 88],
|
||||
[-178, -751, -101],
|
||||
[-182, -847, 70],
|
||||
[-147, -909, -131],
|
||||
[-170, -939, 43],
|
||||
[-224, -994, 60],
|
||||
[-189, -1051, 42],
|
||||
[-242, -968, -183],
|
||||
[-312, -978, -213],
|
||||
[-317, -1298, -334],
|
||||
[-184, -1131, -330],
|
||||
[-287, -754, -141],
|
||||
[-249, -773, -287],
|
||||
[-166, -842, -297],
|
||||
[-196, -742, -214],
|
||||
[-163, -729, -198],
|
||||
[-177, -757, -197],
|
||||
[-174, -830, -155],
|
||||
[-159, -860, -149],
|
||||
[-145, -856, 72],
|
||||
[-132, -849, 47],
|
||||
[-145, -839, 62],
|
||||
[-179, -843, 76],
|
||||
[-163, -941, -114],
|
||||
[-230, -963, -110],
|
||||
]
|
||||
|
||||
|
||||
##################################################################################################
|
||||
def real_value_fft(x):
|
||||
""" Real value FFT as described in Appendix of:
|
||||
"Real-valued Fast Fourier Transform Algorithm", from IEEE Transactions on Acoustics, Speech,
|
||||
and Signal Processing, Vol. ASSP-35, No. 6, June 1987
|
||||
"""
|
||||
|
||||
# Make sure we have a power of 2 length input
|
||||
n = len(x)
|
||||
m = int(math.log(n, 2))
|
||||
if (math.pow(2, m) != n):
|
||||
raise RuntimeError("Length must be a power of 2")
|
||||
|
||||
# The rest of the code assumes 1-based indexing (it comes from fortran)
|
||||
x = [0] + x
|
||||
|
||||
# ---------------------------------------------------------------------------------
|
||||
# Digit reverse counter
|
||||
j = 1
|
||||
n1 = n - 1
|
||||
for i in range(1, n1 + 1):
|
||||
if (i < j):
|
||||
xt = x[j]
|
||||
x[j] = x[i]
|
||||
x[i] = xt
|
||||
k = n/2
|
||||
while (k < j):
|
||||
j = j - k
|
||||
k = k / 2
|
||||
j = j + k
|
||||
|
||||
# ---------------------------------------------------------------------------------
|
||||
# Length 2 butterflies
|
||||
for i in range(1, n + 1, 2):
|
||||
xt = x[i]
|
||||
x[i] = xt + x[i+1]
|
||||
x[i+1] = xt - x[i+1]
|
||||
|
||||
# ---------------------------------------------------------------------------------
|
||||
# Other butterflies
|
||||
n2 = 1
|
||||
for k in range(2, m + 1):
|
||||
n4 = n2
|
||||
n2 = 2 * n4
|
||||
n1 = 2 * n2
|
||||
e = 2 * math.pi / n1
|
||||
for i in range(1, n+1, n1):
|
||||
xt = x[i]
|
||||
x[i] = xt + x[i + n2]
|
||||
x[i + n2] = xt - x[i + n2]
|
||||
x[i + n4 + n2] = -x[i + n4 + n2]
|
||||
|
||||
a = e
|
||||
for j in range(1, n4 - 1):
|
||||
i1 = i + j
|
||||
i2 = i - j + n2
|
||||
i3 = i + j + n2
|
||||
i4 = i - j + n1
|
||||
cc = math.cos(a)
|
||||
ss = math.sin(a)
|
||||
a = a + e
|
||||
t1 = x[i3] * cc + x[i4] * ss
|
||||
t2 = x[i3] * ss - x[i4] * cc
|
||||
x[i4] = x[i2] - t2
|
||||
x[i3] = -x[i2] - t2
|
||||
x[i2] = x[i1] - t1
|
||||
x[i1] = x[i1] + t1
|
||||
|
||||
return x[1:]
|
||||
|
||||
|
||||
###################################################################################################
|
||||
def compute_magnitude(x):
|
||||
""" The real_value_fft() produces an array containing outputs in this order:
|
||||
[Re(0), Re(1), ..., Re(N/2), Im(N/2-1), ..., Im(1)]
|
||||
|
||||
This method returns the magnitudes. The magnitude of term i is sqrt(Re(i)**2 + Im(i)**2)
|
||||
"""
|
||||
result = []
|
||||
n = len(x)
|
||||
real_idx = 0
|
||||
im_idx = n - 1
|
||||
|
||||
result.append(x[real_idx])
|
||||
real_idx += 1
|
||||
|
||||
while real_idx <= n/2 - 1:
|
||||
mag = (x[real_idx]**2 + x[im_idx]**2) ** 0.5
|
||||
result.append(mag)
|
||||
real_idx += 1
|
||||
im_idx -= 1
|
||||
|
||||
result.append(x[real_idx])
|
||||
return result
|
||||
|
||||
|
||||
###################################################################################################
|
||||
def apply_gausian(x, width=0.1):
|
||||
""" Multiply x by the gaussian function. Width is a fraction, like 0.1
|
||||
"""
|
||||
result = []
|
||||
n = len(x)
|
||||
mid = float(n/2)
|
||||
denominator = n**2 * width
|
||||
|
||||
for i in range(len(x)):
|
||||
print i-mid, (i-mid)**2, -1 * (i - mid)**2/denominator, \
|
||||
math.exp(-1 * (i - mid)**2/denominator)
|
||||
g = math.exp(-1 * (i - mid)**2/denominator)
|
||||
result.append(g * x[i])
|
||||
|
||||
return result
|
||||
|
||||
|
||||
###################################################################################################
|
||||
def print_graph(x):
|
||||
min_value = min(x)
|
||||
max_value = max(x)
|
||||
|
||||
extent = max(abs(min_value), abs(max_value))
|
||||
scale = 2 * extent
|
||||
min_value = -extent
|
||||
|
||||
for i in range(len(x)):
|
||||
print "%4d: %10.3f: " % (i, x[i]),
|
||||
position = int((x[i] - min_value) * 80 / scale)
|
||||
if position < 40:
|
||||
print ' ' * position,
|
||||
print '*' * (40 - position)
|
||||
else:
|
||||
print ' ' * 40,
|
||||
print '*' * (position - 40)
|
||||
|
||||
|
||||
###################################################################################################
|
||||
if __name__ == '__main__':
|
||||
|
||||
# Collect our command line arguments
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument('--debug', action='store_true', help="Turn on debug logging")
|
||||
args = parser.parse_args()
|
||||
|
||||
level = logging.INFO
|
||||
if args.debug:
|
||||
level = logging.DEBUG
|
||||
logging.basicConfig(level=level)
|
||||
|
||||
# -------------------------------------------------------------------------------------
|
||||
# Constant signal
|
||||
if 0:
|
||||
input_len = 128
|
||||
input = [1 for x in range(input_len)]
|
||||
print "\n############ INPUT ######################"
|
||||
print_graph(input)
|
||||
|
||||
result = real_value_fft(input)
|
||||
|
||||
print "\n############ RESULT ######################"
|
||||
print_graph(result)
|
||||
|
||||
# -------------------------------------------------------------------------------------
|
||||
# N sine waves
|
||||
if 0:
|
||||
input_len = 128
|
||||
freq = 7
|
||||
input = [math.cos(float(x)/input_len * freq * 2 * math.pi) for x in range(input_len)]
|
||||
print "\n############ INPUT ######################"
|
||||
print_graph(input)
|
||||
|
||||
print "\n############ GAUSIAN OF INPUT ############"
|
||||
# input = apply_gausian(input, 0.1)
|
||||
print_graph(input)
|
||||
|
||||
result = real_value_fft(input)
|
||||
|
||||
print "\n############ REAL, IMAG ######################"
|
||||
print_graph(result)
|
||||
|
||||
print "\n############ MAGNITUDE ######################"
|
||||
mag = compute_magnitude(result)
|
||||
print_graph(mag)
|
||||
|
||||
# -------------------------------------------------------------------------------------
|
||||
# Step data
|
||||
if 1:
|
||||
input_len = 128
|
||||
raw_input = g_walk_10_steps[0:input_len]
|
||||
|
||||
x_data = [x for x, y, z in raw_input]
|
||||
x_mean = sum(x_data) / len(x_data)
|
||||
x_data = [x - x_mean for x in x_data]
|
||||
|
||||
y_data = [y for x, y, z in raw_input]
|
||||
y_mean = sum(y_data) / len(y_data)
|
||||
y_data = [y - y_mean for y in y_data]
|
||||
|
||||
z_data = [z for x, y, z in raw_input]
|
||||
z_mean = sum(z_data) / len(z_data)
|
||||
z_data = [z - z_mean for z in z_data]
|
||||
|
||||
print "\n############ X ######################"
|
||||
print_graph(x_data)
|
||||
print "\n############ Y ######################"
|
||||
print_graph(y_data)
|
||||
print "\n############ Z ######################"
|
||||
print_graph(z_data)
|
||||
|
||||
input = []
|
||||
for (x, y, z) in raw_input:
|
||||
mag = x**2 + y**2 + z**2
|
||||
mag = mag ** 0.5
|
||||
input.append(mag)
|
||||
|
||||
mean_mag = sum(input) / len(input)
|
||||
input = [x - mean_mag for x in input]
|
||||
|
||||
print "\n############ INPUT ######################"
|
||||
# input = apply_gausian(input)
|
||||
print_graph(input)
|
||||
|
||||
result = real_value_fft(input)
|
||||
|
||||
print "\n############ REAL, IMAG ######################"
|
||||
print_graph(result)
|
||||
|
||||
print "\n############ MAGNITUDE ######################"
|
||||
mag = compute_magnitude(result)
|
||||
print_graph(mag)
|
Loading…
Add table
Add a link
Reference in a new issue