kiwi-longtime-waterfall/plot_wf.py

108 lines
3.2 KiB
Python
Executable File

#!/usr/bin/env python3
import sys
from datetime import datetime
import numpy as np
import matplotlib.pyplot as pp
from matplotlib.dates import MinuteLocator, HourLocator, DateFormatter, drange, date2num
from matplotlib.ticker import MultipleLocator
accumulation = sys.argv[1]
resolution = int(sys.argv[2])
logname = sys.argv[3]
outname = sys.argv[4]
print(f"Accumulation: {accumulation}")
print(f"Resolution: {resolution} seconds")
print(f"Input Log: {logname}")
print(f"Output Image: {outname}")
accumulate = {
"avg": np.mean,
"peak": np.max,
}[accumulation]
data = -1000 * np.ones((86400//resolution, 1024), dtype=float)
counts = np.zeros(86400//resolution, dtype=int)
basetime = None
last_lineidx = 0
accumulated_data = []
with open(logname, 'r') as logfile:
for line in logfile:
parts = line.split(";", maxsplit=1)
timestamp = float(parts[0])
if not basetime:
basetime = np.floor(timestamp / 86400) * 86400
lineidx = int((timestamp - basetime) // resolution)
if lineidx != last_lineidx:
if len(accumulated_data) != 0:
# apply the accumulation function
data[last_lineidx] = accumulate(np.array(accumulated_data).astype(float), 0)
accumulated_data = []
last_lineidx = lineidx
tmp_data = np.fromstring(parts[1], sep=";", dtype=int)
if tmp_data.size == 1024:
accumulated_data.append(tmp_data)
else:
print(f"Warning: line ignored due to wrong number of elements: has {tmp_data.size}, expected 1024.")
x = np.linspace(0, 30, data.shape[1])
y = np.linspace(basetime, basetime + resolution * data.shape[0])
extent = [
0, # MHz
30, # MHz
date2num(datetime.utcfromtimestamp(basetime + resolution * data.shape[0])),
date2num(datetime.utcfromtimestamp(basetime))]
fig_x_scale = 0.85
fig_y_scale = 0.90
fig_x_off = 0.05
fig_y_off = 0.05
dpi = pp.rcParams['figure.dpi'] #get the default dpi value
fig_size = (data.shape[1]/dpi/fig_x_scale, data.shape[0]/dpi/fig_y_scale) # convert pixels to DPI
fix, ax = pp.subplots(figsize=fig_size)
image = ax.imshow(data, vmin=-100, vmax=0, cmap='inferno',
extent=extent)
ax.set_position(pos=[fig_x_off, fig_y_off, fig_x_scale, fig_y_scale])
ax.set_title('Spektrogramm vom ' + datetime.fromtimestamp(basetime).strftime('%Y-%m-%d'))
xrange = extent[1] - extent[0]
yrange = extent[2] - extent[3]
ax.set_aspect((data.shape[0] / yrange) / (data.shape[1] / xrange))
ax.yaxis_date()
ax.yaxis.set_major_locator(HourLocator(range(0, 25, 1)))
ax.yaxis.set_minor_locator(MinuteLocator(range(0, 60, 20)))
ax.yaxis.set_major_formatter(DateFormatter('%H:%M'))
ax.yaxis.set_minor_formatter(DateFormatter('%M'))
ax.xaxis.set_major_locator(MultipleLocator(1.0))
ax.set_xlabel('Frequenz [MHz]')
ax_top = ax.twiny()
ax_top.xaxis.set_major_locator(MultipleLocator(1.0))
ax_top.set_xlabel('Frequenz [MHz]')
ax_top.set_xlim(ax.get_xlim())
ax_top.set_position(pos=[fig_x_off, fig_y_off, fig_x_scale, fig_y_scale])
cax = pp.axes([fig_x_scale+fig_x_off+0.02, fig_y_off, 0.03, fig_y_scale])
pp.colorbar(cax=cax, mappable=image)
cax.set_title('dBm')
pp.savefig(outname)