Replace samples_visible with time_visible_ms

Factor out wave-reading code from MatplotlibRenderer backend.
MatplotlibRenderer backend hopefully plots arbitrary data, and can be
swapped with other backends.
pull/357/head
nyanpasu64 2018-07-15 22:07:26 -07:00
rodzic cb3e7265ca
commit 8b71df0bbb
2 zmienionych plików z 50 dodań i 47 usunięć

Wyświetl plik

@ -16,12 +16,9 @@ RENDER_PROFILING = True
class Config(NamedTuple):
wave_dir: str
# TODO: if wave_dir is present, it should overwrite List[WaveConfig].
# wave_dir will be commented out when writing to file.
master_wave: Optional[str]
fps: int
time_visible_ms: int
trigger: TriggerConfig # Maybe overriden per Wave
render: RendererConfig
@ -42,6 +39,8 @@ def main(wave_dir: str, master_wave: Optional[str], fps: int):
wave_dir=wave_dir,
master_wave=master_wave,
fps=fps,
time_visible_ms=25,
trigger=CorrelationTrigger.Config(
trigger_strength=10,
use_edge_trigger=True,
@ -51,7 +50,6 @@ def main(wave_dir: str, master_wave: Optional[str], fps: int):
),
render=RendererConfig( # todo
1280, 720,
samples_visible=1000,
rows_first=False,
ncols=1
)
@ -68,12 +66,13 @@ class Ovgen:
def __init__(self, cfg: Config):
self.cfg = cfg
self.waves: List[Wave] = []
self.nwaves: int = None
def write(self):
self.load_waves() # self.waves =
self.render()
self._load_waves() # self.waves =
self._render()
def load_waves(self):
def _load_waves(self):
wave_dir = Path(self.cfg.wave_dir)
for idx, path in enumerate(wave_dir.glob('*.wav')):
@ -89,13 +88,17 @@ class Ovgen:
wave.set_trigger(trigger)
self.waves.append(wave)
def render(self):
self.nwaves = len(self.waves)
def _render(self):
# Calculate number of frames (TODO master file?)
time_visible_ms = self.cfg.time_visible_ms
fps = self.cfg.fps
nframes = fps * self.waves[0].get_s()
nframes = int(nframes) + 1
renderer = MatplotlibRenderer(self.cfg.render, self.waves)
renderer = MatplotlibRenderer(self.cfg.render, self.nwaves)
if RENDER_PROFILING:
begin = time.perf_counter()
@ -104,17 +107,22 @@ class Ovgen:
for frame in range(nframes):
time_seconds = frame / fps
center_smps = []
datas = []
# Get data from each wave
for wave in self.waves:
sample = round(wave.smp_s * time_seconds)
region_len = round(wave.smp_s * time_visible_ms / 1000)
trigger_sample = wave.trigger.get_trigger(sample)
print(f'- {trigger_sample}')
center_smps.append(trigger_sample)
datas.append(wave.get_around(trigger_sample, region_len))
print(frame)
renderer.render_frame(center_smps)
renderer.render_frame(datas)
if RENDER_PROFILING:
# noinspection PyUnboundLocalVariable
dtime = time.perf_counter() - begin
render_fps = nframes / dtime
print(f'FPS = {render_fps}')

Wyświetl plik

@ -1,5 +1,4 @@
from itertools import count
from typing import NamedTuple, Optional, List, Tuple, TYPE_CHECKING
from typing import NamedTuple, Optional, List, Tuple
import numpy as np
from matplotlib import pyplot as plt
@ -9,16 +8,11 @@ from matplotlib.lines import Line2D
from ovgenpy.util import ceildiv
if TYPE_CHECKING:
from ovgenpy.wave import Wave
class RendererConfig(NamedTuple):
width: int
height: int
samples_visible: int
rows_first: bool
nrows: Optional[int] = None # TODO set to 1
@ -48,19 +42,19 @@ class MatplotlibRenderer:
DPI = 96
def __init__(self, cfg: RendererConfig, waves: List['Wave']):
def __init__(self, cfg: RendererConfig, nplots: int):
self.cfg = cfg
self.waves = waves
self.nwaves = len(waves)
self.nplots = nplots
self.fig: Figure = None
# Setup layout
self.nrows = 0
self.ncols = 0
# Flat array of nrows*ncols elements, ordered by cfg.rows_first.
self.axes: List[Axes] = None
self.lines: List[Line2D] = None
self.axes: List[Axes] = None # set by set_layout()
self.lines: List[Line2D] = None # set by render_frame() first call
self.set_layout() # mutates self
@ -95,17 +89,7 @@ class MatplotlibRenderer:
if not self.cfg.rows_first:
axes2d = axes2d.T
self.axes: List[Axes] = axes2d.flatten().tolist()[:self.nwaves]
# Create oscilloscope line objects
self.lines = []
for ax in self.axes:
# Setup axes limits
ax.set_xlim(0, self.cfg.samples_visible)
ax.set_ylim(-1, 1)
line = ax.plot([0] * self.cfg.samples_visible)[0]
self.lines.append(line)
self.axes: List[Axes] = axes2d.flatten().tolist()[:self.nplots]
# Setup figure geometry
self.fig.set_dpi(self.DPI)
@ -126,26 +110,37 @@ class MatplotlibRenderer:
nrows = cfg.nrows
if nrows is None:
raise ValueError('invalid cfg: rows_first is True and nrows is None')
ncols = ceildiv(self.nwaves, nrows)
ncols = ceildiv(self.nplots, nrows)
else:
ncols = cfg.ncols
if ncols is None:
raise ValueError('invalid cfg: rows_first is False and ncols is None')
nrows = ceildiv(self.nwaves, ncols)
nrows = ceildiv(self.nplots, ncols)
return nrows, ncols
def render_frame(self, center_smps: List[int]) -> None:
ncenters = len(center_smps)
if self.nwaves != ncenters:
def render_frame(self, datas: List[np.ndarray]) -> None:
ndata = len(datas)
if self.nplots != ndata:
raise ValueError(
f'incorrect wave offsets: {self.nwaves} waves but {ncenters} offsets')
f'incorrect data to plot: {self.nplots} plots but {ndata} datas')
for idx, wave, center_smp in zip(count(), self.waves, center_smps):
# Draw waveform data
line = self.lines[idx]
data = wave.get_around(center_smp, self.cfg.samples_visible)
line.set_ydata(data)
# Initialize axes and draw waveform data
if self.lines is None:
self.lines = []
for idx, data in enumerate(datas):
ax = self.axes[idx]
ax.set_xlim(0, len(data) - 1)
ax.set_ylim(-1, 1)
line = ax.plot(data)[0]
self.lines.append(line)
# Draw waveform data
else:
for idx, data in enumerate(datas):
line = self.lines[idx]
line.set_ydata(data)
self.fig.canvas.draw()
self.fig.canvas.flush_events()