translated to russian
This commit is contained in:
@ -65,13 +65,13 @@ class BScanProcessor(BaseProcessor):
|
|||||||
return [
|
return [
|
||||||
UIParameter(
|
UIParameter(
|
||||||
name="open_air",
|
name="open_air",
|
||||||
label="Open Air Reference",
|
label="Референс открытого воздуха",
|
||||||
type="toggle",
|
type="toggle",
|
||||||
value=cfg["open_air"],
|
value=cfg["open_air"],
|
||||||
),
|
),
|
||||||
UIParameter(
|
UIParameter(
|
||||||
name="axis",
|
name="axis",
|
||||||
label="Axis",
|
label="Ось",
|
||||||
type="select",
|
type="select",
|
||||||
value=cfg["axis"],
|
value=cfg["axis"],
|
||||||
options={"choices": ["real", "abs", "phase"]},
|
options={"choices": ["real", "abs", "phase"]},
|
||||||
@ -85,45 +85,45 @@ class BScanProcessor(BaseProcessor):
|
|||||||
# ),
|
# ),
|
||||||
UIParameter(
|
UIParameter(
|
||||||
name="cut",
|
name="cut",
|
||||||
label="Cut (m)",
|
label="Отсечка (м)",
|
||||||
type="slider",
|
type="slider",
|
||||||
value=cfg["cut"],
|
value=cfg["cut"],
|
||||||
options={"min": 0.0, "max": 2.0, "step": 0.001, "dtype": "float"},
|
options={"min": 0.0, "max": 2.0, "step": 0.001, "dtype": "float"},
|
||||||
),
|
),
|
||||||
UIParameter(
|
UIParameter(
|
||||||
name="max",
|
name="max",
|
||||||
label="Max Depth (m)",
|
label="Макс. глубина (м)",
|
||||||
type="slider",
|
type="slider",
|
||||||
value=cfg["max"],
|
value=cfg["max"],
|
||||||
options={"min": 0.1, "max": 5.0, "step": 0.1, "dtype": "float"},
|
options={"min": 0.1, "max": 5.0, "step": 0.1, "dtype": "float"},
|
||||||
),
|
),
|
||||||
UIParameter(
|
UIParameter(
|
||||||
name="gain",
|
name="gain",
|
||||||
label="Gain Factor",
|
label="Коэф. усиления",
|
||||||
type="slider",
|
type="slider",
|
||||||
value=cfg["gain"],
|
value=cfg["gain"],
|
||||||
options={"min": 0.0, "max": 3.0, "step": 0.1, "dtype": "float"},
|
options={"min": 0.0, "max": 3.0, "step": 0.1, "dtype": "float"},
|
||||||
),
|
),
|
||||||
UIParameter(
|
UIParameter(
|
||||||
name="start_freq",
|
name="start_freq",
|
||||||
label="Start Frequency (MHz)",
|
label="Нач. частота (МГц)",
|
||||||
type="slider",
|
type="slider",
|
||||||
value=cfg["start_freq"],
|
value=cfg["start_freq"],
|
||||||
options={"min": 100.0, "max": 8800.0, "step": 10.0, "dtype": "float"},
|
options={"min": 100.0, "max": 8800.0, "step": 10.0, "dtype": "float"},
|
||||||
),
|
),
|
||||||
UIParameter(
|
UIParameter(
|
||||||
name="stop_freq",
|
name="stop_freq",
|
||||||
label="Stop Frequency (MHz)",
|
label="Кон. частота (МГц)",
|
||||||
type="slider",
|
type="slider",
|
||||||
value=cfg["stop_freq"],
|
value=cfg["stop_freq"],
|
||||||
options={"min": 100.0, "max": 8800.0, "step": 10.0, "dtype": "float"},
|
options={"min": 100.0, "max": 8800.0, "step": 10.0, "dtype": "float"},
|
||||||
),
|
),
|
||||||
UIParameter(
|
UIParameter(
|
||||||
name="clear_history",
|
name="clear_history",
|
||||||
label="Clear Plot History",
|
label="Очистить историю",
|
||||||
type="button",
|
type="button",
|
||||||
value=False,
|
value=False,
|
||||||
options={"action": "Clear accumulated plot history"},
|
options={"action": "Очистить накопленную историю графика"},
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -258,10 +258,10 @@ class BScanProcessor(BaseProcessor):
|
|||||||
return {
|
return {
|
||||||
"data": [],
|
"data": [],
|
||||||
"layout": {
|
"layout": {
|
||||||
"title": "B-Scan Analysis - Error",
|
"title": "B-Scan анализ - Ошибка",
|
||||||
"annotations": [
|
"annotations": [
|
||||||
{
|
{
|
||||||
"text": f"Error: {processed_data['error']}",
|
"text": f"Ошибка: {processed_data['error']}",
|
||||||
"x": 0.5,
|
"x": 0.5,
|
||||||
"y": 0.5,
|
"y": 0.5,
|
||||||
"xref": "paper",
|
"xref": "paper",
|
||||||
@ -280,9 +280,9 @@ class BScanProcessor(BaseProcessor):
|
|||||||
return {
|
return {
|
||||||
"data": [],
|
"data": [],
|
||||||
"layout": {
|
"layout": {
|
||||||
"title": "B-Scan Analysis - No Data",
|
"title": "B-Scan анализ - Нет данных",
|
||||||
"xaxis": {"title": "Sweep Number"},
|
"xaxis": {"title": "Номер развертки"},
|
||||||
"yaxis": {"title": "Depth (m)"},
|
"yaxis": {"title": "Глубина (м)"},
|
||||||
"template": "plotly_dark",
|
"template": "plotly_dark",
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@ -316,11 +316,11 @@ class BScanProcessor(BaseProcessor):
|
|||||||
"y": y_coords,
|
"y": y_coords,
|
||||||
"z": z_values,
|
"z": z_values,
|
||||||
"colorscale": colorscale,
|
"colorscale": colorscale,
|
||||||
"colorbar": {"title": "Amplitude"},
|
"colorbar": {"title": "Амплитуда"},
|
||||||
"hovertemplate": (
|
"hovertemplate": (
|
||||||
"Sweep: %{x}<br>"
|
"Развертка: %{x}<br>"
|
||||||
"Depth: %{y:.3f} m<br>"
|
"Глубина: %{y:.3f} м<br>"
|
||||||
"Amplitude: %{z:.3f}<br>"
|
"Амплитуда: %{z:.3f}<br>"
|
||||||
"<extra></extra>"
|
"<extra></extra>"
|
||||||
),
|
),
|
||||||
**heatmap_kwargs,
|
**heatmap_kwargs,
|
||||||
@ -328,28 +328,28 @@ class BScanProcessor(BaseProcessor):
|
|||||||
|
|
||||||
freq_start, freq_stop = processed_data.get("frequency_range", [0.0, 0.0])
|
freq_start, freq_stop = processed_data.get("frequency_range", [0.0, 0.0])
|
||||||
config_info = (
|
config_info = (
|
||||||
f"Freq: {freq_start/1e6:.1f}-{freq_stop/1e6:.1f} MHz | "
|
f"Частота: {freq_start/1e6:.1f}-{freq_stop/1e6:.1f} МГц | "
|
||||||
f"Gain: {self._config['gain']:.1f} | "
|
f"Усиление: {self._config['gain']:.1f} | "
|
||||||
f"Cut: {self._config['cut']:.3f} m | "
|
f"Отсечка: {self._config['cut']:.3f} м | "
|
||||||
f"Max: {self._config['max']:.1f} m | "
|
f"Макс глубина: {self._config['max']:.1f} м | "
|
||||||
f"Axis: {self._config['axis']} | "
|
f"Ось: {self._config['axis']} | "
|
||||||
f"Sweeps: {len(history)}"
|
f"Разверток: {len(history)}"
|
||||||
)
|
)
|
||||||
|
|
||||||
if processed_data.get("reference_used", False):
|
if processed_data.get("reference_used", False):
|
||||||
config_info += " | Open Air: ON"
|
config_info += " | Открытый воздух: ВКЛ"
|
||||||
|
|
||||||
# if self._config["data_limitation"]:
|
# if self._config["data_limitation"]:
|
||||||
# config_info += f" | Limit: {self._config['data_limitation']}"
|
# config_info += f" | Limit: {self._config['data_limitation']}"
|
||||||
|
|
||||||
layout = {
|
layout = {
|
||||||
"title": f"B-Scan Heatmap - {config_info}",
|
"title": f"B-Scan тепловая карта - {config_info}",
|
||||||
"xaxis": {"title": "Sweep Number", "side": "bottom"},
|
"xaxis": {"title": "Номер развертки", "side": "bottom"},
|
||||||
"yaxis": {"title": "Depth (m)", "autorange": "reversed"},
|
"yaxis": {"title": "Глубина (м)", "autorange": "reversed"},
|
||||||
"hovermode": "closest",
|
"hovermode": "closest",
|
||||||
"height": 546,
|
"height": 546,
|
||||||
"template": "plotly_dark",
|
"template": "plotly_dark",
|
||||||
"margin": {"t": 40, "r": 50, "b": 110, "l": 50},
|
"margin": {"t": 40, "r": 50, "b": 110, "l": 50},
|
||||||
"autosize": True
|
"autosize": True
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -137,7 +137,7 @@ class MagnitudeProcessor(BaseProcessor):
|
|||||||
"y": mags_db,
|
"y": mags_db,
|
||||||
"type": "scatter",
|
"type": "scatter",
|
||||||
"mode": "lines",
|
"mode": "lines",
|
||||||
"name": f"|{parameter_type}| Magnitude",
|
"name": f"|{parameter_type}| Амплитуда",
|
||||||
"line": {"color": magnitude_color, "width": 2},
|
"line": {"color": magnitude_color, "width": 2},
|
||||||
"yaxis": "y",
|
"yaxis": "y",
|
||||||
})
|
})
|
||||||
@ -149,15 +149,15 @@ class MagnitudeProcessor(BaseProcessor):
|
|||||||
"y": phases_deg,
|
"y": phases_deg,
|
||||||
"type": "scatter",
|
"type": "scatter",
|
||||||
"mode": "lines",
|
"mode": "lines",
|
||||||
"name": f"∠{parameter_type} Phase",
|
"name": f"∠{parameter_type} Фаза",
|
||||||
"line": {"color": phase_color, "width": 2},
|
"line": {"color": phase_color, "width": 2},
|
||||||
"yaxis": "y2" if show_magnitude else "y",
|
"yaxis": "y2" if show_magnitude else "y",
|
||||||
})
|
})
|
||||||
|
|
||||||
# Layout configuration
|
# Layout configuration
|
||||||
layout = {
|
layout = {
|
||||||
"title": f"{parameter_type} Response",
|
"title": f"Отклик {parameter_type}",
|
||||||
"xaxis": {"title": "Frequency (GHz)", "showgrid": True},
|
"xaxis": {"title": "Частота (ГГц)", "showgrid": True},
|
||||||
"hovermode": "x unified",
|
"hovermode": "x unified",
|
||||||
"showlegend": True,
|
"showlegend": True,
|
||||||
}
|
}
|
||||||
@ -165,7 +165,7 @@ class MagnitudeProcessor(BaseProcessor):
|
|||||||
# Configure y-axis based on what's shown
|
# Configure y-axis based on what's shown
|
||||||
if show_magnitude:
|
if show_magnitude:
|
||||||
y_axis_config = {
|
y_axis_config = {
|
||||||
"title": "Magnitude (dB)",
|
"title": "Амплитуда (дБ)",
|
||||||
"showgrid": True,
|
"showgrid": True,
|
||||||
"side": "left",
|
"side": "left",
|
||||||
"titlefont": {"color": magnitude_color},
|
"titlefont": {"color": magnitude_color},
|
||||||
@ -183,7 +183,7 @@ class MagnitudeProcessor(BaseProcessor):
|
|||||||
if show_magnitude:
|
if show_magnitude:
|
||||||
# Phase on second axis (radians converted to degrees, but displayed as -π to π)
|
# Phase on second axis (radians converted to degrees, but displayed as -π to π)
|
||||||
layout["yaxis2"] = {
|
layout["yaxis2"] = {
|
||||||
"title": "Phase (rad)",
|
"title": "Фаза (рад)",
|
||||||
"overlaying": "y",
|
"overlaying": "y",
|
||||||
"side": "right",
|
"side": "right",
|
||||||
"showgrid": False,
|
"showgrid": False,
|
||||||
@ -194,7 +194,7 @@ class MagnitudeProcessor(BaseProcessor):
|
|||||||
else:
|
else:
|
||||||
# Phase on primary axis if magnitude is hidden
|
# Phase on primary axis if magnitude is hidden
|
||||||
layout["yaxis"] = {
|
layout["yaxis"] = {
|
||||||
"title": "Phase (rad)",
|
"title": "Фаза (рад)",
|
||||||
"showgrid": True,
|
"showgrid": True,
|
||||||
"side": "left",
|
"side": "left",
|
||||||
"range": [-180, 180], # -π to π in degrees
|
"range": [-180, 180], # -π to π in degrees
|
||||||
@ -218,32 +218,32 @@ class MagnitudeProcessor(BaseProcessor):
|
|||||||
return [
|
return [
|
||||||
UIParameter(
|
UIParameter(
|
||||||
name="show_magnitude",
|
name="show_magnitude",
|
||||||
label="Show Magnitude",
|
label="Показать амплитуду",
|
||||||
type="toggle",
|
type="toggle",
|
||||||
value=self._config.get("show_magnitude", True),
|
value=self._config.get("show_magnitude", True),
|
||||||
),
|
),
|
||||||
UIParameter(
|
UIParameter(
|
||||||
name="show_phase",
|
name="show_phase",
|
||||||
label="Show Phase",
|
label="Показать фазу",
|
||||||
type="toggle",
|
type="toggle",
|
||||||
value=self._config.get("show_phase", False),
|
value=self._config.get("show_phase", False),
|
||||||
),
|
),
|
||||||
UIParameter(
|
UIParameter(
|
||||||
name="autoscale",
|
name="autoscale",
|
||||||
label="Autoscale Y Axis",
|
label="Автомасштаб оси Y",
|
||||||
type="toggle",
|
type="toggle",
|
||||||
value=self._config.get("autoscale", False),
|
value=self._config.get("autoscale", False),
|
||||||
),
|
),
|
||||||
UIParameter(
|
UIParameter(
|
||||||
name="y_min",
|
name="y_min",
|
||||||
label="Y Axis Min (dB)",
|
label="Мин. ось Y (дБ)",
|
||||||
type="slider",
|
type="slider",
|
||||||
value=self._config.get("y_min", -80),
|
value=self._config.get("y_min", -80),
|
||||||
options={"min": -80, "max": 20, "step": 5, "dtype": "int"},
|
options={"min": -80, "max": 20, "step": 5, "dtype": "int"},
|
||||||
),
|
),
|
||||||
UIParameter(
|
UIParameter(
|
||||||
name="y_max",
|
name="y_max",
|
||||||
label="Y Axis Max (dB)",
|
label="Макс. ось Y (дБ)",
|
||||||
type="slider",
|
type="slider",
|
||||||
value=self._config.get("y_max", 10),
|
value=self._config.get("y_max", 10),
|
||||||
options={"min": -20, "max": 40, "step": 5, "dtype": "int"},
|
options={"min": -20, "max": 40, "step": 5, "dtype": "int"},
|
||||||
|
|||||||
@ -105,19 +105,19 @@ class ProcessorWebSocketHandler:
|
|||||||
elif mtype == "get_processor_state":
|
elif mtype == "get_processor_state":
|
||||||
await self._handle_get_processor_state(websocket, message)
|
await self._handle_get_processor_state(websocket, message)
|
||||||
else:
|
else:
|
||||||
await self._send_error(websocket, f"Unknown message type: {mtype!r}")
|
await self._send_error(websocket, f"Неизвестный тип сообщения: {mtype!r}")
|
||||||
except json.JSONDecodeError as json_error:
|
except json.JSONDecodeError as json_error:
|
||||||
logger.error("JSON decode error", raw_data=data[:200], error=str(json_error))
|
logger.error("JSON decode error", raw_data=data[:200], error=str(json_error))
|
||||||
await self._send_error(
|
await self._send_error(
|
||||||
websocket,
|
websocket,
|
||||||
"Invalid JSON format",
|
"Неверный формат JSON",
|
||||||
details=f"JSON parse error: {json_error}",
|
details=f"Ошибка парсинга JSON: {json_error}",
|
||||||
source="websocket_handler",
|
source="websocket_handler",
|
||||||
raw_data=data[:200] if len(data) <= 200 else f"{data[:200]}..."
|
raw_data=data[:200] if len(data) <= 200 else f"{data[:200]}..."
|
||||||
)
|
)
|
||||||
except Exception as exc: # noqa: BLE001
|
except Exception as exc: # noqa: BLE001
|
||||||
logger.error("Error handling websocket message")
|
logger.error("Error handling websocket message")
|
||||||
await self._send_error(websocket, f"Internal error: {exc}")
|
await self._send_error(websocket, f"Внутренняя ошибка: {exc}")
|
||||||
|
|
||||||
# --------------------------------------------------------------------- #
|
# --------------------------------------------------------------------- #
|
||||||
# Client commands
|
# Client commands
|
||||||
@ -130,7 +130,7 @@ class ProcessorWebSocketHandler:
|
|||||||
config_updates = message.get("config_updates")
|
config_updates = message.get("config_updates")
|
||||||
|
|
||||||
if not processor_id:
|
if not processor_id:
|
||||||
await self._send_error(websocket, "processor_id is required")
|
await self._send_error(websocket, "Требуется processor_id")
|
||||||
return
|
return
|
||||||
|
|
||||||
try:
|
try:
|
||||||
@ -138,10 +138,10 @@ class ProcessorWebSocketHandler:
|
|||||||
if result:
|
if result:
|
||||||
await websocket.send_text(json.dumps(self._result_to_message(processor_id, result)))
|
await websocket.send_text(json.dumps(self._result_to_message(processor_id, result)))
|
||||||
else:
|
else:
|
||||||
await self._send_error(websocket, f"No result from processor {processor_id}")
|
await self._send_error(websocket, f"Нет результата от процессора {processor_id}")
|
||||||
except Exception as exc: # noqa: BLE001
|
except Exception as exc: # noqa: BLE001
|
||||||
logger.error("Recalculation failed")
|
logger.error("Recalculation failed")
|
||||||
await self._send_error(websocket, f"Recalculation failed: {exc}")
|
await self._send_error(websocket, f"Пересчёт не удался: {exc}")
|
||||||
|
|
||||||
async def _handle_get_history(self, websocket: WebSocket, message: dict[str, Any]) -> None:
|
async def _handle_get_history(self, websocket: WebSocket, message: dict[str, Any]) -> None:
|
||||||
"""
|
"""
|
||||||
@ -151,7 +151,7 @@ class ProcessorWebSocketHandler:
|
|||||||
limit = int(message.get("limit", 10))
|
limit = int(message.get("limit", 10))
|
||||||
|
|
||||||
if not processor_id:
|
if not processor_id:
|
||||||
await self._send_error(websocket, "processor_id is required")
|
await self._send_error(websocket, "Требуется processor_id")
|
||||||
return
|
return
|
||||||
|
|
||||||
try:
|
try:
|
||||||
@ -172,7 +172,7 @@ class ProcessorWebSocketHandler:
|
|||||||
await websocket.send_text(json.dumps(response))
|
await websocket.send_text(json.dumps(response))
|
||||||
except Exception as exc: # noqa: BLE001
|
except Exception as exc: # noqa: BLE001
|
||||||
logger.error("Error getting history")
|
logger.error("Error getting history")
|
||||||
await self._send_error(websocket, f"Error getting history: {exc}")
|
await self._send_error(websocket, f"Ошибка получения истории: {exc}")
|
||||||
|
|
||||||
async def _handle_load_history(self, websocket: WebSocket, message: dict[str, Any]) -> None:
|
async def _handle_load_history(self, websocket: WebSocket, message: dict[str, Any]) -> None:
|
||||||
"""
|
"""
|
||||||
@ -182,11 +182,11 @@ class ProcessorWebSocketHandler:
|
|||||||
history_data = message.get("history_data")
|
history_data = message.get("history_data")
|
||||||
|
|
||||||
if not processor_id:
|
if not processor_id:
|
||||||
await self._send_error(websocket, "processor_id is required")
|
await self._send_error(websocket, "Требуется processor_id")
|
||||||
return
|
return
|
||||||
|
|
||||||
if not history_data or not isinstance(history_data, list):
|
if not history_data or not isinstance(history_data, list):
|
||||||
await self._send_error(websocket, "history_data (list) is required")
|
await self._send_error(websocket, "Требуется history_data (список)")
|
||||||
return
|
return
|
||||||
|
|
||||||
try:
|
try:
|
||||||
@ -194,10 +194,10 @@ class ProcessorWebSocketHandler:
|
|||||||
if result:
|
if result:
|
||||||
await websocket.send_text(json.dumps(self._result_to_message(processor_id, result)))
|
await websocket.send_text(json.dumps(self._result_to_message(processor_id, result)))
|
||||||
else:
|
else:
|
||||||
await self._send_error(websocket, f"No result from processor {processor_id} after loading history")
|
await self._send_error(websocket, f"Нет результата от процессора {processor_id} после загрузки истории")
|
||||||
except Exception as exc: # noqa: BLE001
|
except Exception as exc: # noqa: BLE001
|
||||||
logger.error("History load failed", processor_id=processor_id, error=repr(exc))
|
logger.error("History load failed", processor_id=processor_id, error=repr(exc))
|
||||||
await self._send_error(websocket, f"History load failed: {exc}")
|
await self._send_error(websocket, f"Загрузка истории не удалась: {exc}")
|
||||||
|
|
||||||
async def _handle_get_processor_state(self, websocket: WebSocket, message: dict[str, Any]) -> None:
|
async def _handle_get_processor_state(self, websocket: WebSocket, message: dict[str, Any]) -> None:
|
||||||
"""
|
"""
|
||||||
@ -209,7 +209,7 @@ class ProcessorWebSocketHandler:
|
|||||||
processor_id = message.get("processor_id")
|
processor_id = message.get("processor_id")
|
||||||
|
|
||||||
if not processor_id:
|
if not processor_id:
|
||||||
await self._send_error(websocket, "processor_id is required")
|
await self._send_error(websocket, "Требуется processor_id")
|
||||||
return
|
return
|
||||||
|
|
||||||
try:
|
try:
|
||||||
@ -217,7 +217,7 @@ class ProcessorWebSocketHandler:
|
|||||||
await websocket.send_text(json.dumps(response))
|
await websocket.send_text(json.dumps(response))
|
||||||
except Exception as exc: # noqa: BLE001
|
except Exception as exc: # noqa: BLE001
|
||||||
logger.error("Error getting processor state", processor_id=processor_id, error=repr(exc))
|
logger.error("Error getting processor state", processor_id=processor_id, error=repr(exc))
|
||||||
await self._send_error(websocket, f"Error getting processor state: {exc}")
|
await self._send_error(websocket, f"Ошибка получения состояния процессора: {exc}")
|
||||||
|
|
||||||
def _result_to_message(self, processor_id: str, result: ProcessedResult) -> dict[str, Any]:
|
def _result_to_message(self, processor_id: str, result: ProcessedResult) -> dict[str, Any]:
|
||||||
"""
|
"""
|
||||||
|
|||||||
Reference in New Issue
Block a user