now all charts looks good. Next fix: increase space between charts to fix text labels overlaying.
This commit is contained in:
@ -437,6 +437,7 @@ def main():
|
|||||||
width: Optional[int] = None
|
width: Optional[int] = None
|
||||||
max_sweeps = int(max(10, args.max_sweeps))
|
max_sweeps = int(max(10, args.max_sweeps))
|
||||||
ring = None # type: Optional[np.ndarray]
|
ring = None # type: Optional[np.ndarray]
|
||||||
|
ring_time = None # type: Optional[np.ndarray]
|
||||||
head = 0
|
head = 0
|
||||||
y_min, y_max = None, None
|
y_min, y_max = None, None
|
||||||
# FFT состояние
|
# FFT состояние
|
||||||
@ -480,7 +481,7 @@ def main():
|
|||||||
cmap=args.cmap,
|
cmap=args.cmap,
|
||||||
)
|
)
|
||||||
ax_img.set_title("Сырые данные водопад")
|
ax_img.set_title("Сырые данные водопад")
|
||||||
ax_img.set_xlabel("Время (новое слева)")
|
ax_img.set_xlabel("Время, с (новое справа)")
|
||||||
ax_img.set_ylabel("X (0 снизу)")
|
ax_img.set_ylabel("X (0 снизу)")
|
||||||
|
|
||||||
# Водопад спектров
|
# Водопад спектров
|
||||||
@ -492,7 +493,7 @@ def main():
|
|||||||
cmap=args.cmap,
|
cmap=args.cmap,
|
||||||
)
|
)
|
||||||
ax_spec.set_title("B-scan (дБ)")
|
ax_spec.set_title("B-scan (дБ)")
|
||||||
ax_spec.set_xlabel("Время (новое слева)")
|
ax_spec.set_xlabel("Время, с (новое справа)")
|
||||||
ax_spec.set_ylabel("Бин (0 снизу)")
|
ax_spec.set_ylabel("Бин (0 снизу)")
|
||||||
|
|
||||||
# Для контроля частоты обновления
|
# Для контроля частоты обновления
|
||||||
@ -501,12 +502,13 @@ def main():
|
|||||||
frames_since_ylim_update = 0
|
frames_since_ylim_update = 0
|
||||||
|
|
||||||
def ensure_buffer(_w: int):
|
def ensure_buffer(_w: int):
|
||||||
nonlocal ring, width, head, x_shared, ring_fft, freq_shared
|
nonlocal ring, width, head, x_shared, ring_fft, freq_shared, ring_time
|
||||||
if ring is not None:
|
if ring is not None:
|
||||||
return
|
return
|
||||||
width = WF_WIDTH
|
width = WF_WIDTH
|
||||||
x_shared = np.arange(width, dtype=np.int32)
|
x_shared = np.arange(width, dtype=np.int32)
|
||||||
ring = np.full((max_sweeps, width), np.nan, dtype=np.float32)
|
ring = np.full((max_sweeps, width), np.nan, dtype=np.float32)
|
||||||
|
ring_time = np.full((max_sweeps,), np.nan, dtype=np.float64)
|
||||||
head = 0
|
head = 0
|
||||||
# Обновляем изображение под новые размеры: время по X (горизонталь), X по Y
|
# Обновляем изображение под новые размеры: время по X (горизонталь), X по Y
|
||||||
img_obj.set_data(np.zeros((width, max_sweeps), dtype=np.float32))
|
img_obj.set_data(np.zeros((width, max_sweeps), dtype=np.float32))
|
||||||
@ -522,7 +524,7 @@ def main():
|
|||||||
freq_shared = np.arange(fft_bins, dtype=np.int32)
|
freq_shared = np.arange(fft_bins, dtype=np.int32)
|
||||||
|
|
||||||
def push_sweep(s: np.ndarray):
|
def push_sweep(s: np.ndarray):
|
||||||
nonlocal ring, head, y_min, y_max, ring_fft, y_min_fft, y_max_fft
|
nonlocal ring, head, y_min, y_max, ring_fft, y_min_fft, y_max_fft, ring_time
|
||||||
if s is None or s.size == 0 or ring is None:
|
if s is None or s.size == 0 or ring is None:
|
||||||
return
|
return
|
||||||
# Нормализуем длину до фиксированной ширины
|
# Нормализуем длину до фиксированной ширины
|
||||||
@ -531,6 +533,8 @@ def main():
|
|||||||
take = min(w, s.size)
|
take = min(w, s.size)
|
||||||
row[:take] = s[:take]
|
row[:take] = s[:take]
|
||||||
ring[head, :] = row
|
ring[head, :] = row
|
||||||
|
if ring_time is not None:
|
||||||
|
ring_time[head] = time.time()
|
||||||
head = (head + 1) % ring.shape[0]
|
head = (head + 1) % ring.shape[0]
|
||||||
# Обновляем мин/макс по данным (игнорим NaN)
|
# Обновляем мин/макс по данным (игнорим NaN)
|
||||||
sv_min = np.nanmin(row)
|
sv_min = np.nanmin(row)
|
||||||
@ -593,6 +597,12 @@ def main():
|
|||||||
base = ring if head == 0 else np.roll(ring, -head, axis=0)
|
base = ring if head == 0 else np.roll(ring, -head, axis=0)
|
||||||
return base.T # (width, time)
|
return base.T # (width, time)
|
||||||
|
|
||||||
|
def make_display_times():
|
||||||
|
if ring_time is None:
|
||||||
|
return None
|
||||||
|
base_t = ring_time if head == 0 else np.roll(ring_time, -head)
|
||||||
|
return base_t
|
||||||
|
|
||||||
def make_display_ring_fft():
|
def make_display_ring_fft():
|
||||||
if ring_fft is None:
|
if ring_fft is None:
|
||||||
return np.zeros((1, 1), dtype=np.float32)
|
return np.zeros((1, 1), dtype=np.float32)
|
||||||
@ -649,9 +659,17 @@ def main():
|
|||||||
# Обновление водопада
|
# Обновление водопада
|
||||||
if changed and ring is not None:
|
if changed and ring is not None:
|
||||||
disp = make_display_ring()
|
disp = make_display_ring()
|
||||||
# Новые данные слева: реверсируем время по X
|
# Новые данные справа: без реверса
|
||||||
disp = disp[:, ::-1]
|
|
||||||
img_obj.set_data(disp)
|
img_obj.set_data(disp)
|
||||||
|
times = make_display_times()
|
||||||
|
if times is not None and np.isfinite(times).sum() >= 2:
|
||||||
|
t0 = float(times[np.isfinite(times)][0])
|
||||||
|
rel = times - t0
|
||||||
|
T = disp.shape[1]
|
||||||
|
idx = np.linspace(0, T - 1, num=5, dtype=int)
|
||||||
|
labels = [f"{rel[i]:.1f}" if np.isfinite(rel[i]) else "" for i in idx]
|
||||||
|
ax_img.set_xticks(idx)
|
||||||
|
ax_img.set_xticklabels(labels)
|
||||||
# Актуализируем цветовую шкалу только при расширении экстремумов
|
# Актуализируем цветовую шкалу только при расширении экстремумов
|
||||||
if y_min is not None and y_max is not None and np.isfinite(y_min) and np.isfinite(y_max):
|
if y_min is not None and y_max is not None and np.isfinite(y_min) and np.isfinite(y_max):
|
||||||
if y_min != y_max:
|
if y_min != y_max:
|
||||||
@ -660,8 +678,17 @@ def main():
|
|||||||
# Обновление водопада спектров
|
# Обновление водопада спектров
|
||||||
if changed and ring_fft is not None:
|
if changed and ring_fft is not None:
|
||||||
disp_fft = make_display_ring_fft()
|
disp_fft = make_display_ring_fft()
|
||||||
disp_fft = disp_fft[:, ::-1]
|
# Новые данные справа: без реверса
|
||||||
img_fft_obj.set_data(disp_fft)
|
img_fft_obj.set_data(disp_fft)
|
||||||
|
times = make_display_times()
|
||||||
|
if times is not None and np.isfinite(times).sum() >= 2:
|
||||||
|
t0 = float(times[np.isfinite(times)][0])
|
||||||
|
rel = times - t0
|
||||||
|
T = disp_fft.shape[1]
|
||||||
|
idx = np.linspace(0, T - 1, num=5, dtype=int)
|
||||||
|
labels = [f"{rel[i]:.1f}" if np.isfinite(rel[i]) else "" for i in idx]
|
||||||
|
ax_spec.set_xticks(idx)
|
||||||
|
ax_spec.set_xticklabels(labels)
|
||||||
# Автодиапазон по среднему спектру за видимый интервал (как в хорошей версии)
|
# Автодиапазон по среднему спектру за видимый интервал (как в хорошей версии)
|
||||||
try:
|
try:
|
||||||
# disp_fft имеет форму (bins, time); берём среднее по времени
|
# disp_fft имеет форму (bins, time); берём среднее по времени
|
||||||
@ -739,7 +766,7 @@ def run_pyqtgraph(args):
|
|||||||
p_img = win.addPlot(row=0, col=1, title="Сырые данные водопад")
|
p_img = win.addPlot(row=0, col=1, title="Сырые данные водопад")
|
||||||
p_img.invertY(False)
|
p_img.invertY(False)
|
||||||
p_img.showGrid(x=False, y=False)
|
p_img.showGrid(x=False, y=False)
|
||||||
p_img.setLabel("bottom", "Время (новое слева)")
|
p_img.setLabel("bottom", "Время, с (новое справа)")
|
||||||
p_img.setLabel("left", "X (0 снизу)")
|
p_img.setLabel("left", "X (0 снизу)")
|
||||||
img = pg.ImageItem()
|
img = pg.ImageItem()
|
||||||
p_img.addItem(img)
|
p_img.addItem(img)
|
||||||
@ -755,7 +782,7 @@ def run_pyqtgraph(args):
|
|||||||
p_spec = win.addPlot(row=1, col=1, title="B-scan (дБ)")
|
p_spec = win.addPlot(row=1, col=1, title="B-scan (дБ)")
|
||||||
p_spec.invertY(True)
|
p_spec.invertY(True)
|
||||||
p_spec.showGrid(x=False, y=False)
|
p_spec.showGrid(x=False, y=False)
|
||||||
p_spec.setLabel("bottom", "Время (новое слева)")
|
p_spec.setLabel("bottom", "Время, с (новое справа)")
|
||||||
p_spec.setLabel("left", "Бин (0 снизу)")
|
p_spec.setLabel("left", "Бин (0 снизу)")
|
||||||
img_fft = pg.ImageItem()
|
img_fft = pg.ImageItem()
|
||||||
p_spec.addItem(img_fft)
|
p_spec.addItem(img_fft)
|
||||||
|
|||||||
Reference in New Issue
Block a user