rtl-sdr-blog/debian/heatmap.py

135 lines
3.7 KiB
Python
Raw Normal View History

#! /usr/bin/env python2
from PIL import Image, ImageDraw, ImageFont
import sys, gzip, math, colorsys, datetime
from collections import defaultdict
from itertools import *
# todo: matplotlib powered --interactive
# arbitrary freq marker spacing
path = sys.argv[1]
output = sys.argv[2]
raw_data = lambda: open(path)
if path.endswith('.gz'):
raw_data = lambda: gzip.open(path, 'rb')
def frange(start, stop, step):
i = 0
while (i*step + start <= stop):
yield i*step + start
i += 1
print("loading")
freqs = set()
f_cache = set()
times = set()
labels = set()
min_z = 0
max_z = -100
start, stop = None, None
for line in raw_data():
line = [s.strip() for s in line.strip().split(',')]
line = [line[0], line[1]] + [float(s) for s in line[2:] if s]
low = line[2]
high = line[3]
step = line[4]
f_key = (int(low), int(high), step)
if f_key not in f_cache:
freqs.update(list(frange(int(low), int(high), step)))
freqs.add(high)
labels.add(low)
f_cache.add(f_key)
t = line[0] + ' ' + line[1]
times.add(t)
zs = line[6:]
min_z = min(min_z, min(z for z in zs if not math.isinf(z)))
max_z = max(max_z, max(zs))
if start is None:
start = datetime.datetime.strptime(line[0] + ' ' + line[1], '%Y-%m-%d %H:%M:%S')
stop = datetime.datetime.strptime(line[0] + ' ' + line[1], '%Y-%m-%d %H:%M:%S')
freqs = list(sorted(list(freqs)))
times = list(sorted(list(times)))
labels = list(sorted(list(labels)))
if len(labels) == 1:
delta = (max(freqs) - min(freqs)) / (len(freqs) / 500)
delta = round(delta / 10**int(math.log10(delta))) * 10**int(math.log10(delta))
delta = int(delta)
lower = int(math.ceil(min(freqs) / delta) * delta)
labels = list(range(lower, int(max(freqs)), delta))
print("x: %i, y: %i, z: (%f, %f)" % (len(freqs), len(times), min_z, max_z))
def rgb2(z):
g = (z - min_z) / (max_z - min_z)
return (int(g*255), int(g*255), 50)
def rgb3(z):
g = (z - min_z) / (max_z - min_z)
c = colorsys.hsv_to_rgb(0.65-(g-0.08), 1, 0.2+g)
return (int(c[0]*256),int(c[1]*256),int(c[2]*256))
print("drawing")
img = Image.new("RGB", (len(freqs), len(times)))
pix = img.load()
x_size = img.size[0]
for line in raw_data():
line = [s.strip() for s in line.strip().split(',')]
line = [line[0], line[1]] + [float(s) for s in line[2:] if s]
t = line[0] + ' ' + line[1]
if t not in times:
continue # happens with live files
y = times.index(t)
low = line[2]
high = line[3]
step = line[4]
x_start = freqs.index(low)
for i in range(len(line[6:])):
x = x_start + i
if x >= x_size:
continue
z = line[6+i]
# fast check for nan/-inf
if not z >= min_z:
z = min_z
pix[x,y] = rgb2(z)
print("labeling")
draw = ImageDraw.Draw(img)
font = ImageFont.load_default()
pixel_width = step
for label in labels:
y = 10
#x = freqs.index(label)
x = int((label-min(freqs)) / pixel_width)
s = '%.3fMHz' % (label/1000000.0)
draw.text((x, y), s, font=font, fill='white')
duration = stop - start
duration = duration.seconds
pixel_height = duration / len(times)
hours = int(duration / 3600)
minutes = int((duration - 3600*hours) / 60)
draw.text((2, img.size[1] - 45), 'Duration: %i:%02i' % (hours, minutes), font=font, fill='white')
draw.text((2, img.size[1] - 35), 'Range: %.2fMHz - %.2fMHz' % (min(freqs)/1e6, max(freqs)/1e6), font=font, fill='white')
draw.text((2, img.size[1] - 25), 'Pixel: %.2fHz x %is' % (pixel_width, int(round(pixel_height))), font=font, fill='white')
draw.text((2, img.size[1] - 15), 'Started: {0}'.format(start), font=font, fill='white')
# bin size
print("saving")
img.save(output)