This found a small number of real bugs too, for example, this one that looked weird because of a 2to3 conversion, but was wrong both before and after: - except IndexError as TypeError: + except (IndexError, TypeError):
89 lines
2.9 KiB
Python
Executable File
89 lines
2.9 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
|
|
import nilmtools.filter
|
|
import numpy as np
|
|
|
|
|
|
def main(argv=None):
|
|
f = nilmtools.filter.Filter()
|
|
parser = f.setup_parser("Decimate a stream")
|
|
group = parser.add_argument_group("Decimate options")
|
|
group.add_argument('-f', '--factor', action='store', default=4, type=int,
|
|
help='Decimation factor (default: %(default)s)')
|
|
|
|
# Parse arguments
|
|
try:
|
|
args = f.parse_args(argv)
|
|
except nilmtools.filter.MissingDestination as e:
|
|
# If no destination, suggest how to create it by figuring out
|
|
# a recommended layout.
|
|
src = e.src
|
|
dest = e.dest
|
|
print("Source is %s (%s)" % (src.path, src.layout))
|
|
print("Destination %s doesn't exist" % (dest.path))
|
|
if "decimate_source" in f.client_src.stream_get_metadata(src.path):
|
|
rec = src.layout
|
|
elif ('int32' in src.layout_type or
|
|
'int64' in src.layout_type or
|
|
'float64' in src.layout_type):
|
|
rec = 'float64_' + str(src.layout_count * 3)
|
|
else:
|
|
rec = 'float32_' + str(src.layout_count * 3)
|
|
print("You could make it with a command like:")
|
|
print(" nilmtool -u %s create %s %s" % (e.dest.url,
|
|
e.dest.path, rec))
|
|
raise SystemExit(1)
|
|
|
|
if not (args.factor >= 2):
|
|
raise Exception("factor needs to be 2 or more")
|
|
|
|
f.check_dest_metadata({"decimate_source": f.src.path,
|
|
"decimate_factor": args.factor})
|
|
|
|
# If source is decimated, we have to decimate a bit differently
|
|
if "decimate_source" in f.client_src.stream_get_metadata(args.srcpath):
|
|
again = True
|
|
else:
|
|
again = False
|
|
f.process_numpy(decimate, args=(args.factor, again))
|
|
|
|
|
|
def decimate(data, interval, args, insert_function, final):
|
|
"""Decimate data"""
|
|
(factor, again) = args
|
|
(n, m) = data.shape
|
|
|
|
# Figure out which columns to use as the source for mean, min, and max,
|
|
# depending on whether this is the first decimation or we're decimating
|
|
# again. Note that we include the timestamp in the means.
|
|
if again:
|
|
c = (m - 1) // 3
|
|
# e.g. c = 3
|
|
# ts mean1 mean2 mean3 min1 min2 min3 max1 max2 max3
|
|
mean_col = slice(0, c + 1)
|
|
min_col = slice(c + 1, 2 * c + 1)
|
|
max_col = slice(2 * c + 1, 3 * c + 1)
|
|
else:
|
|
mean_col = slice(0, m)
|
|
min_col = slice(1, m)
|
|
max_col = slice(1, m)
|
|
|
|
# Discard extra rows that aren't a multiple of factor
|
|
n = n // factor * factor
|
|
data = data[:n, :]
|
|
|
|
# Reshape it into 3D so we can process 'factor' rows at a time
|
|
data = data.reshape(n // factor, factor, m)
|
|
|
|
# Fill the result
|
|
out = np.c_[np.mean(data[:, :, mean_col], axis=1),
|
|
np.min(data[:, :, min_col], axis=1),
|
|
np.max(data[:, :, max_col], axis=1)]
|
|
|
|
insert_function(out)
|
|
return n
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|