From 451c0654f56d3621eff1bd43c32ea5690a4ed9a3 Mon Sep 17 00:00:00 2001 From: Ayzen Date: Fri, 26 Sep 2025 17:22:03 +0300 Subject: [PATCH] improved codestyle and added logging --- vna_system/api/api_config.json | 9 - vna_system/api/endpoints/acquisition.py | 116 +- vna_system/api/endpoints/settings.py | 401 +- vna_system/api/main.py | 143 - .../еуыеуые/calibration_info.json | 18 + .../еуыеуые/load.json | 4007 +++++++++++++++++ .../еуыеуые/load_metadata.json | 16 + .../еуыеуые/open.json | 4007 +++++++++++++++++ .../еуыеуые/open_metadata.json | 16 + .../еуыеуые/short.json | 4007 +++++++++++++++++ .../еуыеуые/short_metadata.json | 16 + .../яыф/calibration_info.json | 18 + .../яыф/load.json | 4007 +++++++++++++++++ .../яыф/load_metadata.json | 16 + .../яыф/open.json | 4007 +++++++++++++++++ .../яыф/open_metadata.json | 16 + .../яыф/short.json | 4007 +++++++++++++++++ .../яыф/short_metadata.json | 16 + .../core/acquisition/data_acquisition.py | 177 +- vna_system/core/acquisition/port_manager.py | 136 + vna_system/core/acquisition/sweep_buffer.py | 108 +- vna_system/core/config.py | 130 +- vna_system/core/logging/__init__.py | 9 + vna_system/core/logging/logger.py | 257 ++ vna_system/core/processors/base_processor.py | 624 ++- .../core/processors/calibration_processor.py | 190 +- .../processors/configs/magnitude_config.json | 11 +- .../core/processors/configs/phase_config.json | 8 +- .../implementations/magnitude_processor.py | 426 +- .../implementations/phase_processor.py | 467 +- vna_system/core/processors/manager.py | 316 +- .../core/processors/websocket_handler.py | 283 +- .../core/settings/calibration_manager.py | 388 +- vna_system/core/settings/preset_manager.py | 227 +- vna_system/core/settings/settings_manager.py | 226 +- vna_system/core/singletons.py | 4 +- .../core/visualization/magnitude_chart.py | 410 +- vna_system/main.py | 106 + vna_system/scripts/start.sh | 4 +- 39 files changed, 27401 insertions(+), 1949 deletions(-) delete mode 100644 vna_system/api/api_config.json delete mode 100644 vna_system/api/main.py create mode 100644 vna_system/calibration/s11_start100_stop8800_points1000_bw1khz/еуыеуые/calibration_info.json create mode 100644 vna_system/calibration/s11_start100_stop8800_points1000_bw1khz/еуыеуые/load.json create mode 100644 vna_system/calibration/s11_start100_stop8800_points1000_bw1khz/еуыеуые/load_metadata.json create mode 100644 vna_system/calibration/s11_start100_stop8800_points1000_bw1khz/еуыеуые/open.json create mode 100644 vna_system/calibration/s11_start100_stop8800_points1000_bw1khz/еуыеуые/open_metadata.json create mode 100644 vna_system/calibration/s11_start100_stop8800_points1000_bw1khz/еуыеуые/short.json create mode 100644 vna_system/calibration/s11_start100_stop8800_points1000_bw1khz/еуыеуые/short_metadata.json create mode 100644 vna_system/calibration/s11_start100_stop8800_points1000_bw1khz/яыф/calibration_info.json create mode 100644 vna_system/calibration/s11_start100_stop8800_points1000_bw1khz/яыф/load.json create mode 100644 vna_system/calibration/s11_start100_stop8800_points1000_bw1khz/яыф/load_metadata.json create mode 100644 vna_system/calibration/s11_start100_stop8800_points1000_bw1khz/яыф/open.json create mode 100644 vna_system/calibration/s11_start100_stop8800_points1000_bw1khz/яыф/open_metadata.json create mode 100644 vna_system/calibration/s11_start100_stop8800_points1000_bw1khz/яыф/short.json create mode 100644 vna_system/calibration/s11_start100_stop8800_points1000_bw1khz/яыф/short_metadata.json create mode 100644 vna_system/core/acquisition/port_manager.py create mode 100644 vna_system/core/logging/__init__.py create mode 100644 vna_system/core/logging/logger.py create mode 100644 vna_system/main.py diff --git a/vna_system/api/api_config.json b/vna_system/api/api_config.json deleted file mode 100644 index 08206f4..0000000 --- a/vna_system/api/api_config.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "server": { - "host": "0.0.0.0", - "port": 8000 - }, - "logging": { - "level": "INFO" - } -} \ No newline at end of file diff --git a/vna_system/api/endpoints/acquisition.py b/vna_system/api/endpoints/acquisition.py index e2225d4..85d1ca4 100644 --- a/vna_system/api/endpoints/acquisition.py +++ b/vna_system/api/endpoints/acquisition.py @@ -1,88 +1,148 @@ -from fastapi import APIRouter, HTTPException +from typing import Any + +from fastapi import APIRouter, HTTPException, Query + import vna_system.core.singletons as singletons +from vna_system.core.logging.logger import get_component_logger router = APIRouter(prefix="/api/v1", tags=["acquisition"]) +logger = get_component_logger(__file__) @router.get("/acquisition/status") -async def get_acquisition_status(): - """Get current acquisition status.""" +async def get_acquisition_status() -> dict[str, Any]: + """ + Return current acquisition status. + + Response + -------- + { + "running": bool, + "paused": bool, + "continuous_mode": bool, + "sweep_count": int + } + """ acquisition = singletons.vna_data_acquisition_instance + if acquisition is None: + logger.error("Acquisition singleton is not initialized") + raise HTTPException(status_code=500, detail="Acquisition not initialized") return { "running": acquisition.is_running, "paused": acquisition.is_paused, "continuous_mode": acquisition.is_continuous_mode, - "sweep_count": acquisition._sweep_buffer._sweep_counter if hasattr(acquisition._sweep_buffer, '_sweep_counter') else 0 + "sweep_count": acquisition.sweep_buffer.current_sweep_number, } @router.post("/acquisition/start") -async def start_acquisition(): - """Start data acquisition.""" +async def start_acquisition() -> dict[str, Any]: + """ + Start data acquisition in continuous mode (resumes if paused). + """ try: acquisition = singletons.vna_data_acquisition_instance + if acquisition is None: + logger.error("Acquisition singleton is not initialized") + raise HTTPException(status_code=500, detail="Acquisition not initialized") if not acquisition.is_running: - # Start thread if not running acquisition.start() + logger.info("Acquisition thread started via API") - # Set to continuous mode (also resumes if paused) acquisition.set_continuous_mode(True) return {"success": True, "message": "Acquisition started"} - except Exception as e: - raise HTTPException(status_code=500, detail=str(e)) + except HTTPException: + raise + except Exception as exc: # noqa: BLE001 + logger.error("Failed to start acquisition") + raise HTTPException(status_code=500, detail=str(exc)) @router.post("/acquisition/stop") -async def stop_acquisition(): - """Stop/pause data acquisition.""" +async def stop_acquisition() -> dict[str, Any]: + """ + Pause data acquisition (thread remains alive for fast resume). + """ try: acquisition = singletons.vna_data_acquisition_instance + if acquisition is None: + logger.error("Acquisition singleton is not initialized") + raise HTTPException(status_code=500, detail="Acquisition not initialized") + if not acquisition.is_running: return {"success": True, "message": "Acquisition already stopped"} - # Just pause instead of full stop - keeps thread alive for restart acquisition.pause() - return {"success": True, "message": "Acquisition stopped"} - except Exception as e: - raise HTTPException(status_code=500, detail=str(e)) + logger.info("Acquisition paused via API") + return {"success": True, "message": "Acquisition paused"} + except HTTPException: + raise + except Exception as exc: # noqa: BLE001 + logger.error("Failed to stop acquisition") + raise HTTPException(status_code=500, detail=str(exc)) @router.post("/acquisition/single-sweep") -async def trigger_single_sweep(): - """Trigger a single sweep. Automatically starts acquisition if needed.""" +async def trigger_single_sweep() -> dict[str, Any]: + """ + Trigger a single sweep. + Automatically starts acquisition if needed and switches to single-sweep mode. + """ try: acquisition = singletons.vna_data_acquisition_instance + if acquisition is None: + logger.error("Acquisition singleton is not initialized") + raise HTTPException(status_code=500, detail="Acquisition not initialized") if not acquisition.is_running: - # Start acquisition if not running acquisition.start() + logger.info("Acquisition thread started (single-sweep request)") acquisition.trigger_single_sweep() return {"success": True, "message": "Single sweep triggered"} - except Exception as e: - raise HTTPException(status_code=500, detail=str(e)) + except HTTPException: + raise + except Exception as exc: # noqa: BLE001 + logger.error("Failed to trigger single sweep") + raise HTTPException(status_code=500, detail=str(exc)) @router.get("/acquisition/latest-sweep") -async def get_latest_sweep(): - """Get the latest sweep data.""" +async def get_latest_sweep( + limit: int = Query(10, ge=1, le=1000, description="Max number of points to include in response"), +) -> dict[str, Any]: + """ + Return the latest sweep metadata and a limited subset of points. + + Query Params + ------------ + limit : int + Number of points to include from the start of the sweep (default 10, max 1000). + """ try: acquisition = singletons.vna_data_acquisition_instance - latest_sweep = acquisition._sweep_buffer.get_latest_sweep() + if acquisition is None: + logger.error("Acquisition singleton is not initialized") + raise HTTPException(status_code=500, detail="Acquisition not initialized") + latest_sweep = acquisition.sweep_buffer.get_latest_sweep() if not latest_sweep: return {"sweep": None, "message": "No sweep data available"} + points = latest_sweep.points[:limit] return { "sweep": { "sweep_number": latest_sweep.sweep_number, "timestamp": latest_sweep.timestamp, "total_points": latest_sweep.total_points, - "points": latest_sweep.points[:10] if len(latest_sweep.points) > 10 else latest_sweep.points # Limit for API response + "points": points, }, - "message": f"Latest sweep #{latest_sweep.sweep_number} with {latest_sweep.total_points} points" + "message": f"Latest sweep #{latest_sweep.sweep_number} with {latest_sweep.total_points} points", } - except Exception as e: - raise HTTPException(status_code=500, detail=str(e)) \ No newline at end of file + except HTTPException: + raise + except Exception as exc: # noqa: BLE001 + logger.error("Failed to fetch latest sweep") + raise HTTPException(status_code=500, detail=str(exc)) diff --git a/vna_system/api/endpoints/settings.py b/vna_system/api/endpoints/settings.py index bc3a0a1..8e8cf38 100644 --- a/vna_system/api/endpoints/settings.py +++ b/vna_system/api/endpoints/settings.py @@ -1,10 +1,13 @@ +from typing import Any, List # pydantic response_model uses List + from fastapi import APIRouter, HTTPException -from typing import List -from pathlib import Path import vna_system.core.singletons as singletons +from vna_system.core.logging.logger import get_component_logger from vna_system.core.settings.calibration_manager import CalibrationStandard -from vna_system.core.visualization.magnitude_chart import generate_standards_magnitude_plots, generate_combined_standards_plot +from vna_system.core.visualization.magnitude_chart import ( + generate_standards_magnitude_plots, +) from vna_system.api.models.settings import ( PresetModel, CalibrationModel, @@ -15,74 +18,81 @@ from vna_system.api.models.settings import ( SaveCalibrationRequest, SetCalibrationRequest, RemoveStandardRequest, - WorkingCalibrationModel + WorkingCalibrationModel, ) router = APIRouter(prefix="/api/v1/settings", tags=["settings"]) +logger = get_component_logger(__file__) @router.get("/status", response_model=SettingsStatusModel) -async def get_status(): - """Get current settings status""" +async def get_status() -> dict[str, Any]: + """Get current settings status.""" try: - status = singletons.settings_manager.get_status_summary() - return status - except Exception as e: - raise HTTPException(status_code=500, detail=str(e)) + return singletons.settings_manager.get_status_summary() + except Exception as exc: # noqa: BLE001 + logger.error("Failed to get settings status") + raise HTTPException(status_code=500, detail=str(exc)) @router.get("/presets", response_model=List[PresetModel]) -async def get_presets(mode: str | None = None): - """Get all available configuration presets, optionally filtered by mode""" +async def get_presets(mode: str | None = None) -> list[PresetModel]: + """Get all available configuration presets, optionally filtered by mode.""" try: if mode: from vna_system.core.settings.preset_manager import VNAMode + try: vna_mode = VNAMode(mode.lower()) - presets = singletons.settings_manager.get_presets_by_mode(vna_mode) except ValueError: raise HTTPException(status_code=400, detail=f"Invalid mode: {mode}") + presets = singletons.settings_manager.get_presets_by_mode(vna_mode) else: presets = singletons.settings_manager.get_available_presets() return [ PresetModel( - filename=preset.filename, - mode=preset.mode.value, - start_freq=preset.start_freq, - stop_freq=preset.stop_freq, - points=preset.points, - bandwidth=preset.bandwidth + filename=p.filename, + mode=p.mode.value, + start_freq=p.start_freq, + stop_freq=p.stop_freq, + points=p.points, + bandwidth=p.bandwidth, ) - for preset in presets + for p in presets ] - except Exception as e: - raise HTTPException(status_code=500, detail=str(e)) + except HTTPException: + raise + except Exception as exc: # noqa: BLE001 + logger.error("Failed to list presets") + raise HTTPException(status_code=500, detail=str(exc)) @router.post("/preset/set") -async def set_preset(request: SetPresetRequest): - """Set current configuration preset""" +async def set_preset(request: SetPresetRequest) -> dict[str, Any]: + """Set current configuration preset.""" try: - # Find preset by filename presets = singletons.settings_manager.get_available_presets() preset = next((p for p in presets if p.filename == request.filename), None) - - if not preset: + if preset is None: raise HTTPException(status_code=404, detail=f"Preset not found: {request.filename}") - # Clear current calibration when changing preset + # Changing preset invalidates active calibration selection. singletons.settings_manager.calibration_manager.clear_current_calibration() - singletons.settings_manager.set_current_preset(preset) + + logger.info("Preset selected via API", filename=preset.filename, mode=preset.mode.value) return {"success": True, "message": f"Preset set to {request.filename}"} - except Exception as e: - raise HTTPException(status_code=500, detail=str(e)) + except HTTPException: + raise + except Exception as exc: # noqa: BLE001 + logger.error("Failed to set preset") + raise HTTPException(status_code=500, detail=str(exc)) @router.get("/preset/current", response_model=PresetModel | None) async def get_current_preset(): - """Get currently selected configuration preset""" + """Get currently selected configuration preset.""" try: preset = singletons.settings_manager.get_current_preset() if not preset: @@ -94,171 +104,173 @@ async def get_current_preset(): start_freq=preset.start_freq, stop_freq=preset.stop_freq, points=preset.points, - bandwidth=preset.bandwidth + bandwidth=preset.bandwidth, ) - except Exception as e: - raise HTTPException(status_code=500, detail=str(e)) + except Exception as exc: # noqa: BLE001 + logger.error("Failed to get current preset") + raise HTTPException(status_code=500, detail=str(exc)) @router.get("/calibrations", response_model=List[CalibrationModel]) -async def get_calibrations(preset_filename: str | None = None): - """Get available calibrations for current or specified preset""" +async def get_calibrations(preset_filename: str | None = None) -> list[CalibrationModel]: + """Get available calibrations for current or specified preset.""" try: preset = None if preset_filename: presets = singletons.settings_manager.get_available_presets() preset = next((p for p in presets if p.filename == preset_filename), None) - if not preset: + if preset is None: raise HTTPException(status_code=404, detail=f"Preset not found: {preset_filename}") calibrations = singletons.settings_manager.get_available_calibrations(preset) - - # Get detailed info for each calibration - calibration_details = [] + details: list[CalibrationModel] = [] current_preset = preset or singletons.settings_manager.get_current_preset() if current_preset: - for calib_name in calibrations: - info = singletons.settings_manager.get_calibration_info(calib_name, current_preset) + for name in calibrations: + info = singletons.settings_manager.get_calibration_info(name, current_preset) + standards = info.get("standards", {}) - # Convert standards format if needed - standards = info.get('standards', {}) + # Normalize standards into {standard: bool} if isinstance(standards, list): - # If standards is a list (from complete calibration), convert to dict - required_standards = singletons.settings_manager.get_required_standards(current_preset.mode) - standards = {std.value: std.value in standards for std in required_standards} + required = singletons.settings_manager.get_required_standards(current_preset.mode) + standards = {std.value: (std.value in standards) for std in required} - calibration_details.append(CalibrationModel( - name=calib_name, - is_complete=info.get('is_complete', False), - standards=standards - )) + details.append( + CalibrationModel( + name=name, + is_complete=bool(info.get("is_complete", False)), + standards=standards, + ) + ) - return calibration_details - except Exception as e: - raise HTTPException(status_code=500, detail=str(e)) + return details + except HTTPException: + raise + except Exception as exc: # noqa: BLE001 + logger.error("Failed to list calibrations") + raise HTTPException(status_code=500, detail=str(exc)) @router.post("/calibration/start") -async def start_calibration(request: StartCalibrationRequest): - """Start new calibration for current or specified preset""" +async def start_calibration(request: StartCalibrationRequest) -> dict[str, Any]: + """Start new calibration for current or specified preset.""" try: preset = None if request.preset_filename: presets = singletons.settings_manager.get_available_presets() preset = next((p for p in presets if p.filename == request.preset_filename), None) - if not preset: + if preset is None: raise HTTPException(status_code=404, detail=f"Preset not found: {request.preset_filename}") - calibration_set = singletons.settings_manager.start_new_calibration(preset) - required_standards = singletons.settings_manager.get_required_standards(calibration_set.preset.mode) + calib = singletons.settings_manager.start_new_calibration(preset) + required = singletons.settings_manager.get_required_standards(calib.preset.mode) return { "success": True, "message": "Calibration started", - "preset": calibration_set.preset.filename, - "required_standards": [s.value for s in required_standards] + "preset": calib.preset.filename, + "required_standards": [s.value for s in required], } - except Exception as e: - raise HTTPException(status_code=500, detail=str(e)) + except HTTPException: + raise + except Exception as exc: # noqa: BLE001 + logger.error("Failed to start calibration") + raise HTTPException(status_code=500, detail=str(exc)) @router.post("/calibration/add-standard") -async def add_calibration_standard(request: CalibrateStandardRequest): - """Add calibration standard from latest sweep""" +async def add_calibration_standard(request: CalibrateStandardRequest) -> dict[str, Any]: + """Add calibration standard from the latest sweep.""" try: - # Validate standard try: standard = CalibrationStandard(request.standard) except ValueError: raise HTTPException(status_code=400, detail=f"Invalid calibration standard: {request.standard}") - # Capture from data acquisition - sweep_number = singletons.settings_manager.capture_calibration_standard_from_acquisition( + sweep_no = singletons.settings_manager.capture_calibration_standard_from_acquisition( standard, singletons.vna_data_acquisition_instance ) - # Get current working calibration status - working_calib = singletons.settings_manager.get_current_working_calibration() - progress = working_calib.get_progress() if working_calib else (0, 0) + working = singletons.settings_manager.get_current_working_calibration() + progress = working.get_progress() if working else (0, 0) return { "success": True, - "message": f"Added {standard.value} standard from sweep {sweep_number}", - "sweep_number": sweep_number, + "message": f"Added {standard.value} standard from sweep {sweep_no}", + "sweep_number": sweep_no, "progress": f"{progress[0]}/{progress[1]}", - "is_complete": working_calib.is_complete() if working_calib else False + "is_complete": working.is_complete() if working else False, } - except Exception as e: - raise HTTPException(status_code=500, detail=str(e)) + except HTTPException: + raise + except Exception as exc: # noqa: BLE001 + logger.error("Failed to add calibration standard") + raise HTTPException(status_code=500, detail=str(exc)) @router.post("/calibration/save") -async def save_calibration(request: SaveCalibrationRequest): - """Save current working calibration set""" +async def save_calibration(request: SaveCalibrationRequest) -> dict[str, Any]: + """Save current working calibration set.""" try: - calibration_set = singletons.settings_manager.save_calibration_set(request.name) - + saved = singletons.settings_manager.save_calibration_set(request.name) return { "success": True, "message": f"Calibration '{request.name}' saved successfully", - "preset": calibration_set.preset.filename, - "standards": list(calibration_set.standards.keys()) + "preset": saved.preset.filename, + "standards": [s.value for s in saved.standards.keys()], } - except Exception as e: - raise HTTPException(status_code=500, detail=str(e)) + except Exception as exc: # noqa: BLE001 + logger.error("Failed to save calibration") + raise HTTPException(status_code=500, detail=str(exc)) @router.post("/calibration/set") -async def set_calibration(request: SetCalibrationRequest): - """Set current active calibration""" +async def set_calibration(request: SetCalibrationRequest) -> dict[str, Any]: + """Set current active calibration.""" try: preset = None if request.preset_filename: presets = singletons.settings_manager.get_available_presets() preset = next((p for p in presets if p.filename == request.preset_filename), None) - if not preset: + if preset is None: raise HTTPException(status_code=404, detail=f"Preset not found: {request.preset_filename}") singletons.settings_manager.set_current_calibration(request.name, preset) - - return { - "success": True, - "message": f"Calibration set to '{request.name}'" - } - except Exception as e: - raise HTTPException(status_code=500, detail=str(e)) + return {"success": True, "message": f"Calibration set to '{request.name}'"} + except HTTPException: + raise + except Exception as exc: # noqa: BLE001 + logger.error("Failed to set calibration") + raise HTTPException(status_code=500, detail=str(exc)) @router.get("/working-calibration", response_model=WorkingCalibrationModel) -async def get_working_calibration(): - """Get current working calibration status""" +async def get_working_calibration() -> WorkingCalibrationModel: + """Get current working calibration status.""" try: - working_calib = singletons.settings_manager.get_current_working_calibration() - - if not working_calib: + working = singletons.settings_manager.get_current_working_calibration() + if not working: return WorkingCalibrationModel(active=False) - completed, total = working_calib.get_progress() - missing_standards = working_calib.get_missing_standards() - + completed, total = working.get_progress() return WorkingCalibrationModel( active=True, - preset=working_calib.preset.filename, + preset=working.preset.filename, progress=f"{completed}/{total}", - is_complete=working_calib.is_complete(), - completed_standards=[s.value for s in working_calib.standards.keys()], - missing_standards=[s.value for s in missing_standards] + is_complete=working.is_complete(), + completed_standards=[s.value for s in working.standards.keys()], + missing_standards=[s.value for s in working.get_missing_standards()], ) - except Exception as e: - raise HTTPException(status_code=500, detail=str(e)) + except Exception as exc: # noqa: BLE001 + logger.error("Failed to get working calibration") + raise HTTPException(status_code=500, detail=str(exc)) @router.delete("/calibration/remove-standard") -async def remove_calibration_standard(request: RemoveStandardRequest): - """Remove calibration standard from current working set""" +async def remove_calibration_standard(request: RemoveStandardRequest) -> dict[str, Any]: + """Remove calibration standard from current working set.""" try: - # Validate standard try: standard = CalibrationStandard(request.standard) except ValueError: @@ -266,153 +278,140 @@ async def remove_calibration_standard(request: RemoveStandardRequest): singletons.settings_manager.remove_calibration_standard(standard) - # Get current working calibration status - working_calib = singletons.settings_manager.get_current_working_calibration() - progress = working_calib.get_progress() if working_calib else (0, 0) + working = singletons.settings_manager.get_current_working_calibration() + progress = working.get_progress() if working else (0, 0) return { "success": True, "message": f"Removed {standard.value} standard", "progress": f"{progress[0]}/{progress[1]}", - "is_complete": working_calib.is_complete() if working_calib else False + "is_complete": working.is_complete() if working else False, } - except Exception as e: - raise HTTPException(status_code=500, detail=str(e)) + except HTTPException: + raise + except Exception as exc: # noqa: BLE001 + logger.error("Failed to remove calibration standard") + raise HTTPException(status_code=500, detail=str(exc)) @router.get("/calibration/current") -async def get_current_calibration(): - """Get currently selected calibration details""" +async def get_current_calibration() -> dict[str, Any]: + """Get currently selected calibration details.""" try: - current_calib = singletons.settings_manager.get_current_calibration() - - if not current_calib: + current = singletons.settings_manager.get_current_calibration() + if not current: return {"active": False} return { "active": True, - "preset": { - "filename": current_calib.preset.filename, - "mode": current_calib.preset.mode.value - }, - "calibration_name": current_calib.name, - "standards": [s.value for s in current_calib.standards.keys()], - "is_complete": current_calib.is_complete() + "preset": {"filename": current.preset.filename, "mode": current.preset.mode.value}, + "calibration_name": current.name, + "standards": [s.value for s in current.standards.keys()], + "is_complete": current.is_complete(), } - except Exception as e: - raise HTTPException(status_code=500, detail=str(e)) + except Exception as exc: # noqa: BLE001 + logger.error("Failed to get current calibration") + raise HTTPException(status_code=500, detail=str(exc)) @router.get("/calibration/{calibration_name}/standards-plots") -async def get_calibration_standards_plots(calibration_name: str, preset_filename: str = None): - """Get magnitude plots for all standards in a calibration set""" +async def get_calibration_standards_plots( + calibration_name: str, + preset_filename: str | None = None, +) -> dict[str, Any]: + """Get magnitude plots for all standards in a calibration set.""" try: - # Get preset + # Resolve preset (explicit or current) preset = None if preset_filename: presets = singletons.settings_manager.get_available_presets() preset = next((p for p in presets if p.filename == preset_filename), None) - if not preset: + if preset is None: raise HTTPException(status_code=404, detail=f"Preset not found: {preset_filename}") else: preset = singletons.settings_manager.get_current_preset() - if not preset: + if preset is None: raise HTTPException(status_code=400, detail="No current preset selected") - # Get calibration directory + # Resolve calibration directory (uses manager's internal layout) calibration_manager = singletons.settings_manager.calibration_manager - calibration_dir = calibration_manager._get_preset_calibration_dir(preset) / calibration_name + calibration_dir = calibration_manager._get_preset_calibration_dir(preset) / calibration_name # noqa: SLF001 if not calibration_dir.exists(): raise HTTPException(status_code=404, detail=f"Calibration not found: {calibration_name}") - # Generate plots for each standard individual_plots = generate_standards_magnitude_plots(calibration_dir, preset) return { "calibration_name": calibration_name, - "preset": { - "filename": preset.filename, - "mode": preset.mode.value - }, - "individual_plots": individual_plots + "preset": {"filename": preset.filename, "mode": preset.mode.value}, + "individual_plots": individual_plots, } - except Exception as e: - raise HTTPException(status_code=500, detail=str(e)) + except HTTPException: + raise + except Exception as exc: # noqa: BLE001 + logger.error("Failed to build calibration standards plots") + raise HTTPException(status_code=500, detail=str(exc)) @router.get("/working-calibration/standards-plots") -async def get_working_calibration_standards_plots(): - """Get magnitude plots for standards in current working calibration""" +async def get_working_calibration_standards_plots() -> dict[str, Any]: + """Get magnitude plots for standards in the current working calibration.""" try: - working_calib = singletons.settings_manager.get_current_working_calibration() - - if not working_calib: + working = singletons.settings_manager.get_current_working_calibration() + if not working: raise HTTPException(status_code=404, detail="No working calibration active") - - # Check if there are any standards captured - if not working_calib.standards: + if not working.standards: raise HTTPException(status_code=404, detail="No standards captured in working calibration") - # Generate plots directly from in-memory sweep data from vna_system.core.visualization.magnitude_chart import generate_magnitude_plot_from_sweep_data - individual_plots = {} + individual: dict[str, Any] = {} standard_colors = { - 'open': '#2ca02c', # Green - 'short': '#d62728', # Red - 'load': '#ff7f0e', # Orange - 'through': '#1f77b4' # Blue + "open": "#2ca02c", + "short": "#d62728", + "load": "#ff7f0e", + "through": "#1f77b4", } - for standard, sweep_data in working_calib.standards.items(): + for standard, sweep in working.standards.items(): try: - # Generate plot for this standard - plot_config = generate_magnitude_plot_from_sweep_data(sweep_data, working_calib.preset) + fig = generate_magnitude_plot_from_sweep_data(sweep, working.preset) + if "error" not in fig and fig.get("data"): + fig["data"][0]["line"]["color"] = standard_colors.get(standard.value, "#1f77b4") + fig["data"][0]["name"] = f"{standard.value.upper()} Standard" + fig["layout"]["title"] = f"{standard.value.upper()} Standard Magnitude (Working)" - if 'error' not in plot_config: - # Customize color and title for this standard - if plot_config.get('data'): - plot_config['data'][0]['line']['color'] = standard_colors.get(standard.value, '#1f77b4') - plot_config['data'][0]['name'] = f'{standard.value.upper()} Standard' - plot_config['layout']['title'] = f'{standard.value.upper()} Standard Magnitude (Working)' - - # Include raw sweep data for download - plot_config['raw_sweep_data'] = { - 'sweep_number': sweep_data.sweep_number, - 'timestamp': sweep_data.timestamp, - 'total_points': sweep_data.total_points, - 'points': sweep_data.points, # Raw complex data points - 'file_path': None # No file path for working calibration + fig["raw_sweep_data"] = { + "sweep_number": sweep.sweep_number, + "timestamp": sweep.timestamp, + "total_points": sweep.total_points, + "points": sweep.points, + "file_path": None, } - # Add frequency information - plot_config['frequency_info'] = { - 'start_freq': working_calib.preset.start_freq, - 'stop_freq': working_calib.preset.stop_freq, - 'points': working_calib.preset.points, - 'bandwidth': working_calib.preset.bandwidth + fig["frequency_info"] = { + "start_freq": working.preset.start_freq, + "stop_freq": working.preset.stop_freq, + "points": working.preset.points, + "bandwidth": working.preset.bandwidth, } + individual[standard.value] = fig + except Exception as exc: # noqa: BLE001 + individual[standard.value] = {"error": f"Failed to generate plot for {standard.value}: {exc}"} - individual_plots[standard.value] = plot_config - else: - individual_plots[standard.value] = plot_config - - except Exception as e: - individual_plots[standard.value] = {'error': f'Failed to generate plot for {standard.value}: {str(e)}'} - - if not individual_plots: + if not individual: raise HTTPException(status_code=404, detail="No valid plots generated for working calibration") return { "calibration_name": "Working Calibration", - "preset": { - "filename": working_calib.preset.filename, - "mode": working_calib.preset.mode.value - }, - "individual_plots": individual_plots, + "preset": {"filename": working.preset.filename, "mode": working.preset.mode.value}, + "individual_plots": individual, "is_working": True, - "is_complete": working_calib.is_complete() + "is_complete": working.is_complete(), } - except Exception as e: - raise HTTPException(status_code=500, detail=str(e)) \ No newline at end of file + except HTTPException: + raise + except Exception as exc: # noqa: BLE001 + logger.error("Failed to build working calibration standards plots") + raise HTTPException(status_code=500, detail=str(exc)) diff --git a/vna_system/api/main.py b/vna_system/api/main.py deleted file mode 100644 index c045b6f..0000000 --- a/vna_system/api/main.py +++ /dev/null @@ -1,143 +0,0 @@ -from __future__ import annotations - -import json -import logging -import sys -from contextlib import asynccontextmanager -from typing import Any, Dict - -import uvicorn -from fastapi import FastAPI -from fastapi.staticfiles import StaticFiles -from pathlib import Path - -import vna_system.core.singletons as singletons -from vna_system.api.endpoints import health, settings, web_ui, acquisition -from vna_system.api.websockets import processing as ws_processing - - -# Configure logging -logging.basicConfig( - level=logging.INFO, - format='%(asctime)s - %(name)s - %(levelname)s - %(message)s' -) - -# Disable noisy third-party loggers -logging.getLogger('kaleido').setLevel(logging.ERROR) -logging.getLogger('choreographer').setLevel(logging.ERROR) -logging.getLogger('kaleido.kaleido').setLevel(logging.ERROR) -logging.getLogger('choreographer.browsers.chromium').setLevel(logging.ERROR) -logging.getLogger('choreographer.browser_async').setLevel(logging.ERROR) -logging.getLogger('choreographer.utils._tmpfile').setLevel(logging.ERROR) -logging.getLogger('kaleido._kaleido_tab').setLevel(logging.ERROR) - -logger = logging.getLogger(__name__) - - - - -def load_config(config_path: str = "vna_system/api/api_config.json") -> Dict[str, Any]: - """Load API configuration from file.""" - try: - with open(config_path, 'r') as f: - config = json.load(f) - logger.info(f"Loaded API config from {config_path}") - return config - except Exception as e: - logger.error(f"Failed to load config: {e}") - sys.exit(1) - - -@asynccontextmanager -async def lifespan(app: FastAPI): - """FastAPI lifespan events.""" - # Startup - logger.info("Starting VNA API Server...") - - try: - # Load config - config = load_config() - - # Set log level - log_level = config.get("logging", {}).get("level", "INFO") - logging.getLogger().setLevel(getattr(logging, log_level)) - - # Start acquisition - logger.info("Starting data acquisition...") - singletons.vna_data_acquisition_instance.start() - - # Initialize processor system - logger.info("Starting processor system...") - singletons.processor_manager.start_processing() - logger.info(f"Processor system started with processors: {singletons.processor_manager.list_processors()}") - - logger.info("VNA API Server started successfully") - - yield - - except Exception as e: - logger.error(f"Error during startup: {e}") - raise - - # Shutdown - logger.info("Shutting down VNA API Server...") - - if singletons.processor_manager: - singletons.processor_manager.stop_processing() - logger.info("Processor system stopped") - - if singletons.vna_data_acquisition_instance and singletons.vna_data_acquisition_instance._running: - singletons.vna_data_acquisition_instance.stop() - logger.info("Acquisition stopped") - - logger.info("VNA API Server shutdown complete") - - -# Create FastAPI app -app = FastAPI( - title="VNA System API", - description="Real-time VNA data acquisition and processing API", - version="1.0.0", - lifespan=lifespan -) - -# Mount static files for web UI -WEB_UI_DIR = Path(__file__).parent.parent / "web_ui" -STATIC_DIR = WEB_UI_DIR / "static" - -if STATIC_DIR.exists(): - app.mount("/static", StaticFiles(directory=str(STATIC_DIR)), name="static") - logger.info(f"Mounted static files from: {STATIC_DIR}") -else: - logger.warning(f"Static directory not found: {STATIC_DIR}") - -# Include routers -app.include_router(web_ui.router) # Web UI should be first for root path -app.include_router(health.router) -# app.include_router(processing.router) -app.include_router(acquisition.router) -app.include_router(settings.router) -app.include_router(ws_processing.router) - - -def main(): - """Main entry point.""" - config = load_config() - - # Server configuration - server_config = config.get("server", {}) - host = server_config.get("host", "0.0.0.0") - port = server_config.get("port", 8000) - - # Start server - uvicorn.run( - "vna_system.api.main:app", - host=host, - port=port, - log_level="info", - reload=False - ) - - -if __name__ == "__main__": - main() \ No newline at end of file diff --git a/vna_system/calibration/s11_start100_stop8800_points1000_bw1khz/еуыеуые/calibration_info.json b/vna_system/calibration/s11_start100_stop8800_points1000_bw1khz/еуыеуые/calibration_info.json new file mode 100644 index 0000000..3d23dfa --- /dev/null +++ b/vna_system/calibration/s11_start100_stop8800_points1000_bw1khz/еуыеуые/calibration_info.json @@ -0,0 +1,18 @@ +{ + "preset": { + "filename": "s11_start100_stop8800_points1000_bw1khz.bin", + "mode": "s11", + "start_freq": 100000000.0, + "stop_freq": 8800000000.0, + "points": 1000, + "bandwidth": 1000.0 + }, + "calibration_name": "еуыеуые", + "standards": [ + "open", + "load", + "short" + ], + "created_timestamp": "2025-09-26T17:19:50.019248", + "is_complete": true +} \ No newline at end of file diff --git a/vna_system/calibration/s11_start100_stop8800_points1000_bw1khz/еуыеуые/load.json b/vna_system/calibration/s11_start100_stop8800_points1000_bw1khz/еуыеуые/load.json new file mode 100644 index 0000000..9824a6b --- /dev/null +++ b/vna_system/calibration/s11_start100_stop8800_points1000_bw1khz/еуыеуые/load.json @@ -0,0 +1,4007 @@ +{ + "sweep_number": 12, + "timestamp": 1758896376.33808, + "points": [ + [ + -2.672412872314453, + 0.44942471385002136 + ], + [ + -2.665140151977539, + 0.5138063430786133 + ], + [ + -2.6549153327941895, + 0.5751491785049438 + ], + [ + -2.6450717449188232, + 0.6348942518234253 + ], + [ + -2.633969783782959, + 0.6958639621734619 + ], + [ + -3.4072988033294678, + 0.9295109510421753 + ], + [ + -3.3898448944091797, + 1.0027321577072144 + ], + [ + -3.37446665763855, + 1.0809111595153809 + ], + [ + -3.351916790008545, + 1.1594840288162231 + ], + [ + -3.3281760215759277, + 1.2352432012557983 + ], + [ + -3.3081307411193848, + 1.3111613988876343 + ], + [ + -3.285163164138794, + 1.3833891153335571 + ], + [ + -3.25860333442688, + 1.4568874835968018 + ], + [ + -3.233642101287842, + 1.534937858581543 + ], + [ + -3.211621046066284, + 1.6109647750854492 + ], + [ + -3.1775434017181396, + 1.6917634010314941 + ], + [ + -3.147634744644165, + 1.7618643045425415 + ], + [ + -3.1176207065582275, + 1.8333007097244263 + ], + [ + -3.0827629566192627, + 1.9087711572647095 + ], + [ + -3.040661096572876, + 1.9821110963821411 + ], + [ + -3.00249981880188, + 2.0553479194641113 + ], + [ + -2.971890687942505, + 2.124830961227417 + ], + [ + -2.927703619003296, + 2.2003092765808105 + ], + [ + -2.885180950164795, + 2.274610996246338 + ], + [ + -2.8362882137298584, + 2.3481907844543457 + ], + [ + -2.798276662826538, + 2.413817882537842 + ], + [ + -2.755201578140259, + 2.4848906993865967 + ], + [ + -2.707097291946411, + 2.5589077472686768 + ], + [ + -2.653110980987549, + 2.6352760791778564 + ], + [ + -2.604438066482544, + 2.7032837867736816 + ], + [ + -2.5570480823516846, + 2.7709240913391113 + ], + [ + -2.508699893951416, + 2.835637092590332 + ], + [ + -2.452873468399048, + 2.907918691635132 + ], + [ + -2.395895004272461, + 2.9703681468963623 + ], + [ + -2.338472843170166, + 3.032949686050415 + ], + [ + -2.267284631729126, + 3.100571870803833 + ], + [ + -2.2003400325775146, + 3.165201425552368 + ], + [ + -2.130265712738037, + 3.233243703842163 + ], + [ + -2.0604138374328613, + 3.2860169410705566 + ], + [ + -1.9926751852035522, + 3.354316234588623 + ], + [ + -1.9244656562805176, + 3.414196014404297 + ], + [ + -1.8528647422790527, + 3.476970672607422 + ], + [ + -1.775537133216858, + 3.531400442123413 + ], + [ + -1.698214054107666, + 3.5915467739105225 + ], + [ + -1.6211034059524536, + 3.649618148803711 + ], + [ + -1.535129427909851, + 3.7091827392578125 + ], + [ + -1.449792504310608, + 3.757904052734375 + ], + [ + -1.3677159547805786, + 3.814706563949585 + ], + [ + -1.2757837772369385, + 3.861318349838257 + ], + [ + -1.1859837770462036, + 3.9188220500946045 + ], + [ + -1.092786431312561, + 3.9637033939361572 + ], + [ + -1.0051831007003784, + 4.010341644287109 + ], + [ + -0.89798903465271, + 4.0582275390625 + ], + [ + -0.8046980500221252, + 4.096992492675781 + ], + [ + -0.7105773091316223, + 4.143339157104492 + ], + [ + -0.608837902545929, + 4.182793617248535 + ], + [ + -0.5078397989273071, + 4.2201385498046875 + ], + [ + -0.40349194407463074, + 4.259609699249268 + ], + [ + -0.29068517684936523, + 4.292464733123779 + ], + [ + -0.17644040286540985, + 4.321564674377441 + ], + [ + -0.06537165492773056, + 4.347588539123535 + ], + [ + 0.05515637621283531, + 4.369880676269531 + ], + [ + 0.17611534893512726, + 4.379391193389893 + ], + [ + 0.29344743490219116, + 4.395306587219238 + ], + [ + 0.4191119074821472, + 4.413814544677734 + ], + [ + 0.5425008535385132, + 4.418741226196289 + ], + [ + 0.6587525606155396, + 4.433247089385986 + ], + [ + 0.7864275574684143, + 4.443286895751953 + ], + [ + 0.919674813747406, + 4.438477039337158 + ], + [ + 1.0481877326965332, + 4.434279918670654 + ], + [ + 1.1820579767227173, + 4.434950828552246 + ], + [ + 1.325274109840393, + 4.420563220977783 + ], + [ + 1.4506641626358032, + 4.406406879425049 + ], + [ + 1.5851094722747803, + 4.379190921783447 + ], + [ + 1.724495530128479, + 4.353355884552002 + ], + [ + 1.862963080406189, + 4.324624538421631 + ], + [ + 1.9926867485046387, + 4.288524150848389 + ], + [ + 2.12930965423584, + 4.251039505004883 + ], + [ + 2.2634921073913574, + 4.208732604980469 + ], + [ + 2.396778106689453, + 4.160767078399658 + ], + [ + 2.5294203758239746, + 4.109339714050293 + ], + [ + 2.655141592025757, + 4.0571208000183105 + ], + [ + 2.776848077774048, + 3.990960121154785 + ], + [ + 2.9058425426483154, + 3.925051212310791 + ], + [ + 3.0261900424957275, + 3.8497705459594727 + ], + [ + 3.1437149047851562, + 3.785703659057617 + ], + [ + 3.267310380935669, + 3.7046878337860107 + ], + [ + 3.3856406211853027, + 3.620727062225342 + ], + [ + 3.4874134063720703, + 3.529554843902588 + ], + [ + 3.609124183654785, + 3.4315907955169678 + ], + [ + 3.7178878784179688, + 3.3342206478118896 + ], + [ + 3.816277503967285, + 3.230572462081909 + ], + [ + 3.9382593631744385, + 3.1181538105010986 + ], + [ + 4.044654369354248, + 3.0044479370117188 + ], + [ + 4.155239582061768, + 2.877293825149536 + ], + [ + 4.251413822174072, + 2.7394824028015137 + ], + [ + 4.3388800621032715, + 2.622138261795044 + ], + [ + 4.439864158630371, + 2.4807515144348145 + ], + [ + 4.521735668182373, + 2.3513152599334717 + ], + [ + 4.593135833740234, + 2.204052686691284 + ], + [ + 4.6642985343933105, + 2.053229808807373 + ], + [ + 4.733786106109619, + 1.9070507287979126 + ], + [ + 4.784759044647217, + 1.759527564048767 + ], + [ + 4.843936443328857, + 1.59331214427948 + ], + [ + 4.898230075836182, + 1.4377585649490356 + ], + [ + 4.940882682800293, + 1.2707183361053467 + ], + [ + 4.975884437561035, + 1.1043983697891235 + ], + [ + 5.014648914337158, + 0.941770076751709 + ], + [ + 5.037928581237793, + 0.7779365181922913 + ], + [ + 5.056427001953125, + 0.6137372255325317 + ], + [ + 5.071547031402588, + 0.4381324350833893 + ], + [ + 5.090205669403076, + 0.2855481207370758 + ], + [ + 5.080108642578125, + 0.1063629686832428 + ], + [ + 5.070316314697266, + -0.05431445315480232 + ], + [ + 5.0558671951293945, + -0.207890123128891 + ], + [ + 5.029526233673096, + -0.3491782248020172 + ], + [ + 4.995769023895264, + -0.49604901671409607 + ], + [ + 4.974265098571777, + -0.6504014134407043 + ], + [ + 4.929023265838623, + -0.7893060445785522 + ], + [ + 4.868687629699707, + -0.9384287595748901 + ], + [ + 4.813848972320557, + -1.0797019004821777 + ], + [ + 4.744615077972412, + -1.2186343669891357 + ], + [ + 4.676766872406006, + -1.3487859964370728 + ], + [ + 4.593881130218506, + -1.4832743406295776 + ], + [ + 4.514934539794922, + -1.6201449632644653 + ], + [ + 4.430294513702393, + -1.7410017251968384 + ], + [ + 4.3437933921813965, + -1.8810490369796753 + ], + [ + 4.244453430175781, + -2.0108401775360107 + ], + [ + 4.148582935333252, + -2.138638496398926 + ], + [ + 4.056083679199219, + -2.270153522491455 + ], + [ + 3.9542436599731445, + -2.3845231533050537 + ], + [ + 3.853040933609009, + -2.5266377925872803 + ], + [ + 3.7614054679870605, + -2.6316466331481934 + ], + [ + 3.6557321548461914, + -2.7465944290161133 + ], + [ + 3.567324638366699, + -2.8408336639404297 + ], + [ + 3.455432415008545, + -2.930814027786255 + ], + [ + 3.3636744022369385, + -3.018575429916382 + ], + [ + 3.2565643787384033, + -3.084285259246826 + ], + [ + 3.161194086074829, + -3.156050682067871 + ], + [ + 3.0584988594055176, + -3.1846697330474854 + ], + [ + 2.960036516189575, + -3.227187395095825 + ], + [ + 2.8606131076812744, + -3.2711758613586426 + ], + [ + 2.7450449466705322, + -3.294323205947876 + ], + [ + 2.633589029312134, + -3.304173707962036 + ], + [ + 2.532041311264038, + -3.3372957706451416 + ], + [ + 2.416548728942871, + -3.3474135398864746 + ], + [ + 2.294229745864868, + -3.3516571521759033 + ], + [ + 2.2010910511016846, + -3.375875949859619 + ], + [ + 2.0861196517944336, + -3.367797374725342 + ], + [ + 1.9566923379898071, + -3.3809123039245605 + ], + [ + 1.862547755241394, + -3.3903965950012207 + ], + [ + 1.7353124618530273, + -3.4044573307037354 + ], + [ + 1.6217120885849, + -3.418888807296753 + ], + [ + 1.4697421789169312, + -3.6198036670684814 + ], + [ + 1.3651553392410278, + -3.635737180709839 + ], + [ + 1.2654904127120972, + -3.6339120864868164 + ], + [ + 1.1774555444717407, + -3.6060092449188232 + ], + [ + 1.0734139680862427, + -3.613830089569092 + ], + [ + 0.979674220085144, + -3.6030185222625732 + ], + [ + 0.8761454820632935, + -3.5985333919525146 + ], + [ + 0.7879981994628906, + -3.5754876136779785 + ], + [ + 0.6847778558731079, + -3.5718307495117188 + ], + [ + 0.6000930666923523, + -3.5531673431396484 + ], + [ + 0.4990699589252472, + -3.5412752628326416 + ], + [ + 0.4146011471748352, + -3.5257134437561035 + ], + [ + 0.32755935192108154, + -3.500272512435913 + ], + [ + 0.24657753109931946, + -3.4741697311401367 + ], + [ + 0.16803881525993347, + -3.4575114250183105 + ], + [ + 0.09345711022615433, + -3.4291741847991943 + ], + [ + 0.0022887317463755608, + -3.4094700813293457 + ], + [ + -0.057056330144405365, + -3.3856565952301025 + ], + [ + -0.1329173743724823, + -3.3531155586242676 + ], + [ + -0.2088886946439743, + -3.32807993888855 + ], + [ + -0.26992514729499817, + -3.2984018325805664 + ], + [ + -0.34073227643966675, + -3.275977373123169 + ], + [ + -0.4053002893924713, + -3.2447474002838135 + ], + [ + -0.4613828957080841, + -3.214855909347534 + ], + [ + -0.5255600214004517, + -3.1891062259674072 + ], + [ + -0.5953307151794434, + -3.1630845069885254 + ], + [ + -0.6431891322135925, + -3.128786087036133 + ], + [ + -0.7025863528251648, + -3.0989537239074707 + ], + [ + -0.7591955661773682, + -3.067817211151123 + ], + [ + -0.8138955235481262, + -3.02962327003479 + ], + [ + -0.8665670156478882, + -2.993196487426758 + ], + [ + -0.9244861006736755, + -2.965233564376831 + ], + [ + -0.978937029838562, + -2.9244863986968994 + ], + [ + -1.0342904329299927, + -2.8943440914154053 + ], + [ + -1.0855157375335693, + -2.856853485107422 + ], + [ + -1.1341140270233154, + -2.8258163928985596 + ], + [ + -1.1844428777694702, + -2.7875776290893555 + ], + [ + -1.23549222946167, + -2.7584996223449707 + ], + [ + -1.282921314239502, + -2.7211763858795166 + ], + [ + -1.3237563371658325, + -2.682608127593994 + ], + [ + -1.3692548274993896, + -2.6461188793182373 + ], + [ + -1.4059221744537354, + -2.6106350421905518 + ], + [ + -1.4455393552780151, + -2.570465087890625 + ], + [ + -1.4918361902236938, + -2.5273120403289795 + ], + [ + -1.5309549570083618, + -2.48526668548584 + ], + [ + -1.5699880123138428, + -2.443796157836914 + ], + [ + -1.6006845235824585, + -2.3941171169281006 + ], + [ + -1.6119121313095093, + -2.328874111175537 + ], + [ + -1.6615164279937744, + -2.2707836627960205 + ], + [ + -1.7099251747131348, + -2.228250741958618 + ], + [ + -1.7486892938613892, + -2.1776859760284424 + ], + [ + -1.798826813697815, + -2.120507001876831 + ], + [ + -1.8356176614761353, + -2.075648784637451 + ], + [ + -1.8820902109146118, + -2.019679546356201 + ], + [ + -1.9287985563278198, + -1.9699498414993286 + ], + [ + -1.9618436098098755, + -1.9203039407730103 + ], + [ + -2.006582260131836, + -1.866355538368225 + ], + [ + -2.0462899208068848, + -1.8188000917434692 + ], + [ + -2.0794010162353516, + -1.7730387449264526 + ], + [ + -2.114780902862549, + -1.716410517692566 + ], + [ + -2.1508870124816895, + -1.661577582359314 + ], + [ + -2.177006244659424, + -1.618638038635254 + ], + [ + -2.2129456996917725, + -1.5621641874313354 + ], + [ + -2.239290475845337, + -1.512711763381958 + ], + [ + -2.258457899093628, + -1.470788836479187 + ], + [ + -2.2874667644500732, + -1.410704493522644 + ], + [ + -2.3052868843078613, + -1.361812710762024 + ], + [ + -2.321857213973999, + -1.3169584274291992 + ], + [ + -2.3434555530548096, + -1.266066551208496 + ], + [ + -2.3562746047973633, + -1.2173861265182495 + ], + [ + -2.3685810565948486, + -1.1712769269943237 + ], + [ + -2.376680850982666, + -1.1234360933303833 + ], + [ + -2.3945863246917725, + -1.0710558891296387 + ], + [ + -2.4027750492095947, + -1.0249954462051392 + ], + [ + -2.409137487411499, + -0.9744507670402527 + ], + [ + -2.4202983379364014, + -0.92059725522995 + ], + [ + -2.427290678024292, + -0.8681397438049316 + ], + [ + -2.43591046333313, + -0.8146946430206299 + ], + [ + -2.4493472576141357, + -0.755174458026886 + ], + [ + -2.4590554237365723, + -0.7009482979774475 + ], + [ + -2.4691128730773926, + -0.6405749320983887 + ], + [ + -2.4789717197418213, + -0.5809928774833679 + ], + [ + -2.491446018218994, + -0.5165635347366333 + ], + [ + -2.5009407997131348, + -0.45797818899154663 + ], + [ + -2.5161654949188232, + -0.39766326546669006 + ], + [ + -2.522209405899048, + -0.3381291627883911 + ], + [ + -2.532291889190674, + -0.27920281887054443 + ], + [ + -2.5393848419189453, + -0.21943187713623047 + ], + [ + -2.5431716442108154, + -0.1623566746711731 + ], + [ + -2.53035831451416, + -0.10841787606477737 + ], + [ + -2.5240185260772705, + -0.054554760456085205 + ], + [ + -2.5196309089660645, + 0.0005839953082613647 + ], + [ + -2.5186665058135986, + 0.05507070943713188 + ], + [ + -2.5115649700164795, + 0.11332162469625473 + ], + [ + -2.5050342082977295, + 0.16904401779174805 + ], + [ + -2.4960529804229736, + 0.22937336564064026 + ], + [ + -2.493055820465088, + 0.2873798608779907 + ], + [ + -2.4837512969970703, + 0.33945825695991516 + ], + [ + -2.4726574420928955, + 0.3984595239162445 + ], + [ + -2.463252305984497, + 0.45446890592575073 + ], + [ + -2.456223964691162, + 0.5183476805686951 + ], + [ + -2.4486215114593506, + 0.5806308388710022 + ], + [ + -2.4322755336761475, + 0.6317009925842285 + ], + [ + -2.418165445327759, + 0.6931613087654114 + ], + [ + -2.4122791290283203, + 0.7552086710929871 + ], + [ + -2.404672145843506, + 0.8158265948295593 + ], + [ + -2.3955321311950684, + 0.8753899335861206 + ], + [ + -2.374551773071289, + 0.9307690262794495 + ], + [ + -2.3685660362243652, + 0.9893108606338501 + ], + [ + -2.3576600551605225, + 1.0486433506011963 + ], + [ + -2.3484387397766113, + 1.104414463043213 + ], + [ + -2.3445301055908203, + 1.1570032835006714 + ], + [ + -2.3328933715820312, + 1.2014226913452148 + ], + [ + -2.3077712059020996, + 1.263383388519287 + ], + [ + -2.2995731830596924, + 1.313030481338501 + ], + [ + -2.292541742324829, + 1.353027105331421 + ], + [ + -2.276519298553467, + 1.3915609121322632 + ], + [ + -2.2608678340911865, + 1.4306423664093018 + ], + [ + -2.2396578788757324, + 1.4902138710021973 + ], + [ + -2.2214953899383545, + 1.5249607563018799 + ], + [ + -2.198178291320801, + 1.560704231262207 + ], + [ + -2.1727616786956787, + 1.5866310596466064 + ], + [ + -2.140048027038574, + 1.6220717430114746 + ], + [ + -2.1120855808258057, + 1.6724121570587158 + ], + [ + -2.0751969814300537, + 1.7093777656555176 + ], + [ + -2.0301389694213867, + 1.7423040866851807 + ], + [ + -1.9805330038070679, + 1.779166340827942 + ], + [ + -1.9263598918914795, + 1.8140712976455688 + ], + [ + -1.869299054145813, + 1.859695553779602 + ], + [ + -1.8313579559326172, + 1.9058629274368286 + ], + [ + -1.771677017211914, + 1.9492803812026978 + ], + [ + -1.7108889818191528, + 1.9945214986801147 + ], + [ + -1.6472153663635254, + 2.0433297157287598 + ], + [ + -1.5802081823349, + 2.1042966842651367 + ], + [ + -1.5330379009246826, + 2.1566061973571777 + ], + [ + -1.4707579612731934, + 2.2150795459747314 + ], + [ + -1.4062886238098145, + 2.2799277305603027 + ], + [ + -1.3448680639266968, + 2.3366637229919434 + ], + [ + -1.2860314846038818, + 2.4060957431793213 + ], + [ + -1.235167384147644, + 2.4832816123962402 + ], + [ + -1.1883561611175537, + 2.5211234092712402 + ], + [ + -1.1233900785446167, + 2.590672731399536 + ], + [ + -1.0729283094406128, + 2.6388049125671387 + ], + [ + -1.0146491527557373, + 2.699958086013794 + ], + [ + -0.9592975974082947, + 2.7593612670898438 + ], + [ + -0.9109231233596802, + 2.8192312717437744 + ], + [ + -0.8413457274436951, + 2.858060359954834 + ], + [ + -0.7893630266189575, + 2.9040117263793945 + ], + [ + -0.7232140302658081, + 2.950082540512085 + ], + [ + -0.66054767370224, + 2.995304584503174 + ], + [ + -0.6067798137664795, + 3.043498992919922 + ], + [ + -0.5319972038269043, + 3.072779655456543 + ], + [ + -0.45669662952423096, + 3.1054911613464355 + ], + [ + -0.3879760801792145, + 3.1452856063842773 + ], + [ + -0.3163839280605316, + 3.178647756576538 + ], + [ + -0.23881268501281738, + 3.2143428325653076 + ], + [ + -0.16235657036304474, + 3.242783546447754 + ], + [ + -0.09107659012079239, + 3.2678940296173096 + ], + [ + -0.0015662735095247626, + 3.2931182384490967 + ], + [ + 0.07648210972547531, + 3.3010752201080322 + ], + [ + 0.15851885080337524, + 3.3261008262634277 + ], + [ + 0.2328532338142395, + 3.3402082920074463 + ], + [ + 0.30398327112197876, + 3.3425846099853516 + ], + [ + 0.39275306463241577, + 3.3504340648651123 + ], + [ + 0.5901356339454651, + 3.2232682704925537 + ], + [ + 0.7015319466590881, + 3.2192459106445312 + ], + [ + 0.7880183458328247, + 3.217802047729492 + ], + [ + 0.8911440968513489, + 3.2070109844207764 + ], + [ + 0.9743718504905701, + 3.2074365615844727 + ], + [ + 1.0823267698287964, + 3.199828624725342 + ], + [ + 1.174919843673706, + 3.179307460784912 + ], + [ + 1.2711454629898071, + 3.1628990173339844 + ], + [ + 1.377198576927185, + 3.1466429233551025 + ], + [ + 1.4639960527420044, + 3.1196913719177246 + ], + [ + 1.5541223287582397, + 3.104910135269165 + ], + [ + 1.6455168724060059, + 3.073697805404663 + ], + [ + 1.757059097290039, + 3.033984422683716 + ], + [ + 1.8448561429977417, + 3.0031070709228516 + ], + [ + 1.922029733657837, + 2.9642581939697266 + ], + [ + 2.003798246383667, + 2.911041259765625 + ], + [ + 2.073415756225586, + 2.855860948562622 + ], + [ + 2.1812610626220703, + 2.802154541015625 + ], + [ + 2.2501232624053955, + 2.742271900177002 + ], + [ + 2.3271467685699463, + 2.6747283935546875 + ], + [ + 2.398401975631714, + 2.6032512187957764 + ], + [ + 2.4678356647491455, + 2.5214154720306396 + ], + [ + 2.548351526260376, + 2.4564192295074463 + ], + [ + 2.61041522026062, + 2.373455762863159 + ], + [ + 2.6830625534057617, + 2.28041934967041 + ], + [ + 2.747586488723755, + 2.1921510696411133 + ], + [ + 2.8138184547424316, + 2.095742702484131 + ], + [ + 2.876384735107422, + 1.9926830530166626 + ], + [ + 2.932926654815674, + 1.9086298942565918 + ], + [ + 2.996795654296875, + 1.805037260055542 + ], + [ + 3.0548367500305176, + 1.6983861923217773 + ], + [ + 3.109464406967163, + 1.5877350568771362 + ], + [ + 3.1727302074432373, + 1.481256127357483 + ], + [ + 3.211042881011963, + 1.3843567371368408 + ], + [ + 3.2633306980133057, + 1.2765963077545166 + ], + [ + 3.308006525039673, + 1.1727060079574585 + ], + [ + 3.3526527881622314, + 1.069777488708496 + ], + [ + 3.3911781311035156, + 0.9681896567344666 + ], + [ + 3.424661636352539, + 0.8653106689453125 + ], + [ + 3.4479520320892334, + 0.7716711163520813 + ], + [ + 3.4718735218048096, + 0.6715928316116333 + ], + [ + 3.4897162914276123, + 0.5798554420471191 + ], + [ + 3.506943941116333, + 0.49197688698768616 + ], + [ + 3.5154800415039062, + 0.3985064923763275 + ], + [ + 3.5168020725250244, + 0.30777284502983093 + ], + [ + 3.513289451599121, + 0.22126562893390656 + ], + [ + 3.505326747894287, + 0.13551683723926544 + ], + [ + 3.493556499481201, + 0.043961625546216965 + ], + [ + 3.477113962173462, + -0.04401038959622383 + ], + [ + 3.4577229022979736, + -0.1369541734457016 + ], + [ + 3.4318063259124756, + -0.23035143315792084 + ], + [ + 3.408052921295166, + -0.33046427369117737 + ], + [ + 3.3775947093963623, + -0.41722720861434937 + ], + [ + 3.348123788833618, + -0.5172374844551086 + ], + [ + 3.320546865463257, + -0.6228078007698059 + ], + [ + 3.2952959537506104, + -0.7236150503158569 + ], + [ + 3.281160593032837, + -0.8302838206291199 + ], + [ + 3.271047830581665, + -0.9291787147521973 + ], + [ + 3.2429566383361816, + -1.0215719938278198 + ], + [ + 3.2416298389434814, + -1.1140131950378418 + ], + [ + 3.2357163429260254, + -1.1951252222061157 + ], + [ + 3.229006767272949, + -1.266624093055725 + ], + [ + 3.2191643714904785, + -1.3270381689071655 + ], + [ + 3.2097315788269043, + -1.3761764764785767 + ], + [ + 3.1899614334106445, + -1.4148547649383545 + ], + [ + 3.1712594032287598, + -1.4739134311676025 + ], + [ + 3.1417198181152344, + -1.5053458213806152 + ], + [ + 3.10054874420166, + -1.535404086112976 + ], + [ + 3.0659308433532715, + -1.5642060041427612 + ], + [ + 3.0132031440734863, + -1.5909934043884277 + ], + [ + 2.9598066806793213, + -1.6177518367767334 + ], + [ + 2.8843512535095215, + -1.6470000743865967 + ], + [ + 2.834927558898926, + -1.6705498695373535 + ], + [ + 2.7684693336486816, + -1.6994338035583496 + ], + [ + 2.7022452354431152, + -1.7357183694839478 + ], + [ + 2.6399872303009033, + -1.7731074094772339 + ], + [ + 2.5782599449157715, + -1.8069785833358765 + ], + [ + 2.497802972793579, + -1.8426717519760132 + ], + [ + 2.4158599376678467, + -1.8773146867752075 + ], + [ + 2.3536558151245117, + -1.8955771923065186 + ], + [ + 2.2751362323760986, + -1.9319634437561035 + ], + [ + 2.1982662677764893, + -1.9802165031433105 + ], + [ + 2.121298313140869, + -2.0171074867248535 + ], + [ + 2.0398170948028564, + -2.0653862953186035 + ], + [ + 1.965449333190918, + -2.1093950271606445 + ], + [ + 1.8994574546813965, + -2.1758220195770264 + ], + [ + 1.8282287120819092, + -2.2104318141937256 + ], + [ + 1.7667295932769775, + -2.2617740631103516 + ], + [ + 1.7051221132278442, + -2.3088021278381348 + ], + [ + 1.6403290033340454, + -2.3601555824279785 + ], + [ + 1.5714662075042725, + -2.405578136444092 + ], + [ + 1.525888204574585, + -2.449364423751831 + ], + [ + 1.4739958047866821, + -2.5005486011505127 + ], + [ + 1.510084867477417, + -2.4275670051574707 + ], + [ + 1.452736735343933, + -2.456312656402588 + ], + [ + 1.3698203563690186, + -2.4733352661132812 + ], + [ + 1.3051291704177856, + -2.5106418132781982 + ], + [ + 1.233035922050476, + -2.5337891578674316 + ], + [ + 1.1664057970046997, + -2.560462713241577 + ], + [ + 1.1379961967468262, + -2.581568479537964 + ], + [ + 1.0613441467285156, + -2.5792932510375977 + ], + [ + 0.9942167401313782, + -2.6124143600463867 + ], + [ + 0.9359543919563293, + -2.640059471130371 + ], + [ + 0.8627748489379883, + -2.671437978744507 + ], + [ + 0.808817982673645, + -2.6853275299072266 + ], + [ + 0.7592597007751465, + -2.670433282852173 + ], + [ + 0.6895032525062561, + -2.6909897327423096 + ], + [ + 0.6419966220855713, + -2.703969955444336 + ], + [ + 0.5750437378883362, + -2.72550368309021 + ], + [ + 0.5192556381225586, + -2.7417449951171875 + ], + [ + 0.4641278386116028, + -2.764291763305664 + ], + [ + 0.40754878520965576, + -2.731346845626831 + ], + [ + 0.34376391768455505, + -2.7541184425354004 + ], + [ + 0.2953405976295471, + -2.759856700897217 + ], + [ + 0.2482239305973053, + -2.771167516708374 + ], + [ + 0.19947369396686554, + -2.779921054840088 + ], + [ + 0.16243195533752441, + -2.786778211593628 + ], + [ + 0.0934247225522995, + -2.7600200176239014 + ], + [ + 0.03526142239570618, + -2.7666730880737305 + ], + [ + -0.007865983992815018, + -2.7630529403686523 + ], + [ + -0.05507233738899231, + -2.7645680904388428 + ], + [ + -0.08994065970182419, + -2.765259027481079 + ], + [ + -0.13178949058055878, + -2.7686474323272705 + ], + [ + -0.1968163549900055, + -2.742597818374634 + ], + [ + -0.24626262485980988, + -2.7446844577789307 + ], + [ + -0.2884788513183594, + -2.738398790359497 + ], + [ + -0.3255704939365387, + -2.7313430309295654 + ], + [ + -0.3582229018211365, + -2.7168257236480713 + ], + [ + -0.3956122398376465, + -2.706683874130249 + ], + [ + -0.43911507725715637, + -2.6870875358581543 + ], + [ + -0.5026808977127075, + -2.679696798324585 + ], + [ + -0.5519200563430786, + -2.6719422340393066 + ], + [ + -0.5743615031242371, + -2.655754327774048 + ], + [ + -0.6148557066917419, + -2.621581554412842 + ], + [ + -0.6489402651786804, + -2.606370687484741 + ], + [ + -0.6866077780723572, + -2.5727932453155518 + ], + [ + -0.7350509762763977, + -2.5579111576080322 + ], + [ + -0.7733362317085266, + -2.559326171875 + ], + [ + -0.8110785484313965, + -2.5323524475097656 + ], + [ + -0.8458943963050842, + -2.5049662590026855 + ], + [ + -0.8852884769439697, + -2.4748716354370117 + ], + [ + -0.9210420846939087, + -2.436002731323242 + ], + [ + -0.9677043557167053, + -2.4143435955047607 + ], + [ + -0.9985753297805786, + -2.398808717727661 + ], + [ + -1.0431288480758667, + -2.3674793243408203 + ], + [ + -1.0734139680862427, + -2.339211940765381 + ], + [ + -1.1192092895507812, + -2.289523124694824 + ], + [ + -1.1682292222976685, + -2.2517383098602295 + ], + [ + -1.2169394493103027, + -2.2200450897216797 + ], + [ + -1.26090407371521, + -2.1744117736816406 + ], + [ + -1.2952524423599243, + -2.164081573486328 + ], + [ + -1.3416997194290161, + -2.1214489936828613 + ], + [ + -1.3893687725067139, + -2.0872302055358887 + ], + [ + -1.449247121810913, + -2.054952621459961 + ], + [ + -1.5069382190704346, + -2.022207736968994 + ], + [ + -1.558609962463379, + -1.9946846961975098 + ], + [ + -1.6166878938674927, + -1.9706171751022339 + ], + [ + -1.675876498222351, + -1.9509732723236084 + ], + [ + -1.6974897384643555, + -1.9095323085784912 + ], + [ + -1.7507046461105347, + -1.886737585067749 + ], + [ + -1.7968331575393677, + -1.8695569038391113 + ], + [ + -1.846699833869934, + -1.851417064666748 + ], + [ + -1.8882246017456055, + -1.8381776809692383 + ], + [ + -1.9294058084487915, + -1.8208487033843994 + ], + [ + -1.959072470664978, + -1.8054554462432861 + ], + [ + -1.9954005479812622, + -1.7631641626358032 + ], + [ + -2.035001277923584, + -1.7467588186264038 + ], + [ + -2.0675790309906006, + -1.7271302938461304 + ], + [ + -2.0923659801483154, + -1.7105809450149536 + ], + [ + -2.1157710552215576, + -1.6959792375564575 + ], + [ + -2.1374080181121826, + -1.6704037189483643 + ], + [ + -2.153512716293335, + -1.6433185338974 + ], + [ + -2.165675401687622, + -1.6169507503509521 + ], + [ + -2.205427646636963, + -1.578442931175232 + ], + [ + -2.2238967418670654, + -1.5464286804199219 + ], + [ + -2.236910343170166, + -1.5166398286819458 + ], + [ + -2.2520265579223633, + -1.475869059562683 + ], + [ + -2.780294895172119, + -1.921571969985962 + ], + [ + -2.814448833465576, + -1.872692584991455 + ], + [ + -2.8520143032073975, + -1.8159303665161133 + ], + [ + -2.8915493488311768, + -1.758445382118225 + ], + [ + -2.9299585819244385, + -1.707815170288086 + ], + [ + -2.9612579345703125, + -1.6501107215881348 + ], + [ + -2.9927852153778076, + -1.5900700092315674 + ], + [ + -3.0286331176757812, + -1.5370652675628662 + ], + [ + -3.0627458095550537, + -1.46896231174469 + ], + [ + -3.093890428543091, + -1.4011098146438599 + ], + [ + -3.1280016899108887, + -1.33651602268219 + ], + [ + -3.1599416732788086, + -1.2726335525512695 + ], + [ + -1.93692946434021, + -0.688139021396637 + ], + [ + -1.951135516166687, + -0.6450985074043274 + ], + [ + -1.9691035747528076, + -0.600355327129364 + ], + [ + -1.9830117225646973, + -0.5563389658927917 + ], + [ + -1.996295690536499, + -0.5098227262496948 + ], + [ + -2.008678436279297, + -0.4671855866909027 + ], + [ + -2.018731117248535, + -0.41933777928352356 + ], + [ + -2.029167652130127, + -0.3717145025730133 + ], + [ + -2.0384998321533203, + -0.3248966932296753 + ], + [ + -2.0453851222991943, + -0.27763110399246216 + ], + [ + -2.0543158054351807, + -0.2302936464548111 + ], + [ + -2.06024432182312, + -0.181417778134346 + ], + [ + -2.0660252571105957, + -0.13402564823627472 + ], + [ + -2.0701818466186523, + -0.08482204377651215 + ], + [ + -2.073856830596924, + -0.036377981305122375 + ], + [ + -2.0757954120635986, + 0.013498243875801563 + ], + [ + -2.078766345977783, + 0.06260792165994644 + ], + [ + -2.079815626144409, + 0.11445926874876022 + ], + [ + -2.078620433807373, + 0.16460341215133667 + ], + [ + -2.0784027576446533, + 0.2157268226146698 + ], + [ + -2.0738449096679688, + 0.2678883373737335 + ], + [ + -2.07157564163208, + 0.3169556260108948 + ], + [ + -2.066638231277466, + 0.369326114654541 + ], + [ + -2.0593175888061523, + 0.4226098358631134 + ], + [ + -2.0466578006744385, + 0.47601255774497986 + ], + [ + -2.0334091186523438, + 0.5240135192871094 + ], + [ + -2.02695369720459, + 0.5774964094161987 + ], + [ + -2.014389991760254, + 0.628721296787262 + ], + [ + -1.9990944862365723, + 0.684299111366272 + ], + [ + -1.9853901863098145, + 0.7344710826873779 + ], + [ + -1.9689271450042725, + 0.7822098135948181 + ], + [ + -1.945559024810791, + 0.834809422492981 + ], + [ + -1.926823377609253, + 0.8859231472015381 + ], + [ + -1.9049760103225708, + 0.9356061816215515 + ], + [ + -1.881211757659912, + 0.9852762222290039 + ], + [ + -1.8544278144836426, + 1.0322664976119995 + ], + [ + -1.822708010673523, + 1.0785863399505615 + ], + [ + -1.7999520301818848, + 1.1303937435150146 + ], + [ + -1.7705137729644775, + 1.1707130670547485 + ], + [ + -1.7396730184555054, + 1.2202078104019165 + ], + [ + -1.714820384979248, + 1.2667555809020996 + ], + [ + -1.6777173280715942, + 1.3068474531173706 + ], + [ + -1.6406227350234985, + 1.3570568561553955 + ], + [ + -1.605550765991211, + 1.3950676918029785 + ], + [ + -1.5687322616577148, + 1.4354667663574219 + ], + [ + -1.530615210533142, + 1.4838550090789795 + ], + [ + -1.4922969341278076, + 1.5142518281936646 + ], + [ + -1.4502902030944824, + 1.5600910186767578 + ], + [ + -1.4131070375442505, + 1.595806360244751 + ], + [ + -1.3702269792556763, + 1.627675175666809 + ], + [ + -1.3253364562988281, + 1.6643174886703491 + ], + [ + -1.2857098579406738, + 1.6992449760437012 + ], + [ + -1.2352697849273682, + 1.734252691268921 + ], + [ + -1.1980395317077637, + 1.755337119102478 + ], + [ + -1.153885841369629, + 1.7906246185302734 + ], + [ + -1.1073788404464722, + 1.8209370374679565 + ], + [ + -1.0621074438095093, + 1.8425730466842651 + ], + [ + -1.0196586847305298, + 1.8691282272338867 + ], + [ + -0.9618881940841675, + 1.8960304260253906 + ], + [ + -0.9235616326332092, + 1.9144785404205322 + ], + [ + -0.8682800531387329, + 1.9332228899002075 + ], + [ + -0.8256640434265137, + 1.9428532123565674 + ], + [ + -0.7759353518486023, + 1.9702941179275513 + ], + [ + -0.725291907787323, + 1.987788200378418 + ], + [ + -0.6876645088195801, + 2.0082032680511475 + ], + [ + -0.6292517185211182, + 2.0249319076538086 + ], + [ + -0.5802642703056335, + 2.0265984535217285 + ], + [ + -0.5282400846481323, + 2.038886547088623 + ], + [ + -0.48228719830513, + 2.0465712547302246 + ], + [ + -0.4277693033218384, + 2.0460712909698486 + ], + [ + -0.377517968416214, + 2.064807176589966 + ], + [ + -0.33057844638824463, + 2.05850887298584 + ], + [ + -0.27055439352989197, + 2.0662715435028076 + ], + [ + -0.21040573716163635, + 2.065749168395996 + ], + [ + -0.1696169674396515, + 2.074981451034546 + ], + [ + -0.1197386160492897, + 2.077733278274536 + ], + [ + -0.06094830483198166, + 2.0679469108581543 + ], + [ + -0.011662371456623077, + 2.0676372051239014 + ], + [ + 0.039039935916662216, + 2.0678250789642334 + ], + [ + 0.08889462798833847, + 2.073586940765381 + ], + [ + 0.13304537534713745, + 2.064265727996826 + ], + [ + 0.189015731215477, + 2.0514655113220215 + ], + [ + 0.24343793094158173, + 2.0448896884918213 + ], + [ + 0.2927638590335846, + 2.036569118499756 + ], + [ + 0.33531835675239563, + 2.0193405151367188 + ], + [ + 0.39725443720817566, + 2.0078935623168945 + ], + [ + 0.44500455260276794, + 1.9839231967926025 + ], + [ + 0.4850606918334961, + 1.9698652029037476 + ], + [ + 0.5412566661834717, + 1.9597039222717285 + ], + [ + 0.5927621126174927, + 1.9369587898254395 + ], + [ + 0.6447550058364868, + 1.9127733707427979 + ], + [ + 0.688443660736084, + 1.8987480401992798 + ], + [ + 0.7454437017440796, + 1.8653645515441895 + ], + [ + 0.7987039685249329, + 1.848548412322998 + ], + [ + 0.8304269909858704, + 1.8188258409500122 + ], + [ + 0.8865737915039062, + 1.8037256002426147 + ], + [ + 0.9273987412452698, + 1.7660380601882935 + ], + [ + 0.9767124652862549, + 1.7300115823745728 + ], + [ + 1.0236610174179077, + 1.705960750579834 + ], + [ + 1.068193793296814, + 1.671668529510498 + ], + [ + 1.11372709274292, + 1.6482442617416382 + ], + [ + 1.1559734344482422, + 1.6099097728729248 + ], + [ + 1.2066575288772583, + 1.5819576978683472 + ], + [ + 1.2415891885757446, + 1.5444457530975342 + ], + [ + 1.2930335998535156, + 1.49643874168396 + ], + [ + 1.322836995124817, + 1.4761070013046265 + ], + [ + 1.371530532836914, + 1.428163766860962 + ], + [ + 1.4088071584701538, + 1.3926481008529663 + ], + [ + 1.4491121768951416, + 1.360991358757019 + ], + [ + 1.4858574867248535, + 1.3063172101974487 + ], + [ + 1.5176845788955688, + 1.2624571323394775 + ], + [ + 1.5545073747634888, + 1.2285226583480835 + ], + [ + 1.5879948139190674, + 1.17943274974823 + ], + [ + 1.6243985891342163, + 1.1317617893218994 + ], + [ + 1.6615341901779175, + 1.08260178565979 + ], + [ + 1.6900712251663208, + 1.0333431959152222 + ], + [ + 1.717814326286316, + 0.9902201890945435 + ], + [ + 1.746445655822754, + 0.942279040813446 + ], + [ + 1.772727131843567, + 0.8898627161979675 + ], + [ + 1.8032939434051514, + 0.8373379707336426 + ], + [ + 1.8328804969787598, + 0.7871468663215637 + ], + [ + 1.8513412475585938, + 0.7346880435943604 + ], + [ + 1.8755710124969482, + 0.6825049519538879 + ], + [ + 1.8961644172668457, + 0.6306540966033936 + ], + [ + 1.9181969165802002, + 0.5768918991088867 + ], + [ + 1.936019778251648, + 0.5236983299255371 + ], + [ + 1.9539722204208374, + 0.47032448649406433 + ], + [ + 1.9702845811843872, + 0.414725661277771 + ], + [ + 1.9834765195846558, + 0.3605348765850067 + ], + [ + 1.9971245527267456, + 0.3065274953842163 + ], + [ + 2.008385181427002, + 0.2496398538351059 + ], + [ + 2.0193004608154297, + 0.1949463188648224 + ], + [ + 2.0279579162597656, + 0.13844212889671326 + ], + [ + 2.0361175537109375, + 0.08258921653032303 + ], + [ + 2.0439209938049316, + 0.02562468871474266 + ], + [ + 2.047374963760376, + -0.028325144201517105 + ], + [ + 2.0530107021331787, + -0.0829746350646019 + ], + [ + 2.055759906768799, + -0.13882683217525482 + ], + [ + 2.057039499282837, + -0.1936911642551422 + ], + [ + 2.0530734062194824, + -0.24340954422950745 + ], + [ + 2.050746440887451, + -0.297834575176239 + ], + [ + 2.0459911823272705, + -0.3541272282600403 + ], + [ + 2.0453693866729736, + -0.4127858877182007 + ], + [ + 2.0373477935791016, + -0.46628135442733765 + ], + [ + 2.0328099727630615, + -0.5220854878425598 + ], + [ + 2.0264673233032227, + -0.5758885741233826 + ], + [ + 2.0134334564208984, + -0.6362519860267639 + ], + [ + 2.0051519870758057, + -0.686268150806427 + ], + [ + 1.9915666580200195, + -0.7295870184898376 + ], + [ + 1.9772893190383911, + -0.7930265069007874 + ], + [ + 1.9589542150497437, + -0.851529061794281 + ], + [ + 1.9407579898834229, + -0.8976286053657532 + ], + [ + 1.9251834154129028, + -0.9423039555549622 + ], + [ + 1.9118725061416626, + -0.9959063529968262 + ], + [ + 1.8908127546310425, + -1.0471693277359009 + ], + [ + 1.8672717809677124, + -1.0982557535171509 + ], + [ + 1.8457963466644287, + -1.1430846452713013 + ], + [ + 1.8223048448562622, + -1.1954636573791504 + ], + [ + 1.8043832778930664, + -1.242423176765442 + ], + [ + 1.7639611959457397, + -1.28315007686615 + ], + [ + 1.7371305227279663, + -1.3349566459655762 + ], + [ + 1.7197831869125366, + -1.3766576051712036 + ], + [ + 1.6784757375717163, + -1.4153554439544678 + ], + [ + 1.6463868618011475, + -1.4576956033706665 + ], + [ + 1.6202188730239868, + -1.4995262622833252 + ], + [ + 1.5804072618484497, + -1.541324496269226 + ], + [ + 1.5511451959609985, + -1.5842128992080688 + ], + [ + 1.5204912424087524, + -1.6195735931396484 + ], + [ + 1.4792982339859009, + -1.6671792268753052 + ], + [ + 1.4310437440872192, + -1.6790533065795898 + ], + [ + 1.387775182723999, + -1.7118169069290161 + ], + [ + 1.3452465534210205, + -1.7541178464889526 + ], + [ + 1.3051905632019043, + -1.777711272239685 + ], + [ + 1.269614577293396, + -1.8160505294799805 + ], + [ + 1.2290723323822021, + -1.8326092958450317 + ], + [ + 1.1756011247634888, + -1.8672785758972168 + ], + [ + 1.1443504095077515, + -1.902449131011963 + ], + [ + 1.102105975151062, + -1.920470118522644 + ], + [ + 1.0602314472198486, + -1.954665184020996 + ], + [ + 0.9790259003639221, + -1.9163408279418945 + ], + [ + 0.9420793056488037, + -1.943117380142212 + ], + [ + 0.8876888751983643, + -1.9600069522857666 + ], + [ + 0.8578128218650818, + -1.9957979917526245 + ], + [ + 0.8114399313926697, + -2.0363433361053467 + ], + [ + 0.7715330123901367, + -2.0771844387054443 + ], + [ + 0.7246339321136475, + -2.127476692199707 + ], + [ + 0.6680493354797363, + -2.148742437362671 + ], + [ + 0.615401566028595, + -2.198784828186035 + ], + [ + 0.5356854796409607, + -2.2125742435455322 + ], + [ + 0.45131540298461914, + -2.185903310775757 + ], + [ + 0.35771453380584717, + -2.18733549118042 + ], + [ + 0.2594391405582428, + -2.152716875076294 + ], + [ + 0.11931879073381424, + -2.114509344100952 + ], + [ + -0.05228176340460777, + -2.037353754043579 + ], + [ + -0.2330012023448944, + -1.8894004821777344 + ], + [ + -0.37270742654800415, + -1.7548279762268066 + ], + [ + -0.4824005961418152, + -1.6316970586776733 + ], + [ + -0.5308865904808044, + -1.5764117240905762 + ], + [ + -0.5550938248634338, + -1.5765622854232788 + ], + [ + -0.5972840189933777, + -1.8951325416564941 + ], + [ + -0.6266809701919556, + -1.961323857307434 + ], + [ + -0.6396424770355225, + -1.9779587984085083 + ], + [ + -0.6692653298377991, + -1.9492883682250977 + ], + [ + -0.6722683906555176, + -1.9039932489395142 + ], + [ + -0.6764839887619019, + -1.8050397634506226 + ], + [ + -0.6515088081359863, + -1.7225184440612793 + ], + [ + -0.6263872981071472, + -1.6341053247451782 + ], + [ + -0.587630569934845, + -1.5433638095855713 + ], + [ + -0.5498902201652527, + -1.485793113708496 + ], + [ + -0.506751298904419, + -1.4429348707199097 + ], + [ + -0.579936683177948, + -1.5312026739120483 + ], + [ + -0.5408642888069153, + -1.4762648344039917 + ], + [ + -0.521812379360199, + -1.4505494832992554 + ], + [ + -0.49930599331855774, + -1.4371663331985474 + ], + [ + -0.49079829454421997, + -1.454301118850708 + ], + [ + -0.5385971069335938, + -1.5405988693237305 + ], + [ + -0.6471798419952393, + -1.6939311027526855 + ], + [ + -0.791558563709259, + -1.8816765546798706 + ], + [ + -0.9543705582618713, + -2.057443380355835 + ], + [ + -1.084699034690857, + -2.168057680130005 + ], + [ + -1.1849048137664795, + -2.1777665615081787 + ], + [ + -1.2744269371032715, + -2.159170627593994 + ], + [ + -1.2871183156967163, + -2.1215929985046387 + ], + [ + -1.3741954565048218, + -2.106874942779541 + ], + [ + -1.4468402862548828, + -2.0609853267669678 + ], + [ + -1.5122511386871338, + -2.0195114612579346 + ], + [ + -1.576588749885559, + -1.970413327217102 + ], + [ + -1.6401374340057373, + -1.9090458154678345 + ], + [ + -1.676909327507019, + -1.821027398109436 + ], + [ + -1.711119294166565, + -1.7426294088363647 + ], + [ + -1.7298743724822998, + -1.6583516597747803 + ], + [ + -1.7481632232666016, + -1.5831114053726196 + ], + [ + -1.7637975215911865, + -1.5254923105239868 + ], + [ + -1.7908180952072144, + -1.4974889755249023 + ], + [ + -1.8756924867630005, + -1.4893426895141602 + ], + [ + -1.9129077196121216, + -1.4807029962539673 + ], + [ + -1.9693275690078735, + -1.4795637130737305 + ], + [ + -2.037893533706665, + -1.4828743934631348 + ], + [ + -2.110341787338257, + -1.5002020597457886 + ], + [ + -2.1947784423828125, + -1.500933051109314 + ], + [ + -2.259775400161743, + -1.4907984733581543 + ], + [ + -2.3349084854125977, + -1.4713819026947021 + ], + [ + -2.4125165939331055, + -1.4283255338668823 + ], + [ + -2.471870183944702, + -1.3826944828033447 + ], + [ + -2.53313946723938, + -1.326074481010437 + ], + [ + -2.579136371612549, + -1.2634663581848145 + ], + [ + -2.624403715133667, + -1.19972562789917 + ], + [ + -2.6804511547088623, + -1.1423391103744507 + ], + [ + -2.7289047241210938, + -1.075713038444519 + ], + [ + -2.771232843399048, + -0.9997217059135437 + ], + [ + -2.8056182861328125, + -0.9291902184486389 + ], + [ + -2.837981700897217, + -0.8571382164955139 + ], + [ + -2.861341953277588, + -0.7772646546363831 + ], + [ + -2.8806822299957275, + -0.7099368572235107 + ], + [ + -2.896350383758545, + -0.6319923400878906 + ], + [ + -2.9077041149139404, + -0.5589340925216675 + ], + [ + -2.9155611991882324, + -0.48309653997421265 + ], + [ + -2.919671058654785, + -0.4111967980861664 + ], + [ + -2.9211626052856445, + -0.33548834919929504 + ], + [ + -3.0138392448425293, + -0.25426730513572693 + ], + [ + -3.026895523071289, + -0.17562679946422577 + ], + [ + -3.0333735942840576, + -0.09418465942144394 + ], + [ + -3.0378265380859375, + -0.019998816773295403 + ], + [ + -3.039696216583252, + 0.05766826495528221 + ], + [ + -3.036749839782715, + 0.134446382522583 + ], + [ + -3.0267417430877686, + 0.21114985644817352 + ], + [ + -3.021972417831421, + 0.28294607996940613 + ], + [ + -3.0155367851257324, + 0.3623282015323639 + ], + [ + -2.9996933937072754, + 0.43712347745895386 + ], + [ + -2.9907610416412354, + 0.5138086080551147 + ], + [ + -2.9789650440216064, + 0.5894693732261658 + ], + [ + -2.955921173095703, + 0.6568942666053772 + ], + [ + -2.975410223007202, + 0.7644335627555847 + ], + [ + -2.9585471153259277, + 0.8408146500587463 + ], + [ + -2.9425251483917236, + 0.908227264881134 + ], + [ + -2.9227073192596436, + 0.9782958030700684 + ], + [ + -2.9067611694335938, + 1.0512185096740723 + ], + [ + -2.8807168006896973, + 1.1195088624954224 + ], + [ + -2.85424542427063, + 1.1936523914337158 + ], + [ + -2.8270833492279053, + 1.2662007808685303 + ], + [ + -2.814448833465576, + 1.3580150604248047 + ], + [ + -2.7690584659576416, + 1.4343712329864502 + ], + [ + -2.707697868347168, + 1.5138766765594482 + ], + [ + -2.665834903717041, + 1.574691653251648 + ], + [ + -2.583801746368408, + 1.6460704803466797 + ], + [ + -2.513245105743408, + 1.69454026222229 + ], + [ + -2.475759983062744, + 1.769864797592163 + ], + [ + -2.4156627655029297, + 1.7967053651809692 + ], + [ + -2.3722758293151855, + 1.8330044746398926 + ], + [ + -2.316722869873047, + 1.866292953491211 + ], + [ + -2.279439687728882, + 1.9071019887924194 + ], + [ + -2.226262092590332, + 1.9400603771209717 + ], + [ + -2.1896634101867676, + 1.9803316593170166 + ], + [ + -2.1247670650482178, + 2.0155563354492188 + ], + [ + -2.0847055912017822, + 2.0536720752716064 + ], + [ + -2.0230491161346436, + 2.1191983222961426 + ], + [ + -1.9615904092788696, + 2.139298439025879 + ], + [ + -1.898754596710205, + 2.1596462726593018 + ], + [ + -1.8539307117462158, + 2.19799542427063 + ], + [ + -1.778117060661316, + 2.212709665298462 + ], + [ + -1.736876368522644, + 2.2493553161621094 + ], + [ + -1.6549112796783447, + 2.282167911529541 + ], + [ + -1.613140344619751, + 2.291808605194092 + ], + [ + -1.5526442527770996, + 2.3036253452301025 + ], + [ + -1.51134192943573, + 2.3046796321868896 + ], + [ + -1.4463485479354858, + 2.3146743774414062 + ], + [ + -1.3800686597824097, + 2.3403472900390625 + ], + [ + -1.333465814590454, + 2.330880641937256 + ], + [ + -1.2867395877838135, + 2.342862367630005 + ], + [ + -1.2384792566299438, + 2.3392555713653564 + ], + [ + -1.1968265771865845, + 2.353299379348755 + ], + [ + -1.1462433338165283, + 2.3524646759033203 + ], + [ + -1.0893385410308838, + 2.3619916439056396 + ], + [ + -1.0446783304214478, + 2.36442232131958 + ], + [ + -1.0102226734161377, + 2.3693816661834717 + ], + [ + -0.9800311923027039, + 2.3836965560913086 + ], + [ + -0.9358634352684021, + 2.401972770690918 + ], + [ + -0.8795412182807922, + 2.4004368782043457 + ], + [ + -0.8409472703933716, + 2.4108643531799316 + ], + [ + -0.8039640784263611, + 2.424617290496826 + ], + [ + -0.7709384560585022, + 2.434352159500122 + ], + [ + -0.7341862916946411, + 2.4453024864196777 + ], + [ + -0.6874551177024841, + 2.4448821544647217 + ], + [ + -0.6509413719177246, + 2.473461627960205 + ], + [ + -0.5877283811569214, + 2.478449583053589 + ], + [ + -0.5396758913993835, + 2.487039566040039 + ], + [ + -0.5012562274932861, + 2.491401433944702 + ], + [ + -0.4478049576282501, + 2.5037076473236084 + ], + [ + -0.39794421195983887, + 2.518535614013672 + ], + [ + -0.34363117814064026, + 2.524292469024658 + ], + [ + -0.3036492168903351, + 2.5309927463531494 + ], + [ + -0.2469555139541626, + 2.5450353622436523 + ], + [ + -0.17544643580913544, + 2.539271831512451 + ], + [ + -0.10084348917007446, + 2.554676055908203 + ], + [ + -0.05391861870884895, + 2.542248249053955 + ], + [ + 0.011995027773082256, + 2.550614595413208 + ], + [ + 0.07806886732578278, + 2.5571911334991455 + ], + [ + 0.11975415050983429, + 2.547701835632324 + ], + [ + 0.16011224687099457, + 2.550675392150879 + ], + [ + 0.23179209232330322, + 2.544069766998291 + ], + [ + 0.30070701241493225, + 2.5384163856506348 + ], + [ + 0.3597598075866699, + 2.535822868347168 + ], + [ + 0.4035032093524933, + 2.5177619457244873 + ], + [ + 0.4544868767261505, + 2.5180065631866455 + ], + [ + 0.5448375344276428, + 2.496636390686035 + ], + [ + 0.6129027009010315, + 2.49289870262146 + ], + [ + 0.66318678855896, + 2.4798190593719482 + ], + [ + 0.7213486433029175, + 2.4671852588653564 + ], + [ + 0.776491105556488, + 2.4450807571411133 + ], + [ + 0.8486360907554626, + 2.4312968254089355 + ], + [ + 0.9200431704521179, + 2.4158709049224854 + ], + [ + 0.9822791218757629, + 2.3846287727355957 + ], + [ + 1.0507348775863647, + 2.366086721420288 + ], + [ + 1.109632134437561, + 2.3459889888763428 + ], + [ + 1.1991487741470337, + 2.312267780303955 + ], + [ + 1.2450958490371704, + 2.2846975326538086 + ], + [ + 1.3176641464233398, + 2.245155096054077 + ], + [ + 1.3781532049179077, + 2.2081799507141113 + ], + [ + 1.4392364025115967, + 2.18155837059021 + ], + [ + 1.4881616830825806, + 2.1472420692443848 + ], + [ + 1.5598158836364746, + 2.117340564727783 + ], + [ + 1.621751308441162, + 2.082244873046875 + ], + [ + 1.681108832359314, + 2.0241453647613525 + ], + [ + 1.763067364692688, + 1.9836277961730957 + ], + [ + 1.8027411699295044, + 1.9297118186950684 + ], + [ + 1.8608843088150024, + 1.8849177360534668 + ], + [ + 1.9157190322875977, + 1.846092700958252 + ], + [ + 1.9747368097305298, + 1.799984335899353 + ], + [ + 2.0320544242858887, + 1.7373936176300049 + ], + [ + 2.0969173908233643, + 1.6881911754608154 + ], + [ + 2.1467387676239014, + 1.6389353275299072 + ], + [ + 2.190516710281372, + 1.5842288732528687 + ], + [ + 2.253933906555176, + 1.5260403156280518 + ], + [ + 2.300490379333496, + 1.466659426689148 + ], + [ + 2.339001178741455, + 1.419132947921753 + ], + [ + 2.377389907836914, + 1.3612295389175415 + ], + [ + 2.429159641265869, + 1.2937220335006714 + ], + [ + 2.4760777950286865, + 1.2321645021438599 + ], + [ + 2.52648663520813, + 1.1711915731430054 + ], + [ + 2.5685079097747803, + 1.10277259349823 + ], + [ + 2.612246513366699, + 1.0412447452545166 + ], + [ + 2.6590631008148193, + 0.96451735496521 + ], + [ + 2.6936771869659424, + 0.8945825695991516 + ], + [ + 2.728400468826294, + 0.835950493812561 + ], + [ + 2.7612099647521973, + 0.7599547505378723 + ], + [ + 2.789625883102417, + 0.6861118674278259 + ], + [ + 2.8285393714904785, + 0.6172971725463867 + ], + [ + 2.8627073764801025, + 0.5425089001655579 + ], + [ + 2.8916571140289307, + 0.4606771767139435 + ], + [ + 2.9197311401367188, + 0.3780616521835327 + ], + [ + 2.9487524032592773, + 0.292915403842926 + ], + [ + 2.971808433532715, + 0.20933648943901062 + ], + [ + 2.995140790939331, + 0.11864086240530014 + ], + [ + 3.0181756019592285, + 0.030580004677176476 + ], + [ + 3.0452840328216553, + -0.060586899518966675 + ], + [ + 3.0503077507019043, + -0.13604934513568878 + ], + [ + 3.0698914527893066, + -0.23995622992515564 + ], + [ + 3.078491687774658, + -0.32350262999534607 + ], + [ + 3.0818393230438232, + -0.4170595109462738 + ], + [ + 3.08833646774292, + -0.5095797181129456 + ], + [ + 3.1032161712646484, + -0.6094707250595093 + ], + [ + 3.100677967071533, + -0.7035835385322571 + ], + [ + 3.0946531295776367, + -0.800666093826294 + ], + [ + 3.097914218902588, + -0.9062707424163818 + ], + [ + 3.0996203422546387, + -1.015777349472046 + ], + [ + 3.0824952125549316, + -1.1148368120193481 + ], + [ + 3.077432155609131, + -1.2232158184051514 + ], + [ + 3.066650152206421, + -1.3216910362243652 + ], + [ + 3.083028793334961, + -1.439587950706482 + ], + [ + 2.9883933067321777, + -1.5217981338500977 + ], + [ + 2.9640846252441406, + -1.6210706233978271 + ], + [ + 2.949012041091919, + -1.7401691675186157 + ], + [ + 2.9057304859161377, + -1.8667677640914917 + ], + [ + 2.8564324378967285, + -1.9638339281082153 + ], + [ + 2.8124847412109375, + -2.0664730072021484 + ], + [ + 2.7607383728027344, + -2.186269760131836 + ], + [ + 2.724405288696289, + -2.292771816253662 + ], + [ + 2.6438026428222656, + -2.3951282501220703 + ], + [ + 2.5644590854644775, + -2.51100754737854 + ], + [ + 2.513843059539795, + -2.621408462524414 + ], + [ + 2.406449794769287, + -2.7302536964416504 + ], + [ + 2.281958818435669, + -2.83337664604187 + ], + [ + 2.217024326324463, + -2.889907121658325 + ], + [ + 2.101747989654541, + -2.9808201789855957 + ], + [ + 2.0203118324279785, + -3.1442370414733887 + ], + [ + 1.9015345573425293, + -3.200127601623535 + ], + [ + 1.8035457134246826, + -3.288121223449707 + ], + [ + 1.6917238235473633, + -3.3516671657562256 + ], + [ + 1.5539387464523315, + -3.430612564086914 + ], + [ + 1.4255461692810059, + -3.506840944290161 + ], + [ + 1.2691807746887207, + -3.5530495643615723 + ], + [ + 1.0836812257766724, + -3.6132383346557617 + ], + [ + 0.9056865572929382, + -3.6305294036865234 + ], + [ + 0.7062676548957825, + -3.6409237384796143 + ], + [ + 0.48008227348327637, + -3.651737689971924 + ], + [ + 0.2848135530948639, + -3.645282506942749 + ], + [ + 0.35217246413230896, + -3.7474567890167236 + ], + [ + 0.21195350587368011, + -3.8631370067596436 + ], + [ + 0.043717242777347565, + -3.9295217990875244 + ], + [ + -0.055949967354536057, + -3.8955061435699463 + ], + [ + -0.2313389629125595, + -3.936713218688965 + ], + [ + -0.36753740906715393, + -4.001667022705078 + ], + [ + -0.5701069831848145, + -4.031083106994629 + ], + [ + -0.7193638682365417, + -4.010928630828857 + ], + [ + -0.9123112559318542, + -3.9432568550109863 + ], + [ + -1.0961499214172363, + -3.883634090423584 + ], + [ + -1.2699546813964844, + -3.8151633739471436 + ], + [ + -1.4612833261489868, + -3.751002073287964 + ], + [ + -3.075299024581909, + -7.190287113189697 + ], + [ + -3.478497266769409, + -7.030949592590332 + ], + [ + -3.4163830280303955, + -7.509958744049072 + ], + [ + -3.755155324935913, + -7.513199329376221 + ], + [ + -4.123136043548584, + -7.524814605712891 + ], + [ + -4.453611850738525, + -7.46895170211792 + ], + [ + -4.782583713531494, + -7.421286106109619 + ], + [ + -5.113187789916992, + -7.304635047912598 + ], + [ + -5.412776470184326, + -7.137959003448486 + ], + [ + -5.60633659362793, + -6.936783790588379 + ], + [ + -5.931177616119385, + -6.782471656799316 + ], + [ + -6.1928277015686035, + -6.5194807052612305 + ], + [ + -6.454876899719238, + -6.213492393493652 + ], + [ + -6.648608684539795, + -5.914278984069824 + ], + [ + -6.844915866851807, + -5.5787482261657715 + ], + [ + -7.04181432723999, + -5.181842803955078 + ], + [ + -7.4386162757873535, + -5.66335916519165 + ], + [ + -7.738227367401123, + -5.4609293937683105 + ], + [ + -7.9573893547058105, + -5.193496227264404 + ], + [ + -8.105751991271973, + -4.965923309326172 + ], + [ + -8.291110038757324, + -4.7123703956604 + ], + [ + -8.525086402893066, + -4.458969593048096 + ], + [ + -8.684398651123047, + -4.192453861236572 + ], + [ + -8.80959415435791, + -3.8892505168914795 + ], + [ + -8.951833724975586, + -3.600395917892456 + ], + [ + -9.040789604187012, + -3.326841115951538 + ], + [ + -9.11397933959961, + -3.053290605545044 + ], + [ + -9.198204040527344, + -2.7775681018829346 + ], + [ + -9.268774032592773, + -2.502626657485962 + ], + [ + -9.31387996673584, + -2.18566632270813 + ], + [ + -9.316969871520996, + -1.9154131412506104 + ], + [ + -9.575827598571777, + -1.6899380683898926 + ], + [ + -9.635106086730957, + -1.3736650943756104 + ], + [ + -9.617280006408691, + -1.0886234045028687 + ], + [ + -9.64592170715332, + -0.8348332047462463 + ], + [ + -9.649589538574219, + -0.5451606512069702 + ], + [ + -9.675400733947754, + -0.26295775175094604 + ], + [ + -9.678749084472656, + -0.02756967954337597 + ], + [ + -9.631559371948242, + 0.20831765234470367 + ], + [ + -9.624733924865723, + 0.47894811630249023 + ], + [ + -9.615409851074219, + 0.718176007270813 + ], + [ + -9.581632614135742, + 0.9181302189826965 + ], + [ + -9.554632186889648, + 1.2302730083465576 + ], + [ + -9.550939559936523, + 1.4048774242401123 + ], + [ + -9.48068904876709, + 1.6939939260482788 + ], + [ + -9.420056343078613, + 1.8948835134506226 + ] + ], + "total_points": 1000 +} \ No newline at end of file diff --git a/vna_system/calibration/s11_start100_stop8800_points1000_bw1khz/еуыеуые/load_metadata.json b/vna_system/calibration/s11_start100_stop8800_points1000_bw1khz/еуыеуые/load_metadata.json new file mode 100644 index 0000000..ac2df9c --- /dev/null +++ b/vna_system/calibration/s11_start100_stop8800_points1000_bw1khz/еуыеуые/load_metadata.json @@ -0,0 +1,16 @@ +{ + "preset": { + "filename": "s11_start100_stop8800_points1000_bw1khz.bin", + "mode": "s11", + "start_freq": 100000000.0, + "stop_freq": 8800000000.0, + "points": 1000, + "bandwidth": 1000.0 + }, + "calibration_name": "еуыеуые", + "standard": "load", + "sweep_number": 12, + "sweep_timestamp": 1758896376.33808, + "created_timestamp": "2025-09-26T17:19:50.017201", + "total_points": 1000 +} \ No newline at end of file diff --git a/vna_system/calibration/s11_start100_stop8800_points1000_bw1khz/еуыеуые/open.json b/vna_system/calibration/s11_start100_stop8800_points1000_bw1khz/еуыеуые/open.json new file mode 100644 index 0000000..93916fb --- /dev/null +++ b/vna_system/calibration/s11_start100_stop8800_points1000_bw1khz/еуыеуые/open.json @@ -0,0 +1,4007 @@ +{ + "sweep_number": 10, + "timestamp": 1758896372.20023, + "points": [ + [ + -2.673739433288574, + 0.45156076550483704 + ], + [ + -2.6649129390716553, + 0.513051450252533 + ], + [ + -2.6558549404144287, + 0.5747984051704407 + ], + [ + -2.645857334136963, + 0.6361462473869324 + ], + [ + -2.633631944656372, + 0.6952682733535767 + ], + [ + -3.403935432434082, + 0.9242688417434692 + ], + [ + -3.3881826400756836, + 1.0033330917358398 + ], + [ + -3.3698625564575195, + 1.0824904441833496 + ], + [ + -3.3492372035980225, + 1.1588549613952637 + ], + [ + -3.330765962600708, + 1.232941746711731 + ], + [ + -3.3084704875946045, + 1.3084763288497925 + ], + [ + -3.2857754230499268, + 1.3843321800231934 + ], + [ + -3.2597832679748535, + 1.4665257930755615 + ], + [ + -3.2385432720184326, + 1.5350182056427002 + ], + [ + -3.2074339389801025, + 1.6084271669387817 + ], + [ + -3.1826112270355225, + 1.685124158859253 + ], + [ + -3.145615339279175, + 1.7575218677520752 + ], + [ + -3.1079468727111816, + 1.8319554328918457 + ], + [ + -3.0794737339019775, + 1.912867546081543 + ], + [ + -3.0415241718292236, + 1.982412338256836 + ], + [ + -3.001547336578369, + 2.056443452835083 + ], + [ + -2.9643545150756836, + 2.1307480335235596 + ], + [ + -2.92730975151062, + 2.202094554901123 + ], + [ + -2.8799049854278564, + 2.2769224643707275 + ], + [ + -2.845198154449463, + 2.346991777420044 + ], + [ + -2.799729108810425, + 2.4158167839050293 + ], + [ + -2.7537126541137695, + 2.4876222610473633 + ], + [ + -2.7052769660949707, + 2.564289093017578 + ], + [ + -2.6541028022766113, + 2.6332969665527344 + ], + [ + -2.607245445251465, + 2.705113649368286 + ], + [ + -2.560321569442749, + 2.774329423904419 + ], + [ + -2.507678270339966, + 2.840345859527588 + ], + [ + -2.4572134017944336, + 2.90155029296875 + ], + [ + -2.3991782665252686, + 2.970244884490967 + ], + [ + -2.3359506130218506, + 3.0281262397766113 + ], + [ + -2.272580623626709, + 3.1036369800567627 + ], + [ + -2.2043097019195557, + 3.167612075805664 + ], + [ + -2.1327273845672607, + 3.229475736618042 + ], + [ + -2.0623579025268555, + 3.292647123336792 + ], + [ + -1.993981122970581, + 3.355898141860962 + ], + [ + -1.9178006649017334, + 3.4165966510772705 + ], + [ + -1.8548699617385864, + 3.4743874073028564 + ], + [ + -1.7748606204986572, + 3.5364747047424316 + ], + [ + -1.6955955028533936, + 3.592913866043091 + ], + [ + -1.6184803247451782, + 3.6493875980377197 + ], + [ + -1.5377038717269897, + 3.711130142211914 + ], + [ + -1.451350450515747, + 3.7623093128204346 + ], + [ + -1.360782265663147, + 3.817765235900879 + ], + [ + -1.2736819982528687, + 3.8664159774780273 + ], + [ + -1.1892800331115723, + 3.912588119506836 + ], + [ + -1.0949574708938599, + 3.964703321456909 + ], + [ + -1.0007688999176025, + 4.012701034545898 + ], + [ + -0.9051529765129089, + 4.0576276779174805 + ], + [ + -0.8100021481513977, + 4.103817462921143 + ], + [ + -0.7051001191139221, + 4.1440935134887695 + ], + [ + -0.6106477975845337, + 4.186735153198242 + ], + [ + -0.5065211653709412, + 4.225441932678223 + ], + [ + -0.40272051095962524, + 4.254693508148193 + ], + [ + -0.2933235466480255, + 4.292872905731201 + ], + [ + -0.1805315762758255, + 4.319218158721924 + ], + [ + -0.06295012682676315, + 4.338851451873779 + ], + [ + 0.052794620394706726, + 4.364953517913818 + ], + [ + 0.1731880009174347, + 4.385064601898193 + ], + [ + 0.2995530068874359, + 4.407481670379639 + ], + [ + 0.4214695990085602, + 4.413839817047119 + ], + [ + 0.538074254989624, + 4.417781829833984 + ], + [ + 0.6623815298080444, + 4.419964790344238 + ], + [ + 0.7855268716812134, + 4.439248561859131 + ], + [ + 0.9165951609611511, + 4.436570167541504 + ], + [ + 1.0472674369812012, + 4.430618762969971 + ], + [ + 1.1832053661346436, + 4.43658447265625 + ], + [ + 1.311678409576416, + 4.411652565002441 + ], + [ + 1.4496970176696777, + 4.401487350463867 + ], + [ + 1.5880038738250732, + 4.381790637969971 + ], + [ + 1.7219984531402588, + 4.3501081466674805 + ], + [ + 1.851840853691101, + 4.3273468017578125 + ], + [ + 1.9884774684906006, + 4.291476726531982 + ], + [ + 2.130871295928955, + 4.244260311126709 + ], + [ + 2.266610860824585, + 4.20750617980957 + ], + [ + 2.3970084190368652, + 4.158644676208496 + ], + [ + 2.5286524295806885, + 4.103801727294922 + ], + [ + 2.656381130218506, + 4.056865692138672 + ], + [ + 2.7844386100769043, + 3.9941651821136475 + ], + [ + 2.912785053253174, + 3.930203914642334 + ], + [ + 3.033395290374756, + 3.858043909072876 + ], + [ + 3.1451590061187744, + 3.778082847595215 + ], + [ + 3.2642054557800293, + 3.7020580768585205 + ], + [ + 3.3794069290161133, + 3.616048812866211 + ], + [ + 3.491755485534668, + 3.5333011150360107 + ], + [ + 3.608518600463867, + 3.4394607543945312 + ], + [ + 3.7218852043151855, + 3.327221393585205 + ], + [ + 3.832209348678589, + 3.2247977256774902 + ], + [ + 3.938857078552246, + 3.115402936935425 + ], + [ + 4.040282726287842, + 3.001502752304077 + ], + [ + 4.151309967041016, + 2.877244710922241 + ], + [ + 4.257106304168701, + 2.7531485557556152 + ], + [ + 4.343530654907227, + 2.6141016483306885 + ], + [ + 4.441436290740967, + 2.480767011642456 + ], + [ + 4.520089149475098, + 2.3407106399536133 + ], + [ + 4.599508285522461, + 2.2030017375946045 + ], + [ + 4.662495136260986, + 2.0622448921203613 + ], + [ + 4.734409332275391, + 1.9115701913833618 + ], + [ + 4.798306941986084, + 1.756025791168213 + ], + [ + 4.850204944610596, + 1.5971266031265259 + ], + [ + 4.899227619171143, + 1.4390836954116821 + ], + [ + 4.937671184539795, + 1.2689145803451538 + ], + [ + 4.989025115966797, + 1.1040934324264526 + ], + [ + 5.014588832855225, + 0.9390674233436584 + ], + [ + 5.041609287261963, + 0.7742377519607544 + ], + [ + 5.0642828941345215, + 0.613244891166687 + ], + [ + 5.070995330810547, + 0.44628459215164185 + ], + [ + 5.0812883377075195, + 0.27883169054985046 + ], + [ + 5.079288959503174, + 0.11039372533559799 + ], + [ + 5.072590351104736, + -0.05457678064703941 + ], + [ + 5.052835464477539, + -0.21008096635341644 + ], + [ + 5.032893657684326, + -0.3430282175540924 + ], + [ + 5.003726959228516, + -0.5002836585044861 + ], + [ + 4.962181568145752, + -0.644877552986145 + ], + [ + 4.914470672607422, + -0.7894101738929749 + ], + [ + 4.865083694458008, + -0.9428054094314575 + ], + [ + 4.809659957885742, + -1.075697660446167 + ], + [ + 4.742484092712402, + -1.217930555343628 + ], + [ + 4.67523717880249, + -1.3492511510849 + ], + [ + 4.5907721519470215, + -1.4802731275558472 + ], + [ + 4.511129856109619, + -1.6213281154632568 + ], + [ + 4.432206630706787, + -1.7444605827331543 + ], + [ + 4.334622859954834, + -1.8803452253341675 + ], + [ + 4.245117664337158, + -2.0015625953674316 + ], + [ + 4.147948265075684, + -2.1409358978271484 + ], + [ + 4.060741901397705, + -2.2717814445495605 + ], + [ + 3.9563636779785156, + -2.3853511810302734 + ], + [ + 3.8573825359344482, + -2.5060460567474365 + ], + [ + 3.760112762451172, + -2.6271774768829346 + ], + [ + 3.6596014499664307, + -2.749547243118286 + ], + [ + 3.555980920791626, + -2.8401906490325928 + ], + [ + 3.457160711288452, + -2.9322047233581543 + ], + [ + 3.366191864013672, + -3.0111629962921143 + ], + [ + 3.265988349914551, + -3.085876226425171 + ], + [ + 3.164534330368042, + -3.1570117473602295 + ], + [ + 3.06292724609375, + -3.192289352416992 + ], + [ + 2.9604928493499756, + -3.2231409549713135 + ], + [ + 2.856276750564575, + -3.2706727981567383 + ], + [ + 2.735194444656372, + -3.2982699871063232 + ], + [ + 2.6268210411071777, + -3.307996988296509 + ], + [ + 2.530113458633423, + -3.332594871520996 + ], + [ + 2.4138882160186768, + -3.3434603214263916 + ], + [ + 2.297778844833374, + -3.3559978008270264 + ], + [ + 2.196959972381592, + -3.372385025024414 + ], + [ + 2.0814597606658936, + -3.3710296154022217 + ], + [ + 1.9665361642837524, + -3.371508836746216 + ], + [ + 1.8650518655776978, + -3.3920116424560547 + ], + [ + 1.743028998374939, + -3.403501272201538 + ], + [ + 1.6151542663574219, + -3.4197301864624023 + ], + [ + 1.4722492694854736, + -3.618969678878784 + ], + [ + 1.3700580596923828, + -3.6286001205444336 + ], + [ + 1.267106056213379, + -3.630856990814209 + ], + [ + 1.1844881772994995, + -3.6078035831451416 + ], + [ + 1.0747287273406982, + -3.6167731285095215 + ], + [ + 0.9794720411300659, + -3.6031219959259033 + ], + [ + 0.8784794211387634, + -3.5958197116851807 + ], + [ + 0.7853028774261475, + -3.580150842666626 + ], + [ + 0.6919131875038147, + -3.571664810180664 + ], + [ + 0.5935009121894836, + -3.558393716812134 + ], + [ + 0.49969205260276794, + -3.5379302501678467 + ], + [ + 0.4151228368282318, + -3.521221876144409 + ], + [ + 0.3359678387641907, + -3.499297618865967 + ], + [ + 0.24965906143188477, + -3.4794552326202393 + ], + [ + 0.16907604038715363, + -3.4539520740509033 + ], + [ + 0.08652201294898987, + -3.429109811782837 + ], + [ + 0.007603790611028671, + -3.4137704372406006 + ], + [ + -0.06411737203598022, + -3.379042863845825 + ], + [ + -0.13537371158599854, + -3.3565926551818848 + ], + [ + -0.21225319802761078, + -3.3312411308288574 + ], + [ + -0.26580870151519775, + -3.298767328262329 + ], + [ + -0.3330942690372467, + -3.2713897228240967 + ], + [ + -0.3977962136268616, + -3.2417852878570557 + ], + [ + -0.46008211374282837, + -3.2167229652404785 + ], + [ + -0.5255948305130005, + -3.187068462371826 + ], + [ + -0.5960128307342529, + -3.159050703048706 + ], + [ + -0.6448279023170471, + -3.1287875175476074 + ], + [ + -0.6983448266983032, + -3.0971994400024414 + ], + [ + -0.7648026347160339, + -3.067093849182129 + ], + [ + -0.8129037618637085, + -3.029676675796509 + ], + [ + -0.8739919066429138, + -2.9930315017700195 + ], + [ + -0.9293529391288757, + -2.962355136871338 + ], + [ + -0.9748079776763916, + -2.9249751567840576 + ], + [ + -1.0300065279006958, + -2.892331600189209 + ], + [ + -1.0846223831176758, + -2.85740327835083 + ], + [ + -1.1337939500808716, + -2.8222618103027344 + ], + [ + -1.182889699935913, + -2.7902562618255615 + ], + [ + -1.2297178506851196, + -2.753788471221924 + ], + [ + -1.2800225019454956, + -2.7208938598632812 + ], + [ + -1.3210722208023071, + -2.6829707622528076 + ], + [ + -1.3690178394317627, + -2.647603988647461 + ], + [ + -1.408065915107727, + -2.61004638671875 + ], + [ + -1.4465913772583008, + -2.568586587905884 + ], + [ + -1.493316650390625, + -2.5269253253936768 + ], + [ + -1.5358070135116577, + -2.481229543685913 + ], + [ + -1.5724306106567383, + -2.4416894912719727 + ], + [ + -1.6030418872833252, + -2.398430824279785 + ], + [ + -1.6081273555755615, + -2.322627067565918 + ], + [ + -1.6524028778076172, + -2.2749640941619873 + ], + [ + -1.713636040687561, + -2.2261903285980225 + ], + [ + -1.7460359334945679, + -2.174438714981079 + ], + [ + -1.7953886985778809, + -2.1216330528259277 + ], + [ + -1.840531349182129, + -2.0737547874450684 + ], + [ + -1.884032130241394, + -2.020996332168579 + ], + [ + -1.929288387298584, + -1.9702271223068237 + ], + [ + -1.9631046056747437, + -1.9176175594329834 + ], + [ + -2.00911021232605, + -1.8680694103240967 + ], + [ + -2.046494960784912, + -1.8176757097244263 + ], + [ + -2.081730604171753, + -1.7713377475738525 + ], + [ + -2.114849328994751, + -1.7137656211853027 + ], + [ + -2.149484157562256, + -1.664921760559082 + ], + [ + -2.184220314025879, + -1.6157863140106201 + ], + [ + -2.210482597351074, + -1.5622557401657104 + ], + [ + -2.2365646362304688, + -1.5129673480987549 + ], + [ + -2.2604432106018066, + -1.4678012132644653 + ], + [ + -2.286165714263916, + -1.4109834432601929 + ], + [ + -2.3070719242095947, + -1.3645682334899902 + ], + [ + -2.3230974674224854, + -1.318247675895691 + ], + [ + -2.341379165649414, + -1.263301968574524 + ], + [ + -2.3552560806274414, + -1.2173128128051758 + ], + [ + -2.370678424835205, + -1.1735543012619019 + ], + [ + -2.378852605819702, + -1.1202616691589355 + ], + [ + -2.3944880962371826, + -1.0706045627593994 + ], + [ + -2.403724431991577, + -1.0237311124801636 + ], + [ + -2.410083055496216, + -0.9700629115104675 + ], + [ + -2.4225730895996094, + -0.9199527502059937 + ], + [ + -2.429896116256714, + -0.8685166835784912 + ], + [ + -2.4386253356933594, + -0.8136906027793884 + ], + [ + -2.4466803073883057, + -0.757963240146637 + ], + [ + -2.4590585231781006, + -0.6971179246902466 + ], + [ + -2.4675090312957764, + -0.6415748596191406 + ], + [ + -2.4814071655273438, + -0.5782310366630554 + ], + [ + -2.491809368133545, + -0.5154844522476196 + ], + [ + -2.5017800331115723, + -0.4585004150867462 + ], + [ + -2.5122973918914795, + -0.39757123589515686 + ], + [ + -2.522371292114258, + -0.33535900712013245 + ], + [ + -2.5337188243865967, + -0.2775164544582367 + ], + [ + -2.540048837661743, + -0.21877627074718475 + ], + [ + -2.5418498516082764, + -0.1634608954191208 + ], + [ + -2.529672861099243, + -0.10714323818683624 + ], + [ + -2.5264029502868652, + -0.05357235670089722 + ], + [ + -2.52181339263916, + 0.0009449694189243019 + ], + [ + -2.5180106163024902, + 0.05506140738725662 + ], + [ + -2.5108706951141357, + 0.1126888170838356 + ], + [ + -2.5047857761383057, + 0.16913540661334991 + ], + [ + -2.497627019882202, + 0.22725512087345123 + ], + [ + -2.4901864528656006, + 0.28493207693099976 + ], + [ + -2.4823408126831055, + 0.33867424726486206 + ], + [ + -2.4721734523773193, + 0.39622730016708374 + ], + [ + -2.463728189468384, + 0.456595242023468 + ], + [ + -2.453840732574463, + 0.518212616443634 + ], + [ + -2.448465347290039, + 0.5804044008255005 + ], + [ + -2.4321515560150146, + 0.6308199167251587 + ], + [ + -2.420095205307007, + 0.6932575106620789 + ], + [ + -2.413149356842041, + 0.7538670301437378 + ], + [ + -2.4010212421417236, + 0.814777672290802 + ], + [ + -2.396512269973755, + 0.8780211806297302 + ], + [ + -2.3759570121765137, + 0.9294361472129822 + ], + [ + -2.3672285079956055, + 0.993594229221344 + ], + [ + -2.357659339904785, + 1.0479778051376343 + ], + [ + -2.3484387397766113, + 1.106836199760437 + ], + [ + -2.341672897338867, + 1.1559571027755737 + ], + [ + -2.3341939449310303, + 1.2030401229858398 + ], + [ + -2.311798095703125, + 1.2638663053512573 + ], + [ + -2.302382707595825, + 1.3121248483657837 + ], + [ + -2.289390802383423, + 1.3600784540176392 + ], + [ + -2.2773334980010986, + 1.3965579271316528 + ], + [ + -2.25964617729187, + 1.4329959154129028 + ], + [ + -2.238879680633545, + 1.490058183670044 + ], + [ + -2.22335147857666, + 1.526302456855774 + ], + [ + -2.198225498199463, + 1.5590126514434814 + ], + [ + -2.169659376144409, + 1.5954673290252686 + ], + [ + -2.138239622116089, + 1.624245047569275 + ], + [ + -2.1085927486419678, + 1.6794883012771606 + ], + [ + -2.0723583698272705, + 1.7126065492630005 + ], + [ + -2.029174566268921, + 1.7440983057022095 + ], + [ + -1.9802840948104858, + 1.7782446146011353 + ], + [ + -1.922868251800537, + 1.8137011528015137 + ], + [ + -1.8652958869934082, + 1.858412742614746 + ], + [ + -1.8342331647872925, + 1.902883529663086 + ], + [ + -1.774390697479248, + 1.9451732635498047 + ], + [ + -1.7107019424438477, + 1.9953858852386475 + ], + [ + -1.6426820755004883, + 2.0536253452301025 + ], + [ + -1.5797325372695923, + 2.105282783508301 + ], + [ + -1.5339858531951904, + 2.159935474395752 + ], + [ + -1.471299409866333, + 2.210402011871338 + ], + [ + -1.4078975915908813, + 2.2791850566864014 + ], + [ + -1.3554701805114746, + 2.33878231048584 + ], + [ + -1.2878848314285278, + 2.413783550262451 + ], + [ + -1.2354466915130615, + 2.4714770317077637 + ], + [ + -1.1790872812271118, + 2.517664909362793 + ], + [ + -1.1258577108383179, + 2.5836181640625 + ], + [ + -1.0661447048187256, + 2.63527250289917 + ], + [ + -1.0171890258789062, + 2.7060818672180176 + ], + [ + -0.964286208152771, + 2.7677719593048096 + ], + [ + -0.9123448729515076, + 2.8169736862182617 + ], + [ + -0.8493546843528748, + 2.8513104915618896 + ], + [ + -0.792282223701477, + 2.9037694931030273 + ], + [ + -0.7267330288887024, + 2.9556121826171875 + ], + [ + -0.6574923396110535, + 3.001678466796875 + ], + [ + -0.602440595626831, + 3.0461671352386475 + ], + [ + -0.5327405333518982, + 3.0701825618743896 + ], + [ + -0.454886257648468, + 3.1087234020233154 + ], + [ + -0.38249143958091736, + 3.142806053161621 + ], + [ + -0.3113482892513275, + 3.182225465774536 + ], + [ + -0.2353852540254593, + 3.215853452682495 + ], + [ + -0.1657332181930542, + 3.2433278560638428 + ], + [ + -0.08955152332782745, + 3.2605957984924316 + ], + [ + -0.0075926464051008224, + 3.2846508026123047 + ], + [ + 0.07854433357715607, + 3.3075616359710693 + ], + [ + 0.14819608628749847, + 3.3173820972442627 + ], + [ + 0.23403523862361908, + 3.3423779010772705 + ], + [ + 0.3150162994861603, + 3.343482494354248 + ], + [ + 0.3836282789707184, + 3.3460259437561035 + ], + [ + 0.5782294273376465, + 3.2222185134887695 + ], + [ + 0.6907488107681274, + 3.2164063453674316 + ], + [ + 0.7878395915031433, + 3.221099853515625 + ], + [ + 0.8842020630836487, + 3.21044921875 + ], + [ + 0.9904516339302063, + 3.201211452484131 + ], + [ + 1.077153205871582, + 3.194613218307495 + ], + [ + 1.178472876548767, + 3.1924889087677 + ], + [ + 1.2756860256195068, + 3.168119192123413 + ], + [ + 1.372984766960144, + 3.1504733562469482 + ], + [ + 1.470031976699829, + 3.126138925552368 + ], + [ + 1.5502114295959473, + 3.103952407836914 + ], + [ + 1.6535502672195435, + 3.0751771926879883 + ], + [ + 1.761566162109375, + 3.038121461868286 + ], + [ + 1.8376762866973877, + 3.00028133392334 + ], + [ + 1.9243710041046143, + 2.9549663066864014 + ], + [ + 2.0050714015960693, + 2.9169528484344482 + ], + [ + 2.0730674266815186, + 2.8573431968688965 + ], + [ + 2.172926425933838, + 2.802460193634033 + ], + [ + 2.25787615776062, + 2.7440497875213623 + ], + [ + 2.3289005756378174, + 2.6836647987365723 + ], + [ + 2.3926267623901367, + 2.6066014766693115 + ], + [ + 2.4668145179748535, + 2.521561622619629 + ], + [ + 2.542529582977295, + 2.4651377201080322 + ], + [ + 2.613682508468628, + 2.3731486797332764 + ], + [ + 2.6789608001708984, + 2.2831084728240967 + ], + [ + 2.7482123374938965, + 2.1900265216827393 + ], + [ + 2.8139259815216064, + 2.090883493423462 + ], + [ + 2.8811254501342773, + 1.9886884689331055 + ], + [ + 2.9350249767303467, + 1.9070923328399658 + ], + [ + 2.992642402648926, + 1.8049155473709106 + ], + [ + 3.0565757751464844, + 1.6948270797729492 + ], + [ + 3.1117379665374756, + 1.5908820629119873 + ], + [ + 3.1722068786621094, + 1.479651689529419 + ], + [ + 3.225321054458618, + 1.3797974586486816 + ], + [ + 3.2643582820892334, + 1.275643229484558 + ], + [ + 3.306260108947754, + 1.1684906482696533 + ], + [ + 3.3499972820281982, + 1.071460247039795 + ], + [ + 3.391061544418335, + 0.9684932231903076 + ], + [ + 3.4241015911102295, + 0.8669576048851013 + ], + [ + 3.446537494659424, + 0.7731033563613892 + ], + [ + 3.4725029468536377, + 0.6751901507377625 + ], + [ + 3.4945948123931885, + 0.5823627710342407 + ], + [ + 3.5037426948547363, + 0.4882344901561737 + ], + [ + 3.5103461742401123, + 0.3987807333469391 + ], + [ + 3.5142998695373535, + 0.30780431628227234 + ], + [ + 3.5154154300689697, + 0.22005286812782288 + ], + [ + 3.507274866104126, + 0.1354454904794693 + ], + [ + 3.4941954612731934, + 0.046679913997650146 + ], + [ + 3.4767653942108154, + -0.04540266469120979 + ], + [ + 3.4563658237457275, + -0.13654570281505585 + ], + [ + 3.43294095993042, + -0.2295709103345871 + ], + [ + 3.408233642578125, + -0.32775676250457764 + ], + [ + 3.376615047454834, + -0.41626495122909546 + ], + [ + 3.3531277179718018, + -0.5159972906112671 + ], + [ + 3.321732997894287, + -0.6239827871322632 + ], + [ + 3.298553466796875, + -0.7230573296546936 + ], + [ + 3.2823562622070312, + -0.830716073513031 + ], + [ + 3.273911952972412, + -0.9296934604644775 + ], + [ + 3.2422914505004883, + -1.0242623090744019 + ], + [ + 3.240610361099243, + -1.1142371892929077 + ], + [ + 3.23455810546875, + -1.1950771808624268 + ], + [ + 3.22200083732605, + -1.26573646068573 + ], + [ + 3.215055227279663, + -1.3239927291870117 + ], + [ + 3.2125351428985596, + -1.3787815570831299 + ], + [ + 3.195530891418457, + -1.4163963794708252 + ], + [ + 3.169212818145752, + -1.470687985420227 + ], + [ + 3.137730598449707, + -1.5050407648086548 + ], + [ + 3.104691505432129, + -1.5340887308120728 + ], + [ + 3.066128730773926, + -1.5672608613967896 + ], + [ + 3.014753818511963, + -1.5871334075927734 + ], + [ + 2.959789276123047, + -1.6169579029083252 + ], + [ + 2.886758804321289, + -1.645664095878601 + ], + [ + 2.8378496170043945, + -1.6697461605072021 + ], + [ + 2.765411138534546, + -1.7016713619232178 + ], + [ + 2.702956438064575, + -1.7354638576507568 + ], + [ + 2.641831636428833, + -1.771303653717041 + ], + [ + 2.5774266719818115, + -1.8055553436279297 + ], + [ + 2.504848003387451, + -1.838784098625183 + ], + [ + 2.4341135025024414, + -1.8632429838180542 + ], + [ + 2.358118772506714, + -1.9002314805984497 + ], + [ + 2.275731086730957, + -1.9370590448379517 + ], + [ + 2.195993185043335, + -1.9730925559997559 + ], + [ + 2.120504856109619, + -2.0192766189575195 + ], + [ + 2.0429093837738037, + -2.065446615219116 + ], + [ + 1.9649585485458374, + -2.10963773727417 + ], + [ + 1.8987354040145874, + -2.1859257221221924 + ], + [ + 1.8299338817596436, + -2.204742431640625 + ], + [ + 1.762935757637024, + -2.2607953548431396 + ], + [ + 1.7049702405929565, + -2.305323839187622 + ], + [ + 1.6349676847457886, + -2.360426425933838 + ], + [ + 1.5753570795059204, + -2.4070565700531006 + ], + [ + 1.5193067789077759, + -2.4549832344055176 + ], + [ + 1.4788670539855957, + -2.5025951862335205 + ], + [ + 1.5116792917251587, + -2.4316720962524414 + ], + [ + 1.4467641115188599, + -2.459731340408325 + ], + [ + 1.3770906925201416, + -2.4757649898529053 + ], + [ + 1.2960847616195679, + -2.503100633621216 + ], + [ + 1.22483229637146, + -2.534119129180908 + ], + [ + 1.1520556211471558, + -2.5658578872680664 + ], + [ + 1.1313116550445557, + -2.5748651027679443 + ], + [ + 1.0623812675476074, + -2.5923824310302734 + ], + [ + 0.9986311793327332, + -2.616884469985962 + ], + [ + 0.9269463419914246, + -2.6401853561401367 + ], + [ + 0.8636673092842102, + -2.6629045009613037 + ], + [ + 0.8077315092086792, + -2.6777164936065674 + ], + [ + 0.7562493085861206, + -2.672135591506958 + ], + [ + 0.6929295063018799, + -2.690657615661621 + ], + [ + 0.6395148634910583, + -2.709127902984619 + ], + [ + 0.5786882638931274, + -2.7260775566101074 + ], + [ + 0.5235114693641663, + -2.742631435394287 + ], + [ + 0.46009859442710876, + -2.7636160850524902 + ], + [ + 0.4021819233894348, + -2.7303311824798584 + ], + [ + 0.35444211959838867, + -2.7590198516845703 + ], + [ + 0.2993292808532715, + -2.7578494548797607 + ], + [ + 0.24885420501232147, + -2.7712488174438477 + ], + [ + 0.2040167897939682, + -2.7718870639801025 + ], + [ + 0.14414089918136597, + -2.785547971725464 + ], + [ + 0.08775749057531357, + -2.771876096725464 + ], + [ + 0.038835711777210236, + -2.7708065509796143 + ], + [ + -0.006943136919289827, + -2.767522096633911 + ], + [ + -0.05037892982363701, + -2.780808687210083 + ], + [ + -0.09098981320858002, + -2.7686045169830322 + ], + [ + -0.12635745108127594, + -2.758002758026123 + ], + [ + -0.19055576622486115, + -2.7569143772125244 + ], + [ + -0.2409641146659851, + -2.7455387115478516 + ], + [ + -0.28483158349990845, + -2.741785764694214 + ], + [ + -0.3198874592781067, + -2.7275235652923584 + ], + [ + -0.36454910039901733, + -2.71773099899292 + ], + [ + -0.3960443139076233, + -2.705425977706909 + ], + [ + -0.44505977630615234, + -2.68341064453125 + ], + [ + -0.5011464357376099, + -2.679150342941284 + ], + [ + -0.5432827472686768, + -2.6654818058013916 + ], + [ + -0.5753180384635925, + -2.6457245349884033 + ], + [ + -0.6168137192726135, + -2.6305782794952393 + ], + [ + -0.6538958549499512, + -2.6098320484161377 + ], + [ + -0.6869475841522217, + -2.579406261444092 + ], + [ + -0.7358010411262512, + -2.56002140045166 + ], + [ + -0.7716663479804993, + -2.555180072784424 + ], + [ + -0.8087449073791504, + -2.530482292175293 + ], + [ + -0.8416727781295776, + -2.501129150390625 + ], + [ + -0.8798172473907471, + -2.4753246307373047 + ], + [ + -0.9275298118591309, + -2.433319568634033 + ], + [ + -0.9638142585754395, + -2.408129930496216 + ], + [ + -1.0067325830459595, + -2.401780366897583 + ], + [ + -1.0420506000518799, + -2.365060567855835 + ], + [ + -1.0759315490722656, + -2.331512451171875 + ], + [ + -1.1145292520523071, + -2.291639804840088 + ], + [ + -1.1622941493988037, + -2.248897075653076 + ], + [ + -1.2225165367126465, + -2.2140045166015625 + ], + [ + -1.2719365358352661, + -2.1813507080078125 + ], + [ + -1.2894341945648193, + -2.171036720275879 + ], + [ + -1.3472622632980347, + -2.1215732097625732 + ], + [ + -1.3968429565429688, + -2.089432954788208 + ], + [ + -1.4502267837524414, + -2.0529072284698486 + ], + [ + -1.5092347860336304, + -2.025360107421875 + ], + [ + -1.5607056617736816, + -1.9986934661865234 + ], + [ + -1.6128932237625122, + -1.9748706817626953 + ], + [ + -1.6709580421447754, + -1.9640249013900757 + ], + [ + -1.6940981149673462, + -1.9094479084014893 + ], + [ + -1.7460169792175293, + -1.8862489461898804 + ], + [ + -1.7966976165771484, + -1.868022084236145 + ], + [ + -1.8403350114822388, + -1.8516536951065063 + ], + [ + -1.8861308097839355, + -1.8392239809036255 + ], + [ + -1.9307037591934204, + -1.816249132156372 + ], + [ + -1.9631290435791016, + -1.8177995681762695 + ], + [ + -1.997791051864624, + -1.7638733386993408 + ], + [ + -2.0294389724731445, + -1.7489277124404907 + ], + [ + -2.066037178039551, + -1.7296072244644165 + ], + [ + -2.090733528137207, + -1.7115967273712158 + ], + [ + -2.1171300411224365, + -1.6953872442245483 + ], + [ + -2.136131525039673, + -1.672394037246704 + ], + [ + -2.15145206451416, + -1.6547995805740356 + ], + [ + -2.1622302532196045, + -1.6164861917495728 + ], + [ + -2.2053627967834473, + -1.5762463808059692 + ], + [ + -2.2247374057769775, + -1.547599196434021 + ], + [ + -2.2357237339019775, + -1.518489956855774 + ], + [ + -2.2557544708251953, + -1.4751399755477905 + ], + [ + -2.776089906692505, + -1.91600501537323 + ], + [ + -2.8125431537628174, + -1.8636810779571533 + ], + [ + -2.849144697189331, + -1.815101146697998 + ], + [ + -2.8880953788757324, + -1.761527419090271 + ], + [ + -2.9302313327789307, + -1.708487629890442 + ], + [ + -2.960493803024292, + -1.6507318019866943 + ], + [ + -2.9924964904785156, + -1.5899238586425781 + ], + [ + -3.027252674102783, + -1.526869773864746 + ], + [ + -3.06462025642395, + -1.46726393699646 + ], + [ + -3.095201015472412, + -1.4013924598693848 + ], + [ + -3.128007411956787, + -1.3393831253051758 + ], + [ + -3.159210205078125, + -1.2721375226974487 + ], + [ + -1.9373687505722046, + -0.687658965587616 + ], + [ + -1.9567404985427856, + -0.6457244753837585 + ], + [ + -1.9677261114120483, + -0.6006501913070679 + ], + [ + -1.9837918281555176, + -0.5556674599647522 + ], + [ + -1.996430516242981, + -0.5113258957862854 + ], + [ + -2.007781744003296, + -0.4661876857280731 + ], + [ + -2.019171714782715, + -0.41807228326797485 + ], + [ + -2.029430627822876, + -0.37288954854011536 + ], + [ + -2.0376405715942383, + -0.32479122281074524 + ], + [ + -2.046046257019043, + -0.2766289710998535 + ], + [ + -2.0523316860198975, + -0.22935791313648224 + ], + [ + -2.0607080459594727, + -0.1817891001701355 + ], + [ + -2.0654187202453613, + -0.1333196610212326 + ], + [ + -2.070350408554077, + -0.08491188287734985 + ], + [ + -2.073803663253784, + -0.036153122782707214 + ], + [ + -2.0768747329711914, + 0.011757398955523968 + ], + [ + -2.078334093093872, + 0.06307854503393173 + ], + [ + -2.0797886848449707, + 0.11329557746648788 + ], + [ + -2.0792653560638428, + 0.16401098668575287 + ], + [ + -2.076643705368042, + 0.2158246785402298 + ], + [ + -2.0749804973602295, + 0.2677515745162964 + ], + [ + -2.0700361728668213, + 0.31993335485458374 + ], + [ + -2.064758539199829, + 0.3720895051956177 + ], + [ + -2.058629035949707, + 0.4212532043457031 + ], + [ + -2.049105167388916, + 0.4750703275203705 + ], + [ + -2.039303779602051, + 0.5249077081680298 + ], + [ + -2.0273003578186035, + 0.5786474943161011 + ], + [ + -2.011540651321411, + 0.6299139857292175 + ], + [ + -2.0000319480895996, + 0.6787533760070801 + ], + [ + -1.982649564743042, + 0.7373634576797485 + ], + [ + -1.9643205404281616, + 0.7834905982017517 + ], + [ + -1.9482014179229736, + 0.8389235734939575 + ], + [ + -1.9259650707244873, + 0.888401985168457 + ], + [ + -1.903965711593628, + 0.9372542500495911 + ], + [ + -1.8809194564819336, + 0.9865264296531677 + ], + [ + -1.8571441173553467, + 1.0310412645339966 + ], + [ + -1.8297030925750732, + 1.0749905109405518 + ], + [ + -1.7996293306350708, + 1.127497911453247 + ], + [ + -1.768414855003357, + 1.169742465019226 + ], + [ + -1.7392507791519165, + 1.2146421670913696 + ], + [ + -1.7002179622650146, + 1.2653138637542725 + ], + [ + -1.6753215789794922, + 1.3106189966201782 + ], + [ + -1.637405514717102, + 1.3534568548202515 + ], + [ + -1.6046419143676758, + 1.3953598737716675 + ], + [ + -1.5689152479171753, + 1.4374327659606934 + ], + [ + -1.5292876958847046, + 1.4817149639129639 + ], + [ + -1.4907194375991821, + 1.5149449110031128 + ], + [ + -1.4553582668304443, + 1.5537257194519043 + ], + [ + -1.4063055515289307, + 1.598868489265442 + ], + [ + -1.3688337802886963, + 1.629974603652954 + ], + [ + -1.323130488395691, + 1.6579619646072388 + ], + [ + -1.2863125801086426, + 1.6987625360488892 + ], + [ + -1.2382919788360596, + 1.7274837493896484 + ], + [ + -1.1951282024383545, + 1.759080171585083 + ], + [ + -1.15132737159729, + 1.7977052927017212 + ], + [ + -1.1095582246780396, + 1.8104259967803955 + ], + [ + -1.0585930347442627, + 1.840865969657898 + ], + [ + -1.024928331375122, + 1.8762376308441162 + ], + [ + -0.9766343235969543, + 1.8847450017929077 + ], + [ + -0.9207645654678345, + 1.9064584970474243 + ], + [ + -0.8830953240394592, + 1.925300121307373 + ], + [ + -0.8213379383087158, + 1.9521971940994263 + ], + [ + -0.7745769619941711, + 1.9671939611434937 + ], + [ + -0.7329925298690796, + 1.9801470041275024 + ], + [ + -0.6721110939979553, + 1.9983370304107666 + ], + [ + -0.6298264861106873, + 2.0183792114257812 + ], + [ + -0.5816912055015564, + 2.0260770320892334 + ], + [ + -0.5265570282936096, + 2.034031391143799 + ], + [ + -0.4700908660888672, + 2.0477805137634277 + ], + [ + -0.4192957580089569, + 2.057662010192871 + ], + [ + -0.38392138481140137, + 2.05867338180542 + ], + [ + -0.32581835985183716, + 2.0608699321746826 + ], + [ + -0.27377158403396606, + 2.058837652206421 + ], + [ + -0.2195213884115219, + 2.0168819427490234 + ], + [ + -0.17654797434806824, + 2.0714313983917236 + ], + [ + -0.1236642599105835, + 2.072991371154785 + ], + [ + -0.06580013036727905, + 2.066287040710449 + ], + [ + -0.011298995465040207, + 2.0659680366516113 + ], + [ + 0.04905214160680771, + 2.069998025894165 + ], + [ + 0.08712049573659897, + 2.0614261627197266 + ], + [ + 0.14548538625240326, + 2.061068058013916 + ], + [ + 0.18884845077991486, + 2.0493621826171875 + ], + [ + 0.23841571807861328, + 2.038118839263916 + ], + [ + 0.290791392326355, + 2.033129930496216 + ], + [ + 0.3410610258579254, + 2.029426097869873 + ], + [ + 0.3881123661994934, + 2.009795904159546 + ], + [ + 0.44929778575897217, + 1.988051414489746 + ], + [ + 0.4942169785499573, + 1.9731496572494507 + ], + [ + 0.5452936887741089, + 1.954063892364502 + ], + [ + 0.5970275402069092, + 1.9365123510360718 + ], + [ + 0.6509848237037659, + 1.924027442932129 + ], + [ + 0.6856898665428162, + 1.8882616758346558 + ], + [ + 0.7433739304542542, + 1.8762861490249634 + ], + [ + 0.7904962301254272, + 1.8530000448226929 + ], + [ + 0.8413768410682678, + 1.8205828666687012 + ], + [ + 0.8796847462654114, + 1.7954844236373901 + ], + [ + 0.9302541613578796, + 1.7645785808563232 + ], + [ + 0.9733292460441589, + 1.7385317087173462 + ], + [ + 1.0164016485214233, + 1.7120795249938965 + ], + [ + 1.0654385089874268, + 1.6723074913024902 + ], + [ + 1.1056432723999023, + 1.6361925601959229 + ], + [ + 1.151710033416748, + 1.6078670024871826 + ], + [ + 1.2016239166259766, + 1.585679531097412 + ], + [ + 1.247826099395752, + 1.547390341758728 + ], + [ + 1.2877600193023682, + 1.4986555576324463 + ], + [ + 1.3315609693527222, + 1.470244288444519 + ], + [ + 1.3716522455215454, + 1.4282230138778687 + ], + [ + 1.4004631042480469, + 1.394335389137268 + ], + [ + 1.4472661018371582, + 1.3543901443481445 + ], + [ + 1.4783884286880493, + 1.3118622303009033 + ], + [ + 1.5157989263534546, + 1.26576828956604 + ], + [ + 1.5556528568267822, + 1.223323941230774 + ], + [ + 1.5930302143096924, + 1.1771893501281738 + ], + [ + 1.6253530979156494, + 1.1353462934494019 + ], + [ + 1.6550267934799194, + 1.0851715803146362 + ], + [ + 1.6846950054168701, + 1.0348342657089233 + ], + [ + 1.71904456615448, + 0.991441547870636 + ], + [ + 1.7517995834350586, + 0.9367889761924744 + ], + [ + 1.77241051197052, + 0.8924040198326111 + ], + [ + 1.8028929233551025, + 0.8404454588890076 + ], + [ + 1.8293216228485107, + 0.7894368171691895 + ], + [ + 1.8525500297546387, + 0.7363119125366211 + ], + [ + 1.8742786645889282, + 0.6843820810317993 + ], + [ + 1.8973894119262695, + 0.6317936778068542 + ], + [ + 1.918625831604004, + 0.5770905017852783 + ], + [ + 1.9377092123031616, + 0.5240634679794312 + ], + [ + 1.9524019956588745, + 0.47013792395591736 + ], + [ + 1.9698057174682617, + 0.41376423835754395 + ], + [ + 1.9845064878463745, + 0.3598710298538208 + ], + [ + 1.998123049736023, + 0.3040426969528198 + ], + [ + 2.010262966156006, + 0.24980008602142334 + ], + [ + 2.0186808109283447, + 0.1933097094297409 + ], + [ + 2.027729034423828, + 0.1380096971988678 + ], + [ + 2.0365614891052246, + 0.0821828842163086 + ], + [ + 2.0436134338378906, + 0.027277732267975807 + ], + [ + 2.047438859939575, + -0.02850763499736786 + ], + [ + 2.052830696105957, + -0.08190131187438965 + ], + [ + 2.0559091567993164, + -0.13836929202079773 + ], + [ + 2.0554943084716797, + -0.1948576122522354 + ], + [ + 2.054262161254883, + -0.2429756224155426 + ], + [ + 2.0492851734161377, + -0.2982705533504486 + ], + [ + 2.0460047721862793, + -0.35397082567214966 + ], + [ + 2.0429322719573975, + -0.4116803705692291 + ], + [ + 2.0370543003082275, + -0.4687536656856537 + ], + [ + 2.0360848903656006, + -0.5216527581214905 + ], + [ + 2.022625207901001, + -0.5786315202713013 + ], + [ + 2.0135915279388428, + -0.6327869296073914 + ], + [ + 2.00388240814209, + -0.6865890622138977 + ], + [ + 1.9945049285888672, + -0.7365972399711609 + ], + [ + 1.9760324954986572, + -0.7906712293624878 + ], + [ + 1.9536018371582031, + -0.8428434729576111 + ], + [ + 1.9453186988830566, + -0.902852475643158 + ], + [ + 1.9226458072662354, + -0.9453467726707458 + ], + [ + 1.9068204164505005, + -0.9906208515167236 + ], + [ + 1.888498306274414, + -1.0431103706359863 + ], + [ + 1.8660893440246582, + -1.0983434915542603 + ], + [ + 1.8442203998565674, + -1.1417163610458374 + ], + [ + 1.8240623474121094, + -1.1944342851638794 + ], + [ + 1.7965861558914185, + -1.2372251749038696 + ], + [ + 1.7642314434051514, + -1.2820314168930054 + ], + [ + 1.7454888820648193, + -1.3286857604980469 + ], + [ + 1.716557264328003, + -1.3708795309066772 + ], + [ + 1.6803069114685059, + -1.4093809127807617 + ], + [ + 1.649004578590393, + -1.4622102975845337 + ], + [ + 1.6141331195831299, + -1.499295711517334 + ], + [ + 1.5843092203140259, + -1.5439730882644653 + ], + [ + 1.5537644624710083, + -1.5844804048538208 + ], + [ + 1.5203417539596558, + -1.6248613595962524 + ], + [ + 1.482574701309204, + -1.662704586982727 + ], + [ + 1.4335455894470215, + -1.6817632913589478 + ], + [ + 1.3933861255645752, + -1.7100132703781128 + ], + [ + 1.347791314125061, + -1.7424839735031128 + ], + [ + 1.3086135387420654, + -1.7782269716262817 + ], + [ + 1.2632516622543335, + -1.808411955833435 + ], + [ + 1.2263751029968262, + -1.836814522743225 + ], + [ + 1.1774564981460571, + -1.8698006868362427 + ], + [ + 1.14694344997406, + -1.8961422443389893 + ], + [ + 1.1060105562210083, + -1.9282045364379883 + ], + [ + 1.0613515377044678, + -1.9523619413375854 + ], + [ + 0.9767477512359619, + -1.9145909547805786 + ], + [ + 0.9367333054542542, + -1.9360671043395996 + ], + [ + 0.8941814303398132, + -1.9598908424377441 + ], + [ + 0.8521147966384888, + -2.000023603439331 + ], + [ + 0.8099852204322815, + -2.033231735229492 + ], + [ + 0.7777267098426819, + -2.082531452178955 + ], + [ + 0.7178225517272949, + -2.107881784439087 + ], + [ + 0.6608885526657104, + -2.1683475971221924 + ], + [ + 0.6100983619689941, + -2.200039863586426 + ], + [ + 0.5484849214553833, + -2.2216248512268066 + ], + [ + 0.45223158597946167, + -2.178671360015869 + ], + [ + 0.3617185056209564, + -2.184727191925049 + ], + [ + 0.2500578463077545, + -2.139714479446411 + ], + [ + 0.12207137048244476, + -2.120217800140381 + ], + [ + -0.03046162985265255, + -2.043266534805298 + ], + [ + -0.22456346452236176, + -1.8977487087249756 + ], + [ + -0.37734341621398926, + -1.7458083629608154 + ], + [ + -0.47449222207069397, + -1.6287363767623901 + ], + [ + -0.5308443307876587, + -1.5835742950439453 + ], + [ + -0.550518810749054, + -1.5726583003997803 + ], + [ + -0.592523992061615, + -1.8948761224746704 + ], + [ + -0.6113048195838928, + -1.9565513134002686 + ], + [ + -0.6465625762939453, + -1.9697359800338745 + ], + [ + -0.657958447933197, + -1.9584122896194458 + ], + [ + -0.67497318983078, + -1.9029390811920166 + ], + [ + -0.6709612011909485, + -1.8054695129394531 + ], + [ + -0.659602165222168, + -1.7241662740707397 + ], + [ + -0.6231850385665894, + -1.634726881980896 + ], + [ + -0.5898367166519165, + -1.5434861183166504 + ], + [ + -0.5447386503219604, + -1.4782150983810425 + ], + [ + -0.5066683292388916, + -1.4419256448745728 + ], + [ + -0.5777979493141174, + -1.5316094160079956 + ], + [ + -0.5480158925056458, + -1.4727426767349243 + ], + [ + -0.5296277403831482, + -1.4529491662979126 + ], + [ + -0.4932945966720581, + -1.4279478788375854 + ], + [ + -0.48626619577407837, + -1.446819543838501 + ], + [ + -0.5336313247680664, + -1.543454885482788 + ], + [ + -0.6351917386054993, + -1.693145990371704 + ], + [ + -0.7970563173294067, + -1.8774240016937256 + ], + [ + -0.9687163829803467, + -2.0555434226989746 + ], + [ + -1.0926519632339478, + -2.1540071964263916 + ], + [ + -1.1981594562530518, + -2.1783509254455566 + ], + [ + -1.2816945314407349, + -2.171433210372925 + ], + [ + -1.283292531967163, + -2.125459671020508 + ], + [ + -1.366607427597046, + -2.0996780395507812 + ], + [ + -1.4414464235305786, + -2.0701253414154053 + ], + [ + -1.5036375522613525, + -2.034614324569702 + ], + [ + -1.5689448118209839, + -1.9688081741333008 + ], + [ + -1.6448124647140503, + -1.9020062685012817 + ], + [ + -1.6848541498184204, + -1.8317625522613525 + ], + [ + -1.710188865661621, + -1.7287054061889648 + ], + [ + -1.7407164573669434, + -1.6552411317825317 + ], + [ + -1.753398060798645, + -1.5795811414718628 + ], + [ + -1.761881709098816, + -1.526234745979309 + ], + [ + -1.7891532182693481, + -1.4981086254119873 + ], + [ + -1.874226450920105, + -1.4860548973083496 + ], + [ + -1.9209702014923096, + -1.4840530157089233 + ], + [ + -1.9750984907150269, + -1.4783458709716797 + ], + [ + -2.040234088897705, + -1.4898481369018555 + ], + [ + -2.1138787269592285, + -1.4982445240020752 + ], + [ + -2.1910839080810547, + -1.5020952224731445 + ], + [ + -2.267169952392578, + -1.4967803955078125 + ], + [ + -2.332648277282715, + -1.4647438526153564 + ], + [ + -2.410879135131836, + -1.4315284490585327 + ], + [ + -2.4733102321624756, + -1.3849326372146606 + ], + [ + -2.5286028385162354, + -1.3286173343658447 + ], + [ + -2.5822184085845947, + -1.2601898908615112 + ], + [ + -2.62640380859375, + -1.195574402809143 + ], + [ + -2.684053659439087, + -1.1418659687042236 + ], + [ + -2.721994161605835, + -1.0776159763336182 + ], + [ + -2.7678463459014893, + -0.9992008805274963 + ], + [ + -2.8056368827819824, + -0.9273333549499512 + ], + [ + -2.8387606143951416, + -0.8552564978599548 + ], + [ + -2.8625783920288086, + -0.7832523584365845 + ], + [ + -2.87913179397583, + -0.7079869508743286 + ], + [ + -2.8984718322753906, + -0.6348634958267212 + ], + [ + -2.906923532485962, + -0.561181366443634 + ], + [ + -2.914639472961426, + -0.48678258061408997 + ], + [ + -2.9203436374664307, + -0.4115007817745209 + ], + [ + -2.9199202060699463, + -0.33925607800483704 + ], + [ + -3.014723062515259, + -0.25158438086509705 + ], + [ + -3.0243592262268066, + -0.17927449941635132 + ], + [ + -3.030862808227539, + -0.09946616739034653 + ], + [ + -3.0365350246429443, + -0.020055940374732018 + ], + [ + -3.0375051498413086, + 0.059202998876571655 + ], + [ + -3.0339345932006836, + 0.13518790900707245 + ], + [ + -3.029900550842285, + 0.2117515504360199 + ], + [ + -3.0234715938568115, + 0.2890035808086395 + ], + [ + -3.0095951557159424, + 0.36305946111679077 + ], + [ + -3.003141164779663, + 0.43939393758773804 + ], + [ + -2.9896178245544434, + 0.5112302303314209 + ], + [ + -2.974623680114746, + 0.5876010060310364 + ], + [ + -2.9586071968078613, + 0.6611071228981018 + ], + [ + -2.9775683879852295, + 0.7690820097923279 + ], + [ + -2.966081380844116, + 0.8362208604812622 + ], + [ + -2.9400296211242676, + 0.9062945246696472 + ], + [ + -2.922243118286133, + 0.9789568185806274 + ], + [ + -2.9054222106933594, + 1.0485942363739014 + ], + [ + -2.879047393798828, + 1.123626947402954 + ], + [ + -2.847252130508423, + 1.1961723566055298 + ], + [ + -2.833730697631836, + 1.268467903137207 + ], + [ + -2.8087072372436523, + 1.3499864339828491 + ], + [ + -2.7563562393188477, + 1.4295743703842163 + ], + [ + -2.7128143310546875, + 1.50718355178833 + ], + [ + -2.6596157550811768, + 1.587365746498108 + ], + [ + -2.592546224594116, + 1.6452574729919434 + ], + [ + -2.5268120765686035, + 1.701596736907959 + ], + [ + -2.4737961292266846, + 1.7574485540390015 + ], + [ + -2.4005465507507324, + 1.8056174516677856 + ], + [ + -2.376152276992798, + 1.8353793621063232 + ], + [ + -2.3139841556549072, + 1.8659106492996216 + ], + [ + -2.2776949405670166, + 1.9160854816436768 + ], + [ + -2.224914789199829, + 1.9407954216003418 + ], + [ + -2.190617322921753, + 1.9856469631195068 + ], + [ + -2.127591371536255, + 2.0119316577911377 + ], + [ + -2.0631816387176514, + 2.0585265159606934 + ], + [ + -2.0183942317962646, + 2.1005406379699707 + ], + [ + -1.9596422910690308, + 2.1306276321411133 + ], + [ + -1.9052480459213257, + 2.1633965969085693 + ], + [ + -1.8515745401382446, + 2.194302558898926 + ], + [ + -1.7892173528671265, + 2.228243827819824 + ], + [ + -1.721562147140503, + 2.239980459213257 + ], + [ + -1.6727690696716309, + 2.2685039043426514 + ], + [ + -1.6132731437683105, + 2.281430244445801 + ], + [ + -1.5536688566207886, + 2.30460524559021 + ], + [ + -1.5043140649795532, + 2.319028854370117 + ], + [ + -1.448581337928772, + 2.3278157711029053 + ], + [ + -1.40326988697052, + 2.3259804248809814 + ], + [ + -1.3372397422790527, + 2.3336005210876465 + ], + [ + -1.284512996673584, + 2.3449981212615967 + ], + [ + -1.2397150993347168, + 2.3501384258270264 + ], + [ + -1.202107548713684, + 2.3505489826202393 + ], + [ + -1.1415570974349976, + 2.3553671836853027 + ], + [ + -1.1036701202392578, + 2.3625011444091797 + ], + [ + -1.0473092794418335, + 2.365088939666748 + ], + [ + -1.009000301361084, + 2.372141122817993 + ], + [ + -0.9684298634529114, + 2.3692705631256104 + ], + [ + -0.9128687977790833, + 2.3951046466827393 + ], + [ + -0.9000723958015442, + 2.3940954208374023 + ], + [ + -0.8488529920578003, + 2.4052839279174805 + ], + [ + -0.8163118362426758, + 2.4254302978515625 + ], + [ + -0.760624349117279, + 2.43585467338562 + ], + [ + -0.7355799674987793, + 2.436842203140259 + ], + [ + -0.6761532425880432, + 2.44765567779541 + ], + [ + -0.6398229002952576, + 2.4737274646759033 + ], + [ + -0.5805181264877319, + 2.4792304039001465 + ], + [ + -0.5378209352493286, + 2.4789812564849854 + ], + [ + -0.5035869479179382, + 2.499934673309326 + ], + [ + -0.4525150954723358, + 2.492938756942749 + ], + [ + -0.38988593220710754, + 2.5283310413360596 + ], + [ + -0.3520790636539459, + 2.524868965148926 + ], + [ + -0.2947022318840027, + 2.5402474403381348 + ], + [ + -0.22233811020851135, + 2.541107416152954 + ], + [ + -0.18316896259784698, + 2.554361343383789 + ], + [ + -0.12354230880737305, + 2.551254987716675 + ], + [ + -0.06236350163817406, + 2.5415234565734863 + ], + [ + -0.0015733469044789672, + 2.5383076667785645 + ], + [ + 0.05565869063138962, + 2.5294928550720215 + ], + [ + 0.11286536604166031, + 2.541764974594116 + ], + [ + 0.1730954796075821, + 2.5484516620635986 + ], + [ + 0.2533372640609741, + 2.536052703857422 + ], + [ + 0.29477474093437195, + 2.5321707725524902 + ], + [ + 0.33681246638298035, + 2.5362038612365723 + ], + [ + 0.40637996792793274, + 2.5310583114624023 + ], + [ + 0.4790002107620239, + 2.511387348175049 + ], + [ + 0.5379141569137573, + 2.5016205310821533 + ], + [ + 0.6020739674568176, + 2.4903693199157715 + ], + [ + 0.662628710269928, + 2.4692440032958984 + ], + [ + 0.7383211851119995, + 2.4548137187957764 + ], + [ + 0.7877758741378784, + 2.4772934913635254 + ], + [ + 0.8612822890281677, + 2.4367876052856445 + ], + [ + 0.9310339093208313, + 2.41324520111084 + ], + [ + 0.9836178421974182, + 2.3841257095336914 + ], + [ + 1.0522150993347168, + 2.362483263015747 + ], + [ + 1.1256319284439087, + 2.3406782150268555 + ], + [ + 1.1893442869186401, + 2.313577175140381 + ], + [ + 1.248160481452942, + 2.2843594551086426 + ], + [ + 1.3153645992279053, + 2.243107557296753 + ], + [ + 1.3786572217941284, + 2.2158265113830566 + ], + [ + 1.4311448335647583, + 2.1746737957000732 + ], + [ + 1.513066053390503, + 2.138443946838379 + ], + [ + 1.561434030532837, + 2.123777389526367 + ], + [ + 1.6146823167800903, + 2.070502758026123 + ], + [ + 1.681473970413208, + 2.0239615440368652 + ], + [ + 1.7344552278518677, + 1.9881253242492676 + ], + [ + 1.8040094375610352, + 1.9375382661819458 + ], + [ + 1.8609315156936646, + 1.8893376588821411 + ], + [ + 1.919103980064392, + 1.847089171409607 + ], + [ + 1.9807238578796387, + 1.7984771728515625 + ], + [ + 2.0307517051696777, + 1.7399605512619019 + ], + [ + 2.086857318878174, + 1.6887915134429932 + ], + [ + 2.1521847248077393, + 1.6333191394805908 + ], + [ + 2.1871964931488037, + 1.5826473236083984 + ], + [ + 2.246978998184204, + 1.5443059206008911 + ], + [ + 2.2898635864257812, + 1.4812337160110474 + ], + [ + 2.337564468383789, + 1.4218977689743042 + ], + [ + 2.3825016021728516, + 1.36211359500885 + ], + [ + 2.433154821395874, + 1.2955820560455322 + ], + [ + 2.4753410816192627, + 1.2363232374191284 + ], + [ + 2.517812728881836, + 1.1690304279327393 + ], + [ + 2.56685733795166, + 1.105243444442749 + ], + [ + 2.614696502685547, + 1.0327651500701904 + ], + [ + 2.656031608581543, + 0.9662779569625854 + ], + [ + 2.6932857036590576, + 0.8977018594741821 + ], + [ + 2.7311902046203613, + 0.8329114317893982 + ], + [ + 2.7676937580108643, + 0.759700357913971 + ], + [ + 2.798693895339966, + 0.6926404237747192 + ], + [ + 2.8273799419403076, + 0.6188287138938904 + ], + [ + 2.8561201095581055, + 0.5407487750053406 + ], + [ + 2.8933780193328857, + 0.4619722366333008 + ], + [ + 2.9210941791534424, + 0.37715575098991394 + ], + [ + 2.9469153881073, + 0.29472753405570984 + ], + [ + 2.972013235092163, + 0.20958900451660156 + ], + [ + 2.997572183609009, + 0.1193346306681633 + ], + [ + 3.0202105045318604, + 0.02736293151974678 + ], + [ + 3.03875732421875, + -0.060730356723070145 + ], + [ + 3.058960199356079, + -0.14332455396652222 + ], + [ + 3.062605619430542, + -0.2327321320772171 + ], + [ + 3.074321746826172, + -0.32316166162490845 + ], + [ + 3.0817067623138428, + -0.42629995942115784 + ], + [ + 3.0900368690490723, + -0.5090985298156738 + ], + [ + 3.096859931945801, + -0.6048561334609985 + ], + [ + 3.098104476928711, + -0.7021270990371704 + ], + [ + 3.1053202152252197, + -0.7940771579742432 + ], + [ + 3.0891177654266357, + -0.9064589738845825 + ], + [ + 3.0887906551361084, + -1.0061686038970947 + ], + [ + 3.08528733253479, + -1.1122899055480957 + ], + [ + 3.0815200805664062, + -1.221608281135559 + ], + [ + 3.0674517154693604, + -1.3348989486694336 + ], + [ + 3.081165075302124, + -1.4455362558364868 + ], + [ + 2.999358654022217, + -1.5402673482894897 + ], + [ + 2.970099687576294, + -1.6325130462646484 + ], + [ + 2.9328720569610596, + -1.7626663446426392 + ], + [ + 2.905538320541382, + -1.8415330648422241 + ], + [ + 2.876554012298584, + -1.9632959365844727 + ], + [ + 2.812915086746216, + -2.084019660949707 + ], + [ + 2.7611076831817627, + -2.193690776824951 + ], + [ + 2.717302083969116, + -2.2968392372131348 + ], + [ + 2.665426015853882, + -2.4135353565216064 + ], + [ + 2.5908195972442627, + -2.5151913166046143 + ], + [ + 2.497185468673706, + -2.623262405395508 + ], + [ + 2.3934168815612793, + -2.7428183555603027 + ], + [ + 2.275559425354004, + -2.844158887863159 + ], + [ + 2.205986738204956, + -2.9018936157226562 + ], + [ + 2.1243228912353516, + -2.9838058948516846 + ], + [ + 2.024345636367798, + -3.0774917602539062 + ], + [ + 1.9042062759399414, + -3.1999130249023438 + ], + [ + 1.7818541526794434, + -3.2654149532318115 + ], + [ + 1.6864264011383057, + -3.3660154342651367 + ], + [ + 1.5665850639343262, + -3.4253852367401123 + ], + [ + 1.4279528856277466, + -3.513599157333374 + ], + [ + 1.2642351388931274, + -3.575394630432129 + ], + [ + 1.0790010690689087, + -3.6155807971954346 + ], + [ + 0.9043346047401428, + -3.6323413848876953 + ], + [ + 0.7109134793281555, + -3.6271824836730957 + ], + [ + 0.5092260241508484, + -3.641875982284546 + ], + [ + 0.2658410966396332, + -3.651787519454956 + ], + [ + 0.3486539423465729, + -3.760416269302368 + ], + [ + 0.216196671128273, + -3.8394291400909424 + ], + [ + 0.09202255308628082, + -3.9004604816436768 + ], + [ + -0.07208014279603958, + -3.9429306983947754 + ], + [ + -0.2448507845401764, + -3.946885108947754 + ], + [ + -0.37714168429374695, + -4.022502422332764 + ], + [ + -0.543254554271698, + -4.01075553894043 + ], + [ + -0.719575047492981, + -3.956655502319336 + ], + [ + -0.9022912383079529, + -3.9400041103363037 + ], + [ + -1.087738037109375, + -3.880995750427246 + ], + [ + -1.2733289003372192, + -3.8258161544799805 + ], + [ + -1.4660786390304565, + -3.7293763160705566 + ], + [ + -3.050274610519409, + -7.170773029327393 + ], + [ + -3.420567512512207, + -6.978158950805664 + ], + [ + -3.4528133869171143, + -7.511008262634277 + ], + [ + -3.7497732639312744, + -7.541960716247559 + ], + [ + -4.084168434143066, + -7.520591735839844 + ], + [ + -4.372245788574219, + -7.478677749633789 + ], + [ + -4.812235355377197, + -7.379395008087158 + ], + [ + -5.051166534423828, + -7.318378925323486 + ], + [ + -5.396759033203125, + -7.158172130584717 + ], + [ + -5.660764694213867, + -6.917031764984131 + ], + [ + -5.955574035644531, + -6.7251081466674805 + ], + [ + -6.193223476409912, + -6.464974880218506 + ], + [ + -6.4657301902771, + -6.206353664398193 + ], + [ + -6.665205955505371, + -5.89431095123291 + ], + [ + -6.8499555587768555, + -5.594375133514404 + ], + [ + -7.055996417999268, + -5.190771579742432 + ], + [ + -7.47048282623291, + -5.671463489532471 + ], + [ + -7.6744208335876465, + -5.461728096008301 + ], + [ + -7.947720050811768, + -5.2285542488098145 + ], + [ + -8.123114585876465, + -4.92912483215332 + ], + [ + -8.340371131896973, + -4.779562950134277 + ], + [ + -8.496562004089355, + -4.464376926422119 + ], + [ + -8.656535148620605, + -4.142075061798096 + ], + [ + -8.796727180480957, + -3.9076247215270996 + ], + [ + -8.947331428527832, + -3.6078040599823 + ], + [ + -9.025215148925781, + -3.3593945503234863 + ], + [ + -9.127816200256348, + -3.039128065109253 + ], + [ + -9.191609382629395, + -2.76166033744812 + ], + [ + -9.289085388183594, + -2.4623420238494873 + ], + [ + -9.303400039672852, + -2.2000296115875244 + ], + [ + -9.345283508300781, + -1.8965966701507568 + ], + [ + -9.580484390258789, + -1.6555150747299194 + ], + [ + -9.60629940032959, + -1.3843989372253418 + ], + [ + -9.66955280303955, + -1.0827698707580566 + ], + [ + -9.65463638305664, + -0.8437310457229614 + ], + [ + -9.673254013061523, + -0.5553527474403381 + ], + [ + -9.690669059753418, + -0.30570414662361145 + ], + [ + -9.69246768951416, + -0.04600979760289192 + ], + [ + -9.641256332397461, + 0.23859380185604095 + ], + [ + -9.639616012573242, + 0.4528926908969879 + ], + [ + -9.621818542480469, + 0.7170064449310303 + ], + [ + -9.579920768737793, + 0.9591527581214905 + ], + [ + -9.54615592956543, + 1.1940033435821533 + ], + [ + -9.511819839477539, + 1.4324532747268677 + ], + [ + -9.496679306030273, + 1.7128961086273193 + ], + [ + -9.425264358520508, + 1.9186654090881348 + ] + ], + "total_points": 1000 +} \ No newline at end of file diff --git a/vna_system/calibration/s11_start100_stop8800_points1000_bw1khz/еуыеуые/open_metadata.json b/vna_system/calibration/s11_start100_stop8800_points1000_bw1khz/еуыеуые/open_metadata.json new file mode 100644 index 0000000..b25c7a2 --- /dev/null +++ b/vna_system/calibration/s11_start100_stop8800_points1000_bw1khz/еуыеуые/open_metadata.json @@ -0,0 +1,16 @@ +{ + "preset": { + "filename": "s11_start100_stop8800_points1000_bw1khz.bin", + "mode": "s11", + "start_freq": 100000000.0, + "stop_freq": 8800000000.0, + "points": 1000, + "bandwidth": 1000.0 + }, + "calibration_name": "еуыеуые", + "standard": "open", + "sweep_number": 10, + "sweep_timestamp": 1758896372.20023, + "created_timestamp": "2025-09-26T17:19:50.015286", + "total_points": 1000 +} \ No newline at end of file diff --git a/vna_system/calibration/s11_start100_stop8800_points1000_bw1khz/еуыеуые/short.json b/vna_system/calibration/s11_start100_stop8800_points1000_bw1khz/еуыеуые/short.json new file mode 100644 index 0000000..02a24fe --- /dev/null +++ b/vna_system/calibration/s11_start100_stop8800_points1000_bw1khz/еуыеуые/short.json @@ -0,0 +1,4007 @@ +{ + "sweep_number": 13, + "timestamp": 1758896378.4093437, + "points": [ + [ + -2.673182249069214, + 0.4526049792766571 + ], + [ + -2.664034366607666, + 0.5132845640182495 + ], + [ + -2.655735731124878, + 0.5743225812911987 + ], + [ + -2.6458590030670166, + 0.6349809765815735 + ], + [ + -2.634361982345581, + 0.695916473865509 + ], + [ + -3.4052376747131348, + 0.9254970550537109 + ], + [ + -3.395155906677246, + 1.005311369895935 + ], + [ + -3.374450206756592, + 1.0801655054092407 + ], + [ + -3.3507912158966064, + 1.15727961063385 + ], + [ + -3.3300724029541016, + 1.235087513923645 + ], + [ + -3.3067891597747803, + 1.3097753524780273 + ], + [ + -3.283984422683716, + 1.3847987651824951 + ], + [ + -3.25875186920166, + 1.4610011577606201 + ], + [ + -3.2363553047180176, + 1.5382307767868042 + ], + [ + -3.2065091133117676, + 1.6121679544448853 + ], + [ + -3.1773478984832764, + 1.6901707649230957 + ], + [ + -3.1499924659729004, + 1.7628757953643799 + ], + [ + -3.1139655113220215, + 1.833876132965088 + ], + [ + -3.0769565105438232, + 1.914526343345642 + ], + [ + -3.042905330657959, + 1.9799810647964478 + ], + [ + -3.0091936588287354, + 2.0521206855773926 + ], + [ + -2.9654510021209717, + 2.1246461868286133 + ], + [ + -2.9285709857940674, + 2.196747303009033 + ], + [ + -2.8818817138671875, + 2.2762978076934814 + ], + [ + -2.845154285430908, + 2.344907522201538 + ], + [ + -2.8012142181396484, + 2.417104959487915 + ], + [ + -2.7593495845794678, + 2.485837936401367 + ], + [ + -2.708976984024048, + 2.557717800140381 + ], + [ + -2.6601366996765137, + 2.630138874053955 + ], + [ + -2.611405849456787, + 2.707428455352783 + ], + [ + -2.5598292350769043, + 2.7706453800201416 + ], + [ + -2.5039029121398926, + 2.839930772781372 + ], + [ + -2.4566142559051514, + 2.9033286571502686 + ], + [ + -2.3961703777313232, + 2.9676992893218994 + ], + [ + -2.333775043487549, + 3.034329414367676 + ], + [ + -2.2696292400360107, + 3.100053310394287 + ], + [ + -2.19866943359375, + 3.1644294261932373 + ], + [ + -2.134021759033203, + 3.2304770946502686 + ], + [ + -2.0648105144500732, + 3.29374361038208 + ], + [ + -1.9910874366760254, + 3.3556854724884033 + ], + [ + -1.922908902168274, + 3.4146387577056885 + ], + [ + -1.8499655723571777, + 3.4767093658447266 + ], + [ + -1.7743914127349854, + 3.536162853240967 + ], + [ + -1.7014591693878174, + 3.592197895050049 + ], + [ + -1.615335464477539, + 3.649122953414917 + ], + [ + -1.5358545780181885, + 3.7070083618164062 + ], + [ + -1.445051670074463, + 3.7634963989257812 + ], + [ + -1.3620245456695557, + 3.815241813659668 + ], + [ + -1.2775665521621704, + 3.8688762187957764 + ], + [ + -1.1896209716796875, + 3.9140381813049316 + ], + [ + -1.0998587608337402, + 3.9655003547668457 + ], + [ + -0.9990155696868896, + 4.009896755218506 + ], + [ + -0.9009591937065125, + 4.054059028625488 + ], + [ + -0.807556688785553, + 4.105104923248291 + ], + [ + -0.7030119299888611, + 4.147378444671631 + ], + [ + -0.6066522598266602, + 4.1889801025390625 + ], + [ + -0.5006924271583557, + 4.220681667327881 + ], + [ + -0.3956588804721832, + 4.258335113525391 + ], + [ + -0.28977978229522705, + 4.28523063659668 + ], + [ + -0.18176065385341644, + 4.3160881996154785 + ], + [ + -0.05864642187952995, + 4.342520713806152 + ], + [ + 0.0496070459485054, + 4.363901615142822 + ], + [ + 0.17840063571929932, + 4.385037899017334 + ], + [ + 0.2935994565486908, + 4.398932456970215 + ], + [ + 0.4185701906681061, + 4.4109721183776855 + ], + [ + 0.5423102974891663, + 4.418863296508789 + ], + [ + 0.66508549451828, + 4.425356388092041 + ], + [ + 0.7866483926773071, + 4.424631595611572 + ], + [ + 0.9205178618431091, + 4.4424262046813965 + ], + [ + 1.046618103981018, + 4.436233997344971 + ], + [ + 1.1802787780761719, + 4.4440741539001465 + ], + [ + 1.3159068822860718, + 4.417740821838379 + ], + [ + 1.460447072982788, + 4.3973188400268555 + ], + [ + 1.5849770307540894, + 4.380573272705078 + ], + [ + 1.7220685482025146, + 4.357413291931152 + ], + [ + 1.8599116802215576, + 4.320777416229248 + ], + [ + 1.9986697435379028, + 4.294105529785156 + ], + [ + 2.1329915523529053, + 4.255446434020996 + ], + [ + 2.2709624767303467, + 4.2123188972473145 + ], + [ + 2.3979651927948, + 4.151188850402832 + ], + [ + 2.5227243900299072, + 4.108695030212402 + ], + [ + 2.659486770629883, + 4.052158355712891 + ], + [ + 2.7887051105499268, + 3.987877130508423 + ], + [ + 2.906116247177124, + 3.919907331466675 + ], + [ + 3.0215811729431152, + 3.849973201751709 + ], + [ + 3.1460373401641846, + 3.782819986343384 + ], + [ + 3.267817735671997, + 3.7028074264526367 + ], + [ + 3.378697156906128, + 3.618018627166748 + ], + [ + 3.495452404022217, + 3.5282583236694336 + ], + [ + 3.6076154708862305, + 3.4318997859954834 + ], + [ + 3.7200639247894287, + 3.334930419921875 + ], + [ + 3.8343679904937744, + 3.231701612472534 + ], + [ + 3.942572832107544, + 3.1166374683380127 + ], + [ + 4.039266109466553, + 2.99684739112854 + ], + [ + 4.153839588165283, + 2.8691771030426025 + ], + [ + 4.257083415985107, + 2.742621421813965 + ], + [ + 4.353559970855713, + 2.617739677429199 + ], + [ + 4.441986083984375, + 2.48197078704834 + ], + [ + 4.52557373046875, + 2.3450729846954346 + ], + [ + 4.591869354248047, + 2.2022571563720703 + ], + [ + 4.665722846984863, + 2.0598435401916504 + ], + [ + 4.738101959228516, + 1.9026832580566406 + ], + [ + 4.794832706451416, + 1.7572259902954102 + ], + [ + 4.845154762268066, + 1.5968844890594482 + ], + [ + 4.90429162979126, + 1.438180923461914 + ], + [ + 4.938620090484619, + 1.271759033203125 + ], + [ + 4.973180770874023, + 1.1124613285064697 + ], + [ + 5.01839017868042, + 0.941400945186615 + ], + [ + 5.032951354980469, + 0.7707509994506836 + ], + [ + 5.0646185874938965, + 0.6067417860031128 + ], + [ + 5.078636169433594, + 0.43243736028671265 + ], + [ + 5.088210582733154, + 0.2722599506378174 + ], + [ + 5.077387809753418, + 0.10976143926382065 + ], + [ + 5.076402187347412, + -0.056312985718250275 + ], + [ + 5.058142185211182, + -0.21401184797286987 + ], + [ + 5.026561737060547, + -0.34496769309043884 + ], + [ + 4.999899387359619, + -0.49822258949279785 + ], + [ + 4.967226028442383, + -0.645676851272583 + ], + [ + 4.923960208892822, + -0.7984857559204102 + ], + [ + 4.867866516113281, + -0.9335814714431763 + ], + [ + 4.809844017028809, + -1.0838066339492798 + ], + [ + 4.741298675537109, + -1.2189158201217651 + ], + [ + 4.668980121612549, + -1.350603461265564 + ], + [ + 4.602053642272949, + -1.4819140434265137 + ], + [ + 4.514710903167725, + -1.620599627494812 + ], + [ + 4.4300537109375, + -1.7464057207107544 + ], + [ + 4.339680194854736, + -1.8790059089660645 + ], + [ + 4.237917900085449, + -2.0014591217041016 + ], + [ + 4.148985862731934, + -2.139927625656128 + ], + [ + 4.056626319885254, + -2.2732622623443604 + ], + [ + 3.9556679725646973, + -2.3923707008361816 + ], + [ + 3.857477903366089, + -2.51560378074646 + ], + [ + 3.7648003101348877, + -2.629596710205078 + ], + [ + 3.6510813236236572, + -2.739619731903076 + ], + [ + 3.5633087158203125, + -2.841643810272217 + ], + [ + 3.4544761180877686, + -2.9344141483306885 + ], + [ + 3.3673555850982666, + -3.024390459060669 + ], + [ + 3.2654435634613037, + -3.0797317028045654 + ], + [ + 3.164827346801758, + -3.150209426879883 + ], + [ + 3.063897132873535, + -3.1965482234954834 + ], + [ + 2.952057123184204, + -3.2245943546295166 + ], + [ + 2.856443405151367, + -3.2749805450439453 + ], + [ + 2.7456510066986084, + -3.2942886352539062 + ], + [ + 2.6304144859313965, + -3.3073441982269287 + ], + [ + 2.5269925594329834, + -3.3382651805877686 + ], + [ + 2.415584087371826, + -3.3440864086151123 + ], + [ + 2.297959089279175, + -3.3568880558013916 + ], + [ + 2.2026796340942383, + -3.3695178031921387 + ], + [ + 2.0875866413116455, + -3.373654365539551 + ], + [ + 1.9661145210266113, + -3.3805530071258545 + ], + [ + 1.8646941184997559, + -3.3887622356414795 + ], + [ + 1.7419407367706299, + -3.4012157917022705 + ], + [ + 1.6218788623809814, + -3.4237658977508545 + ], + [ + 1.4743952751159668, + -3.6106114387512207 + ], + [ + 1.3657457828521729, + -3.6342482566833496 + ], + [ + 1.2740747928619385, + -3.6237294673919678 + ], + [ + 1.1761966943740845, + -3.6070613861083984 + ], + [ + 1.0804895162582397, + -3.618767738342285 + ], + [ + 0.9801827669143677, + -3.5969154834747314 + ], + [ + 0.8770717978477478, + -3.60530686378479 + ], + [ + 0.781680703163147, + -3.581618547439575 + ], + [ + 0.6918584108352661, + -3.5595405101776123 + ], + [ + 0.5921069979667664, + -3.5595414638519287 + ], + [ + 0.5056436061859131, + -3.531352996826172 + ], + [ + 0.42071250081062317, + -3.5172648429870605 + ], + [ + 0.3273966312408447, + -3.500552177429199 + ], + [ + 0.24874982237815857, + -3.4709088802337646 + ], + [ + 0.16427558660507202, + -3.4581565856933594 + ], + [ + 0.09205229580402374, + -3.4318172931671143 + ], + [ + 0.008539530448615551, + -3.407423973083496 + ], + [ + -0.06903084367513657, + -3.384385108947754 + ], + [ + -0.13350863754749298, + -3.3539860248565674 + ], + [ + -0.20439986884593964, + -3.3272244930267334 + ], + [ + -0.2684410810470581, + -3.30094838142395 + ], + [ + -0.34321293234825134, + -3.2741923332214355 + ], + [ + -0.39875319600105286, + -3.2431230545043945 + ], + [ + -0.4613335132598877, + -3.210358142852783 + ], + [ + -0.5248931050300598, + -3.185352325439453 + ], + [ + -0.5931600332260132, + -3.1653990745544434 + ], + [ + -0.6398776769638062, + -3.1249661445617676 + ], + [ + -0.7001591920852661, + -3.0916523933410645 + ], + [ + -0.7636449933052063, + -3.063239097595215 + ], + [ + -0.8128881454467773, + -3.0300707817077637 + ], + [ + -0.8683986067771912, + -2.998833179473877 + ], + [ + -0.9263790249824524, + -2.965181350708008 + ], + [ + -0.9759135842323303, + -2.922837734222412 + ], + [ + -1.0341508388519287, + -2.8908348083496094 + ], + [ + -1.0867713689804077, + -2.856797218322754 + ], + [ + -1.1402214765548706, + -2.827364444732666 + ], + [ + -1.186988353729248, + -2.7884135246276855 + ], + [ + -1.232167363166809, + -2.757401943206787 + ], + [ + -1.2791557312011719, + -2.7225444316864014 + ], + [ + -1.3236093521118164, + -2.6816565990448 + ], + [ + -1.3567805290222168, + -2.6507019996643066 + ], + [ + -1.4071881771087646, + -2.610079288482666 + ], + [ + -1.446117877960205, + -2.5702223777770996 + ], + [ + -1.4979808330535889, + -2.5301907062530518 + ], + [ + -1.5319688320159912, + -2.486398696899414 + ], + [ + -1.5736669301986694, + -2.4392106533050537 + ], + [ + -1.6006675958633423, + -2.394244432449341 + ], + [ + -1.6032633781433105, + -2.3215057849884033 + ], + [ + -1.6616684198379517, + -2.2746148109436035 + ], + [ + -1.7068790197372437, + -2.223567247390747 + ], + [ + -1.7490354776382446, + -2.1755223274230957 + ], + [ + -1.7988929748535156, + -2.1212801933288574 + ], + [ + -1.8376071453094482, + -2.074448585510254 + ], + [ + -1.8857108354568481, + -2.0204172134399414 + ], + [ + -1.92911696434021, + -1.9718801975250244 + ], + [ + -1.9663833379745483, + -1.9226932525634766 + ], + [ + -2.0039913654327393, + -1.868977427482605 + ], + [ + -2.047943353652954, + -1.8163002729415894 + ], + [ + -2.080768346786499, + -1.7732667922973633 + ], + [ + -2.1188628673553467, + -1.7129542827606201 + ], + [ + -2.1526827812194824, + -1.6670058965682983 + ], + [ + -2.1762266159057617, + -1.6211575269699097 + ], + [ + -2.2120344638824463, + -1.5595113039016724 + ], + [ + -2.2398288249969482, + -1.5118365287780762 + ], + [ + -2.260369062423706, + -1.4670323133468628 + ], + [ + -2.2859272956848145, + -1.4121975898742676 + ], + [ + -2.3089702129364014, + -1.3657389879226685 + ], + [ + -2.321678400039673, + -1.319008708000183 + ], + [ + -2.34130859375, + -1.2638022899627686 + ], + [ + -2.358565330505371, + -1.2190756797790527 + ], + [ + -2.367945432662964, + -1.1691783666610718 + ], + [ + -2.3798136711120605, + -1.122207522392273 + ], + [ + -2.3943703174591064, + -1.072206974029541 + ], + [ + -2.400977611541748, + -1.0242115259170532 + ], + [ + -2.4109771251678467, + -0.9730558395385742 + ], + [ + -2.421635627746582, + -0.9196767807006836 + ], + [ + -2.4310638904571533, + -0.8683810234069824 + ], + [ + -2.4374585151672363, + -0.813830554485321 + ], + [ + -2.4480936527252197, + -0.7566489577293396 + ], + [ + -2.4574458599090576, + -0.6995614767074585 + ], + [ + -2.469574213027954, + -0.6409438252449036 + ], + [ + -2.4798359870910645, + -0.5829693675041199 + ], + [ + -2.4901702404022217, + -0.519244372844696 + ], + [ + -2.503509998321533, + -0.4582385718822479 + ], + [ + -2.5134944915771484, + -0.3993208408355713 + ], + [ + -2.525212526321411, + -0.33690086007118225 + ], + [ + -2.531342029571533, + -0.27798953652381897 + ], + [ + -2.5383381843566895, + -0.2205219268798828 + ], + [ + -2.5438132286071777, + -0.16239959001541138 + ], + [ + -2.530621290206909, + -0.10677018761634827 + ], + [ + -2.526913642883301, + -0.053873252123594284 + ], + [ + -2.5224623680114746, + 0.0016842411132529378 + ], + [ + -2.517287254333496, + 0.0572863332927227 + ], + [ + -2.5091207027435303, + 0.11101123690605164 + ], + [ + -2.501587152481079, + 0.16734004020690918 + ], + [ + -2.498530626296997, + 0.22565042972564697 + ], + [ + -2.4925310611724854, + 0.28695037961006165 + ], + [ + -2.4820055961608887, + 0.3394150137901306 + ], + [ + -2.4736030101776123, + 0.3964601457118988 + ], + [ + -2.464576244354248, + 0.4571801424026489 + ], + [ + -2.457829236984253, + 0.5174599289894104 + ], + [ + -2.446819543838501, + 0.5789187550544739 + ], + [ + -2.433417797088623, + 0.6292660236358643 + ], + [ + -2.4219560623168945, + 0.6928188800811768 + ], + [ + -2.4111437797546387, + 0.7525805830955505 + ], + [ + -2.404707431793213, + 0.8153723478317261 + ], + [ + -2.3971235752105713, + 0.8778687119483948 + ], + [ + -2.3757927417755127, + 0.9285744428634644 + ], + [ + -2.3689565658569336, + 0.9883994460105896 + ], + [ + -2.356597661972046, + 1.047275424003601 + ], + [ + -2.3498377799987793, + 1.105019211769104 + ], + [ + -2.3425841331481934, + 1.156809687614441 + ], + [ + -2.335012435913086, + 1.2025091648101807 + ], + [ + -2.310600757598877, + 1.2657932043075562 + ], + [ + -2.301192045211792, + 1.3172303438186646 + ], + [ + -2.2908334732055664, + 1.3577792644500732 + ], + [ + -2.27878737449646, + 1.3989558219909668 + ], + [ + -2.261579751968384, + 1.4277735948562622 + ], + [ + -2.238513231277466, + 1.4949188232421875 + ], + [ + -2.2176127433776855, + 1.5282776355743408 + ], + [ + -2.1968090534210205, + 1.5617926120758057 + ], + [ + -2.169755697250366, + 1.5892717838287354 + ], + [ + -2.13558292388916, + 1.625771164894104 + ], + [ + -2.109731435775757, + 1.67192542552948 + ], + [ + -2.075552225112915, + 1.7093220949172974 + ], + [ + -2.0314695835113525, + 1.7475249767303467 + ], + [ + -1.980591058731079, + 1.775829553604126 + ], + [ + -1.9266046285629272, + 1.8126258850097656 + ], + [ + -1.867958903312683, + 1.8584524393081665 + ], + [ + -1.8301701545715332, + 1.9078624248504639 + ], + [ + -1.7699631452560425, + 1.9495002031326294 + ], + [ + -1.7086732387542725, + 1.9993089437484741 + ], + [ + -1.6490353345870972, + 2.0524954795837402 + ], + [ + -1.581202507019043, + 2.1065025329589844 + ], + [ + -1.5355106592178345, + 2.1579995155334473 + ], + [ + -1.473389983177185, + 2.209970235824585 + ], + [ + -1.4070863723754883, + 2.272813081741333 + ], + [ + -1.342864990234375, + 2.337266445159912 + ], + [ + -1.2887318134307861, + 2.410109281539917 + ], + [ + -1.231166958808899, + 2.479233980178833 + ], + [ + -1.1784919500350952, + 2.5283203125 + ], + [ + -1.1275389194488525, + 2.586707592010498 + ], + [ + -1.0714021921157837, + 2.638383388519287 + ], + [ + -1.0138081312179565, + 2.7014384269714355 + ], + [ + -0.9613556861877441, + 2.767829179763794 + ], + [ + -0.9044824838638306, + 2.816967248916626 + ], + [ + -0.8406919836997986, + 2.859841823577881 + ], + [ + -0.7884116172790527, + 2.9085583686828613 + ], + [ + -0.7255499362945557, + 2.953869581222534 + ], + [ + -0.6576851606369019, + 2.998589277267456 + ], + [ + -0.6037365198135376, + 3.039970874786377 + ], + [ + -0.5375269651412964, + 3.081350564956665 + ], + [ + -0.44995808601379395, + 3.110718250274658 + ], + [ + -0.39340701699256897, + 3.1451056003570557 + ], + [ + -0.3168303072452545, + 3.183993339538574 + ], + [ + -0.23857304453849792, + 3.2116355895996094 + ], + [ + -0.16603463888168335, + 3.2358429431915283 + ], + [ + -0.0916532352566719, + 3.2647645473480225 + ], + [ + -0.0005811986047774553, + 3.2859268188476562 + ], + [ + 0.07298585772514343, + 3.3010852336883545 + ], + [ + 0.1580224484205246, + 3.319701671600342 + ], + [ + 0.23015999794006348, + 3.3372697830200195 + ], + [ + 0.30307266116142273, + 3.349024534225464 + ], + [ + 0.3876035511493683, + 3.3475186824798584 + ], + [ + 0.5878651738166809, + 3.2136189937591553 + ], + [ + 0.6779069304466248, + 3.219494581222534 + ], + [ + 0.7918234467506409, + 3.2124924659729004 + ], + [ + 0.8848069906234741, + 3.2114877700805664 + ], + [ + 0.9875006079673767, + 3.199876308441162 + ], + [ + 1.0822911262512207, + 3.192505359649658 + ], + [ + 1.1757166385650635, + 3.180107831954956 + ], + [ + 1.2767142057418823, + 3.164475679397583 + ], + [ + 1.379189372062683, + 3.1488306522369385 + ], + [ + 1.4690500497817993, + 3.1253068447113037 + ], + [ + 1.5520175695419312, + 3.1033992767333984 + ], + [ + 1.6493271589279175, + 3.0771281719207764 + ], + [ + 1.757622480392456, + 3.039611577987671 + ], + [ + 1.8461952209472656, + 3.0060765743255615 + ], + [ + 1.9201148748397827, + 2.956674575805664 + ], + [ + 2.001403570175171, + 2.910261392593384 + ], + [ + 2.076373815536499, + 2.870056629180908 + ], + [ + 2.1798932552337646, + 2.8098409175872803 + ], + [ + 2.250122308731079, + 2.744114398956299 + ], + [ + 2.3202872276306152, + 2.6732492446899414 + ], + [ + 2.3956542015075684, + 2.6075103282928467 + ], + [ + 2.4642441272735596, + 2.5216567516326904 + ], + [ + 2.5547165870666504, + 2.454493284225464 + ], + [ + 2.618576765060425, + 2.375303030014038 + ], + [ + 2.6805849075317383, + 2.284599542617798 + ], + [ + 2.749704599380493, + 2.186394691467285 + ], + [ + 2.813284397125244, + 2.094119071960449 + ], + [ + 2.880871057510376, + 1.9898854494094849 + ], + [ + 2.934469223022461, + 1.9067977666854858 + ], + [ + 2.991663932800293, + 1.8043824434280396 + ], + [ + 3.057093858718872, + 1.6970021724700928 + ], + [ + 3.1130027770996094, + 1.5867290496826172 + ], + [ + 3.171023368835449, + 1.4858604669570923 + ], + [ + 3.2148594856262207, + 1.3836365938186646 + ], + [ + 3.263996124267578, + 1.274282455444336 + ], + [ + 3.3087658882141113, + 1.1732949018478394 + ], + [ + 3.350975513458252, + 1.0699526071548462 + ], + [ + 3.390791893005371, + 0.9659026265144348 + ], + [ + 3.4243171215057373, + 0.8666683435440063 + ], + [ + 3.446524143218994, + 0.7704423069953918 + ], + [ + 3.472703456878662, + 0.675892174243927 + ], + [ + 3.4931538105010986, + 0.580154299736023 + ], + [ + 3.5077016353607178, + 0.4884197413921356 + ], + [ + 3.5124459266662598, + 0.3999975323677063 + ], + [ + 3.5147197246551514, + 0.30849725008010864 + ], + [ + 3.512087821960449, + 0.22403927147388458 + ], + [ + 3.504700183868408, + 0.13418523967266083 + ], + [ + 3.4935789108276367, + 0.045682694762945175 + ], + [ + 3.477421760559082, + -0.044898029416799545 + ], + [ + 3.456566572189331, + -0.13699372112751007 + ], + [ + 3.4338762760162354, + -0.23066364228725433 + ], + [ + 3.4055705070495605, + -0.327321857213974 + ], + [ + 3.378270149230957, + -0.4164586663246155 + ], + [ + 3.347321033477783, + -0.5155251622200012 + ], + [ + 3.322336435317993, + -0.6215901374816895 + ], + [ + 3.3006479740142822, + -0.7233368754386902 + ], + [ + 3.2822046279907227, + -0.8258315920829773 + ], + [ + 3.2668824195861816, + -0.9272357225418091 + ], + [ + 3.243856906890869, + -1.0230904817581177 + ], + [ + 3.244309186935425, + -1.116092324256897 + ], + [ + 3.234924077987671, + -1.1947085857391357 + ], + [ + 3.2223989963531494, + -1.2671915292739868 + ], + [ + 3.219113349914551, + -1.3285025358200073 + ], + [ + 3.207261323928833, + -1.3796749114990234 + ], + [ + 3.1931650638580322, + -1.415226697921753 + ], + [ + 3.1698687076568604, + -1.4688541889190674 + ], + [ + 3.1412322521209717, + -1.5014845132827759 + ], + [ + 3.1008613109588623, + -1.534751296043396 + ], + [ + 3.0634870529174805, + -1.5698833465576172 + ], + [ + 3.0127251148223877, + -1.588167667388916 + ], + [ + 2.9586687088012695, + -1.6208267211914062 + ], + [ + 2.8867380619049072, + -1.648159146308899 + ], + [ + 2.83349347114563, + -1.6734973192214966 + ], + [ + 2.766019105911255, + -1.6997148990631104 + ], + [ + 2.6952385902404785, + -1.7353109121322632 + ], + [ + 2.6424436569213867, + -1.7725975513458252 + ], + [ + 2.5772390365600586, + -1.807450771331787 + ], + [ + 2.497368812561035, + -1.8400312662124634 + ], + [ + 2.4342873096466064, + -1.8636877536773682 + ], + [ + 2.355811834335327, + -1.8967679738998413 + ], + [ + 2.2752785682678223, + -1.9312840700149536 + ], + [ + 2.1962032318115234, + -1.9753929376602173 + ], + [ + 2.121793746948242, + -2.019887924194336 + ], + [ + 2.0455734729766846, + -2.0668246746063232 + ], + [ + 1.9679526090621948, + -2.1126163005828857 + ], + [ + 1.9006325006484985, + -2.180799961090088 + ], + [ + 1.8309653997421265, + -2.2034127712249756 + ], + [ + 1.763604760169983, + -2.2559385299682617 + ], + [ + 1.697442889213562, + -2.307339906692505 + ], + [ + 1.6368964910507202, + -2.3589682579040527 + ], + [ + 1.5709640979766846, + -2.404280662536621 + ], + [ + 1.5167990922927856, + -2.4437079429626465 + ], + [ + 1.4635775089263916, + -2.4949469566345215 + ], + [ + 1.5027706623077393, + -2.411202907562256 + ], + [ + 1.453515887260437, + -2.456845283508301 + ], + [ + 1.3780262470245361, + -2.4823944568634033 + ], + [ + 1.3080123662948608, + -2.499399185180664 + ], + [ + 1.2225286960601807, + -2.535712242126465 + ], + [ + 1.1629917621612549, + -2.5621891021728516 + ], + [ + 1.1361860036849976, + -2.5766618251800537 + ], + [ + 1.063064455986023, + -2.587355852127075 + ], + [ + 0.9937528371810913, + -2.6161532402038574 + ], + [ + 0.9249582886695862, + -2.63638973236084 + ], + [ + 0.8631870746612549, + -2.6620867252349854 + ], + [ + 0.7993646264076233, + -2.6841962337493896 + ], + [ + 0.7536969780921936, + -2.673858642578125 + ], + [ + 0.694944441318512, + -2.6893975734710693 + ], + [ + 0.6465615034103394, + -2.7003469467163086 + ], + [ + 0.5747862458229065, + -2.727842330932617 + ], + [ + 0.5197077989578247, + -2.745699882507324 + ], + [ + 0.4731369912624359, + -2.75351619720459 + ], + [ + 0.40462714433670044, + -2.738023281097412 + ], + [ + 0.3501152992248535, + -2.738109588623047 + ], + [ + 0.2983783483505249, + -2.756690263748169 + ], + [ + 0.2515210509300232, + -2.7695090770721436 + ], + [ + 0.20125414431095123, + -2.7769975662231445 + ], + [ + 0.15428268909454346, + -2.775938034057617 + ], + [ + 0.0821581780910492, + -2.7765653133392334 + ], + [ + 0.04347499459981918, + -2.767928123474121 + ], + [ + -0.00789116881787777, + -2.7652084827423096 + ], + [ + -0.04599149525165558, + -2.7722885608673096 + ], + [ + -0.09060350060462952, + -2.763873338699341 + ], + [ + -0.12612250447273254, + -2.761052370071411 + ], + [ + -0.20212243497371674, + -2.75677490234375 + ], + [ + -0.24069586396217346, + -2.743093967437744 + ], + [ + -0.2836313843727112, + -2.7396843433380127 + ], + [ + -0.3282116949558258, + -2.7346386909484863 + ], + [ + -0.36533138155937195, + -2.7167201042175293 + ], + [ + -0.39979082345962524, + -2.7093350887298584 + ], + [ + -0.4458392858505249, + -2.6665122509002686 + ], + [ + -0.49984124302864075, + -2.6887519359588623 + ], + [ + -0.544296383857727, + -2.6687815189361572 + ], + [ + -0.5792315602302551, + -2.647686004638672 + ], + [ + -0.6127561926841736, + -2.6242294311523438 + ], + [ + -0.6479333639144897, + -2.6033527851104736 + ], + [ + -0.6897246837615967, + -2.5753986835479736 + ], + [ + -0.7329197525978088, + -2.567378282546997 + ], + [ + -0.780539870262146, + -2.5552568435668945 + ], + [ + -0.8120342493057251, + -2.526226282119751 + ], + [ + -0.8462810516357422, + -2.502086639404297 + ], + [ + -0.886154294013977, + -2.4731786251068115 + ], + [ + -0.9251731038093567, + -2.442185878753662 + ], + [ + -0.9638217687606812, + -2.400994300842285 + ], + [ + -1.00369131565094, + -2.4034459590911865 + ], + [ + -1.033838152885437, + -2.372750759124756 + ], + [ + -1.0716140270233154, + -2.3319952487945557 + ], + [ + -1.122118592262268, + -2.2918314933776855 + ], + [ + -1.1665476560592651, + -2.2538442611694336 + ], + [ + -1.2205716371536255, + -2.2237606048583984 + ], + [ + -1.273909568786621, + -2.18815279006958 + ], + [ + -1.2945715188980103, + -2.16145920753479 + ], + [ + -1.3416869640350342, + -2.1253881454467773 + ], + [ + -1.395548939704895, + -2.0892577171325684 + ], + [ + -1.445960521697998, + -2.055070161819458 + ], + [ + -1.5000419616699219, + -2.024179220199585 + ], + [ + -1.5625221729278564, + -1.9943028688430786 + ], + [ + -1.6127196550369263, + -1.9717718362808228 + ], + [ + -1.671931266784668, + -1.9514291286468506 + ], + [ + -1.6947245597839355, + -1.9129234552383423 + ], + [ + -1.7501715421676636, + -1.8841849565505981 + ], + [ + -1.8020837306976318, + -1.8659074306488037 + ], + [ + -1.8445435762405396, + -1.8498421907424927 + ], + [ + -1.887615442276001, + -1.8390449285507202 + ], + [ + -1.9261912107467651, + -1.8158771991729736 + ], + [ + -1.9600956439971924, + -1.8054693937301636 + ], + [ + -1.9973646402359009, + -1.7634742259979248 + ], + [ + -2.0321316719055176, + -1.7462167739868164 + ], + [ + -2.067336082458496, + -1.7277648448944092 + ], + [ + -2.0930607318878174, + -1.708570957183838 + ], + [ + -2.1171107292175293, + -1.6954368352890015 + ], + [ + -2.128897190093994, + -1.6695770025253296 + ], + [ + -2.147247076034546, + -1.650486707687378 + ], + [ + -2.168623924255371, + -1.6228190660476685 + ], + [ + -2.209636688232422, + -1.5790663957595825 + ], + [ + -2.229109525680542, + -1.5512958765029907 + ], + [ + -2.240053415298462, + -1.5164803266525269 + ], + [ + -2.252962350845337, + -1.4774736166000366 + ], + [ + -2.7837743759155273, + -1.919206976890564 + ], + [ + -2.8080172538757324, + -1.8697103261947632 + ], + [ + -2.853060245513916, + -1.8182430267333984 + ], + [ + -2.887516498565674, + -1.7683335542678833 + ], + [ + -2.9246363639831543, + -1.7109719514846802 + ], + [ + -2.9605214595794678, + -1.6502751111984253 + ], + [ + -2.991450786590576, + -1.590841293334961 + ], + [ + -3.0296034812927246, + -1.5322867631912231 + ], + [ + -3.0597405433654785, + -1.4669045209884644 + ], + [ + -3.0953335762023926, + -1.399247646331787 + ], + [ + -3.1277523040771484, + -1.3386845588684082 + ], + [ + -3.1657650470733643, + -1.2710931301116943 + ], + [ + -1.935664415359497, + -0.6883072257041931 + ], + [ + -1.95100998878479, + -0.6450150012969971 + ], + [ + -1.9696930646896362, + -0.6015149354934692 + ], + [ + -1.9844924211502075, + -0.5559136271476746 + ], + [ + -1.996744155883789, + -0.5113682746887207 + ], + [ + -2.008295774459839, + -0.4664038419723511 + ], + [ + -2.019610643386841, + -0.4187585711479187 + ], + [ + -2.030045986175537, + -0.37128278613090515 + ], + [ + -2.038402795791626, + -0.3244359791278839 + ], + [ + -2.0470566749572754, + -0.2772515118122101 + ], + [ + -2.0540878772735596, + -0.22947342693805695 + ], + [ + -2.0611395835876465, + -0.18174809217453003 + ], + [ + -2.066038131713867, + -0.133727565407753 + ], + [ + -2.0703699588775635, + -0.08456044644117355 + ], + [ + -2.074824094772339, + -0.03492160513997078 + ], + [ + -2.0768260955810547, + 0.013081388548016548 + ], + [ + -2.07806134223938, + 0.06199152022600174 + ], + [ + -2.079186201095581, + 0.11421190947294235 + ], + [ + -2.0783491134643555, + 0.1651063710451126 + ], + [ + -2.0766143798828125, + 0.2155379205942154 + ], + [ + -2.074216604232788, + 0.267122745513916 + ], + [ + -2.0705089569091797, + 0.32017746567726135 + ], + [ + -2.064100980758667, + 0.3715705871582031 + ], + [ + -2.0582058429718018, + 0.42422521114349365 + ], + [ + -2.0500378608703613, + 0.47659358382225037 + ], + [ + -2.0369718074798584, + 0.5266203284263611 + ], + [ + -2.028622627258301, + 0.5784882307052612 + ], + [ + -2.016465663909912, + 0.6334421634674072 + ], + [ + -2.0024194717407227, + 0.6820216178894043 + ], + [ + -1.985360026359558, + 0.7365118265151978 + ], + [ + -1.9684746265411377, + 0.7855709791183472 + ], + [ + -1.949262261390686, + 0.8370513319969177 + ], + [ + -1.927605152130127, + 0.8893451690673828 + ], + [ + -1.9071763753890991, + 0.9342036247253418 + ], + [ + -1.8821049928665161, + 0.9854799509048462 + ], + [ + -1.8544752597808838, + 1.0311120748519897 + ], + [ + -1.8296862840652466, + 1.0803190469741821 + ], + [ + -1.7978023290634155, + 1.1293190717697144 + ], + [ + -1.7671458721160889, + 1.1716810464859009 + ], + [ + -1.741865873336792, + 1.2175030708312988 + ], + [ + -1.7134449481964111, + 1.2704921960830688 + ], + [ + -1.6739500761032104, + 1.309050440788269 + ], + [ + -1.637024998664856, + 1.3500995635986328 + ], + [ + -1.6051915884017944, + 1.399223804473877 + ], + [ + -1.568987488746643, + 1.4360132217407227 + ], + [ + -1.5305047035217285, + 1.4814079999923706 + ], + [ + -1.490166187286377, + 1.518885612487793 + ], + [ + -1.4531137943267822, + 1.5561578273773193 + ], + [ + -1.4059789180755615, + 1.5879491567611694 + ], + [ + -1.3669108152389526, + 1.6364701986312866 + ], + [ + -1.3275558948516846, + 1.6582576036453247 + ], + [ + -1.2846368551254272, + 1.6983668804168701 + ], + [ + -1.241637110710144, + 1.7289179563522339 + ], + [ + -1.1996538639068604, + 1.757182002067566 + ], + [ + -1.148848533630371, + 1.7901995182037354 + ], + [ + -1.1093586683273315, + 1.8149954080581665 + ], + [ + -1.0608354806900024, + 1.8442833423614502 + ], + [ + -1.0009334087371826, + 1.862099051475525 + ], + [ + -0.9629958271980286, + 1.8989758491516113 + ], + [ + -0.919478714466095, + 1.9106411933898926 + ], + [ + -0.8724031448364258, + 1.9270148277282715 + ], + [ + -0.8270814418792725, + 1.953360676765442 + ], + [ + -0.7705026268959045, + 1.976083517074585 + ], + [ + -0.7327464818954468, + 1.9781056642532349 + ], + [ + -0.6781279444694519, + 1.997910737991333 + ], + [ + -0.635509192943573, + 2.018270969390869 + ], + [ + -0.5865940451622009, + 2.0264360904693604 + ], + [ + -0.5320722460746765, + 2.037405490875244 + ], + [ + -0.47908514738082886, + 2.0507781505584717 + ], + [ + -0.43149876594543457, + 2.053215980529785 + ], + [ + -0.38548192381858826, + 2.062180519104004 + ], + [ + -0.3325420320034027, + 2.063960313796997 + ], + [ + -0.2815983295440674, + 2.0593724250793457 + ], + [ + -0.20684583485126495, + 2.0576412677764893 + ], + [ + -0.16255079209804535, + 2.071381092071533 + ], + [ + -0.12181153148412704, + 2.0720713138580322 + ], + [ + -0.06642143428325653, + 2.0724048614501953 + ], + [ + -0.009489577263593674, + 2.0693399906158447 + ], + [ + 0.04472999647259712, + 2.066993236541748 + ], + [ + 0.09162499010562897, + 2.0643627643585205 + ], + [ + 0.14289888739585876, + 2.061814308166504 + ], + [ + 0.19132329523563385, + 2.0530941486358643 + ], + [ + 0.2475784420967102, + 2.0457935333251953 + ], + [ + 0.2924618422985077, + 2.029400110244751 + ], + [ + 0.34878143668174744, + 2.0216708183288574 + ], + [ + 0.38956591486930847, + 2.0064573287963867 + ], + [ + 0.43953731656074524, + 1.9903284311294556 + ], + [ + 0.4915914535522461, + 1.977489948272705 + ], + [ + 0.54994136095047, + 1.9571533203125 + ], + [ + 0.5936962366104126, + 1.9308748245239258 + ], + [ + 0.6432555913925171, + 1.9216440916061401 + ], + [ + 0.6953475475311279, + 1.898364782333374 + ], + [ + 0.7386367917060852, + 1.867858648300171 + ], + [ + 0.7911633849143982, + 1.8482643365859985 + ], + [ + 0.8304948806762695, + 1.8175406455993652 + ], + [ + 0.8832184672355652, + 1.7979975938796997 + ], + [ + 0.9245592355728149, + 1.769811987876892 + ], + [ + 0.9727722406387329, + 1.7323118448257446 + ], + [ + 1.0234758853912354, + 1.7048507928848267 + ], + [ + 1.0653328895568848, + 1.6785727739334106 + ], + [ + 1.1094121932983398, + 1.6469670534133911 + ], + [ + 1.1535905599594116, + 1.6131222248077393 + ], + [ + 1.2006678581237793, + 1.581589698791504 + ], + [ + 1.241642713546753, + 1.5472909212112427 + ], + [ + 1.2739598751068115, + 1.5033990144729614 + ], + [ + 1.327681303024292, + 1.4695595502853394 + ], + [ + 1.3650836944580078, + 1.4261245727539062 + ], + [ + 1.4111230373382568, + 1.3918198347091675 + ], + [ + 1.446264386177063, + 1.3551913499832153 + ], + [ + 1.480709195137024, + 1.311214566230774 + ], + [ + 1.515140414237976, + 1.2644424438476562 + ], + [ + 1.5527229309082031, + 1.2219665050506592 + ], + [ + 1.5906987190246582, + 1.177523136138916 + ], + [ + 1.6212247610092163, + 1.1303155422210693 + ], + [ + 1.6595853567123413, + 1.089963674545288 + ], + [ + 1.6904889345169067, + 1.033535361289978 + ], + [ + 1.7179726362228394, + 0.988362729549408 + ], + [ + 1.7513253688812256, + 0.9392821192741394 + ], + [ + 1.7762948274612427, + 0.890687882900238 + ], + [ + 1.8051608800888062, + 0.8408190608024597 + ], + [ + 1.8268612623214722, + 0.7908740639686584 + ], + [ + 1.852120041847229, + 0.7372981309890747 + ], + [ + 1.8749315738677979, + 0.6847925186157227 + ], + [ + 1.89579176902771, + 0.630113422870636 + ], + [ + 1.917185664176941, + 0.5766167044639587 + ], + [ + 1.9351413249969482, + 0.5243584513664246 + ], + [ + 1.9529199600219727, + 0.4701376259326935 + ], + [ + 1.969649076461792, + 0.4148019850254059 + ], + [ + 1.9852980375289917, + 0.36000943183898926 + ], + [ + 1.9972517490386963, + 0.30596867203712463 + ], + [ + 2.009254217147827, + 0.24899908900260925 + ], + [ + 2.0200159549713135, + 0.19426099956035614 + ], + [ + 2.028616189956665, + 0.14022786915302277 + ], + [ + 2.0368642807006836, + 0.0837329849600792 + ], + [ + 2.0446321964263916, + 0.027753230184316635 + ], + [ + 2.0468854904174805, + -0.027986951172351837 + ], + [ + 2.0531952381134033, + -0.08293461799621582 + ], + [ + 2.0552361011505127, + -0.13702012598514557 + ], + [ + 2.05584979057312, + -0.1936483234167099 + ], + [ + 2.052304744720459, + -0.24383021891117096 + ], + [ + 2.0526440143585205, + -0.29550325870513916 + ], + [ + 2.048532724380493, + -0.3591861128807068 + ], + [ + 2.0443758964538574, + -0.40666431188583374 + ], + [ + 2.0443642139434814, + -0.46980494260787964 + ], + [ + 2.0338969230651855, + -0.5193932056427002 + ], + [ + 2.0240724086761475, + -0.5742443799972534 + ], + [ + 2.0198025703430176, + -0.6330156922340393 + ], + [ + 2.0025546550750732, + -0.6862195730209351 + ], + [ + 1.9887348413467407, + -0.7390432357788086 + ], + [ + 1.9728606939315796, + -0.7888534069061279 + ], + [ + 1.9517942667007446, + -0.8563905358314514 + ], + [ + 1.9420608282089233, + -0.9004015326499939 + ], + [ + 1.9264236688613892, + -0.9444159865379333 + ], + [ + 1.909824013710022, + -0.9982982277870178 + ], + [ + 1.886473536491394, + -1.050907015800476 + ], + [ + 1.8674519062042236, + -1.094844102859497 + ], + [ + 1.8503884077072144, + -1.1460943222045898 + ], + [ + 1.8287944793701172, + -1.19496488571167 + ], + [ + 1.7960340976715088, + -1.2443928718566895 + ], + [ + 1.7666563987731934, + -1.2799354791641235 + ], + [ + 1.7382992506027222, + -1.3262783288955688 + ], + [ + 1.7129380702972412, + -1.3695182800292969 + ], + [ + 1.684373140335083, + -1.4202955961227417 + ], + [ + 1.6448442935943604, + -1.4575445652008057 + ], + [ + 1.624143362045288, + -1.4992337226867676 + ], + [ + 1.5851563215255737, + -1.5449323654174805 + ], + [ + 1.55446195602417, + -1.5835217237472534 + ], + [ + 1.5131127834320068, + -1.6291346549987793 + ], + [ + 1.4787636995315552, + -1.6570931673049927 + ], + [ + 1.4342319965362549, + -1.6829447746276855 + ], + [ + 1.384718894958496, + -1.7119535207748413 + ], + [ + 1.3472832441329956, + -1.738911747932434 + ], + [ + 1.3141601085662842, + -1.7887866497039795 + ], + [ + 1.2666597366333008, + -1.8041819334030151 + ], + [ + 1.22465980052948, + -1.8300002813339233 + ], + [ + 1.1822032928466797, + -1.8676955699920654 + ], + [ + 1.1421464681625366, + -1.8964000940322876 + ], + [ + 1.0968680381774902, + -1.9208683967590332 + ], + [ + 1.0547646284103394, + -1.9544309377670288 + ], + [ + 0.976579487323761, + -1.914185881614685 + ], + [ + 0.9392303228378296, + -1.9442344903945923 + ], + [ + 0.8792645931243896, + -1.9660634994506836 + ], + [ + 0.8503670692443848, + -1.9907130002975464 + ], + [ + 0.812386691570282, + -2.0461530685424805 + ], + [ + 0.7761523723602295, + -2.0736730098724365 + ], + [ + 0.7160670757293701, + -2.117474317550659 + ], + [ + 0.6659147143363953, + -2.1630029678344727 + ], + [ + 0.6172897815704346, + -2.1951303482055664 + ], + [ + 0.5469140410423279, + -2.2127740383148193 + ], + [ + 0.45462772250175476, + -2.1820499897003174 + ], + [ + 0.36450082063674927, + -2.183260679244995 + ], + [ + 0.25341686606407166, + -2.1558573246002197 + ], + [ + 0.11812781542539597, + -2.118143081665039 + ], + [ + -0.054833926260471344, + -2.017806053161621 + ], + [ + -0.22248850762844086, + -1.9006211757659912 + ], + [ + -0.3778339624404907, + -1.7416913509368896 + ], + [ + -0.47833186388015747, + -1.6339031457901 + ], + [ + -0.5277042984962463, + -1.5874066352844238 + ], + [ + -0.5500900149345398, + -1.573772668838501 + ], + [ + -0.5985336899757385, + -1.892890214920044 + ], + [ + -0.6200459599494934, + -1.9435665607452393 + ], + [ + -0.6419571042060852, + -1.9800007343292236 + ], + [ + -0.6618088483810425, + -1.9544645547866821 + ], + [ + -0.6725050210952759, + -1.910160779953003 + ], + [ + -0.667539119720459, + -1.8135590553283691 + ], + [ + -0.640052318572998, + -1.7172532081604004 + ], + [ + -0.629052460193634, + -1.6340324878692627 + ], + [ + -0.5882589221000671, + -1.5393677949905396 + ], + [ + -0.5432126522064209, + -1.4833647012710571 + ], + [ + -0.5077447891235352, + -1.445670247077942 + ], + [ + -0.46375808119773865, + -1.4242428541183472 + ], + [ + -0.5480551719665527, + -1.4715851545333862 + ], + [ + -0.5247310400009155, + -1.4488811492919922 + ], + [ + -0.4918777644634247, + -1.4331812858581543 + ], + [ + -0.4947419762611389, + -1.450975775718689 + ], + [ + -0.5342426896095276, + -1.5435386896133423 + ], + [ + -0.6388733983039856, + -1.7032588720321655 + ], + [ + -0.8014348745346069, + -1.8765698671340942 + ], + [ + -0.9571249485015869, + -2.0633420944213867 + ], + [ + -1.0846765041351318, + -2.1561086177825928 + ], + [ + -1.1955300569534302, + -2.180401086807251 + ], + [ + -1.2772194147109985, + -2.169501781463623 + ], + [ + -1.29525887966156, + -2.1280534267425537 + ], + [ + -1.3648170232772827, + -2.0986809730529785 + ], + [ + -1.4442802667617798, + -2.0715749263763428 + ], + [ + -1.5120972394943237, + -2.0225284099578857 + ], + [ + -1.5730106830596924, + -1.965773582458496 + ], + [ + -1.6367148160934448, + -1.8953351974487305 + ], + [ + -1.6879174709320068, + -1.8227035999298096 + ], + [ + -1.7132043838500977, + -1.7314528226852417 + ], + [ + -1.735830545425415, + -1.650993824005127 + ], + [ + -1.7569620609283447, + -1.5841424465179443 + ], + [ + -1.7611446380615234, + -1.5269325971603394 + ], + [ + -1.7931441068649292, + -1.497328758239746 + ], + [ + -1.8771740198135376, + -1.4869850873947144 + ], + [ + -1.9236654043197632, + -1.4803944826126099 + ], + [ + -1.9705396890640259, + -1.4703142642974854 + ], + [ + -2.044564962387085, + -1.480547547340393 + ], + [ + -2.1139039993286133, + -1.4970269203186035 + ], + [ + -2.194765567779541, + -1.5028825998306274 + ], + [ + -2.2751429080963135, + -1.4990124702453613 + ], + [ + -2.3369157314300537, + -1.467200517654419 + ], + [ + -2.4083096981048584, + -1.430380940437317 + ], + [ + -2.4738833904266357, + -1.3780300617218018 + ], + [ + -2.5244171619415283, + -1.3232356309890747 + ], + [ + -2.581082820892334, + -1.2635838985443115 + ], + [ + -2.625917434692383, + -1.196604609489441 + ], + [ + -2.682605743408203, + -1.1417529582977295 + ], + [ + -2.724843978881836, + -1.0747928619384766 + ], + [ + -2.763423204421997, + -1.0052158832550049 + ], + [ + -2.8057756423950195, + -0.9306648969650269 + ], + [ + -2.836543083190918, + -0.8596242070198059 + ], + [ + -2.858031749725342, + -0.7836382985115051 + ], + [ + -2.878641128540039, + -0.7108041644096375 + ], + [ + -2.895611524581909, + -0.634407639503479 + ], + [ + -2.9086661338806152, + -0.5609465837478638 + ], + [ + -2.9136550426483154, + -0.4889409840106964 + ], + [ + -2.9176650047302246, + -0.4121151566505432 + ], + [ + -2.920250177383423, + -0.33876174688339233 + ], + [ + -3.012542724609375, + -0.2511477768421173 + ], + [ + -3.027001142501831, + -0.17742539942264557 + ], + [ + -3.031571865081787, + -0.09994552284479141 + ], + [ + -3.0404305458068848, + -0.019353676587343216 + ], + [ + -3.0370371341705322, + 0.05985275283455849 + ], + [ + -3.0380406379699707, + 0.1337829828262329 + ], + [ + -3.027435064315796, + 0.20997832715511322 + ], + [ + -3.0283520221710205, + 0.2803376317024231 + ], + [ + -3.0140609741210938, + 0.35903212428092957 + ], + [ + -3.0063071250915527, + 0.43691587448120117 + ], + [ + -2.9903881549835205, + 0.5095707774162292 + ], + [ + -2.9810566902160645, + 0.5858488082885742 + ], + [ + -2.9618659019470215, + 0.6596417427062988 + ], + [ + -2.9772891998291016, + 0.7641208171844482 + ], + [ + -2.9629781246185303, + 0.84083491563797 + ], + [ + -2.9462153911590576, + 0.9086923599243164 + ], + [ + -2.9220540523529053, + 0.9702616930007935 + ], + [ + -2.9029810428619385, + 1.050229549407959 + ], + [ + -2.87648606300354, + 1.1280237436294556 + ], + [ + -2.85565185546875, + 1.1965140104293823 + ], + [ + -2.8345563411712646, + 1.2685397863388062 + ], + [ + -2.8009085655212402, + 1.3566017150878906 + ], + [ + -2.7621185779571533, + 1.4320367574691772 + ], + [ + -2.711992025375366, + 1.5123510360717773 + ], + [ + -2.651895523071289, + 1.5944353342056274 + ], + [ + -2.5953571796417236, + 1.6477941274642944 + ], + [ + -2.5262110233306885, + 1.699404239654541 + ], + [ + -2.482839584350586, + 1.7643747329711914 + ], + [ + -2.4126625061035156, + 1.7879997491836548 + ], + [ + -2.363837480545044, + 1.8217486143112183 + ], + [ + -2.317458391189575, + 1.8715041875839233 + ], + [ + -2.2701034545898438, + 1.9078409671783447 + ], + [ + -2.2377190589904785, + 1.945436954498291 + ], + [ + -2.177765130996704, + 1.9780257940292358 + ], + [ + -2.1320748329162598, + 2.0156772136688232 + ], + [ + -2.07867431640625, + 2.0727920532226562 + ], + [ + -2.030075788497925, + 2.1081161499023438 + ], + [ + -1.9569929838180542, + 2.1331570148468018 + ], + [ + -1.9040024280548096, + 2.1690497398376465 + ], + [ + -1.8473048210144043, + 2.198195457458496 + ], + [ + -1.790403962135315, + 2.2111968994140625 + ], + [ + -1.7382831573486328, + 2.2407805919647217 + ], + [ + -1.6828320026397705, + 2.276496648788452 + ], + [ + -1.6152105331420898, + 2.281519651412964 + ], + [ + -1.5538396835327148, + 2.3064870834350586 + ], + [ + -1.501750111579895, + 2.310166358947754 + ], + [ + -1.4373867511749268, + 2.329052448272705 + ], + [ + -1.3839010000228882, + 2.3393683433532715 + ], + [ + -1.3358155488967896, + 2.3524537086486816 + ], + [ + -1.292285680770874, + 2.344827175140381 + ], + [ + -1.2370109558105469, + 2.3486952781677246 + ], + [ + -1.2000646591186523, + 2.348179578781128 + ], + [ + -1.1455433368682861, + 2.350385904312134 + ], + [ + -1.101224422454834, + 2.3683669567108154 + ], + [ + -1.052161455154419, + 2.3695015907287598 + ], + [ + -1.0148978233337402, + 2.374345064163208 + ], + [ + -0.9671911001205444, + 2.3812332153320312 + ], + [ + -0.9316477179527283, + 2.3903934955596924 + ], + [ + -0.8905055522918701, + 2.3952643871307373 + ], + [ + -0.8540663719177246, + 2.3975415229797363 + ], + [ + -0.7962154746055603, + 2.4191648960113525 + ], + [ + -0.7757487297058105, + 2.435396671295166 + ], + [ + -0.7300823330879211, + 2.44856858253479 + ], + [ + -0.6863178610801697, + 2.4689321517944336 + ], + [ + -0.6393466591835022, + 2.463688611984253 + ], + [ + -0.5890231728553772, + 2.481721878051758 + ], + [ + -0.5453053116798401, + 2.490652561187744 + ], + [ + -0.50407874584198, + 2.4985015392303467 + ], + [ + -0.45502135157585144, + 2.503329038619995 + ], + [ + -0.4007115662097931, + 2.5152299404144287 + ], + [ + -0.3617822229862213, + 2.5356392860412598 + ], + [ + -0.28880366683006287, + 2.5387301445007324 + ], + [ + -0.23872920870780945, + 2.525373697280884 + ], + [ + -0.16778776049613953, + 2.5388519763946533 + ], + [ + -0.10583434253931046, + 2.5329205989837646 + ], + [ + -0.05415201932191849, + 2.547940492630005 + ], + [ + -0.0032007666304707527, + 2.5527305603027344 + ], + [ + 0.0419035479426384, + 2.5284228324890137 + ], + [ + 0.12796764075756073, + 2.5247223377227783 + ], + [ + 0.1797327697277069, + 2.5494322776794434 + ], + [ + 0.24520958960056305, + 2.5436084270477295 + ], + [ + 0.3022260069847107, + 2.542194366455078 + ], + [ + 0.35460618138313293, + 2.520174503326416 + ], + [ + 0.41946378350257874, + 2.5196592807769775 + ], + [ + 0.46872425079345703, + 2.5220162868499756 + ], + [ + 0.5266742706298828, + 2.504120349884033 + ], + [ + 0.6060177683830261, + 2.5000243186950684 + ], + [ + 0.6642038226127625, + 2.4721007347106934 + ], + [ + 0.7458529472351074, + 2.458055019378662 + ], + [ + 0.797263503074646, + 2.4908089637756348 + ], + [ + 0.8470003604888916, + 2.4221208095550537 + ], + [ + 0.9332271218299866, + 2.42008113861084 + ], + [ + 0.9862779974937439, + 2.3952484130859375 + ], + [ + 1.0538870096206665, + 2.3781652450561523 + ], + [ + 1.111477017402649, + 2.3285584449768066 + ], + [ + 1.1954751014709473, + 2.3137598037719727 + ], + [ + 1.2511414289474487, + 2.268101930618286 + ], + [ + 1.3104890584945679, + 2.246967315673828 + ], + [ + 1.3784379959106445, + 2.2122318744659424 + ], + [ + 1.4414472579956055, + 2.17385196685791 + ], + [ + 1.5019047260284424, + 2.1512889862060547 + ], + [ + 1.5576761960983276, + 2.105919599533081 + ], + [ + 1.6273058652877808, + 2.0529260635375977 + ], + [ + 1.6929495334625244, + 2.029416799545288 + ], + [ + 1.7603707313537598, + 1.9849306344985962 + ], + [ + 1.8037184476852417, + 1.9327088594436646 + ], + [ + 1.8640540838241577, + 1.8926706314086914 + ], + [ + 1.9293409585952759, + 1.8465800285339355 + ], + [ + 1.9726957082748413, + 1.796122670173645 + ], + [ + 2.03570294380188, + 1.7438268661499023 + ], + [ + 2.0876803398132324, + 1.6883608102798462 + ], + [ + 2.1440749168395996, + 1.6497546434402466 + ], + [ + 2.191690683364868, + 1.59380304813385 + ], + [ + 2.2472918033599854, + 1.5241057872772217 + ], + [ + 2.2852673530578613, + 1.4742635488510132 + ], + [ + 2.3335671424865723, + 1.4111393690109253 + ], + [ + 2.3914554119110107, + 1.3513866662979126 + ], + [ + 2.4380853176116943, + 1.297100305557251 + ], + [ + 2.474743604660034, + 1.2347817420959473 + ], + [ + 2.5217645168304443, + 1.1775881052017212 + ], + [ + 2.5668768882751465, + 1.1088923215866089 + ], + [ + 2.6099956035614014, + 1.0353500843048096 + ], + [ + 2.657444477081299, + 0.968788206577301 + ], + [ + 2.6951029300689697, + 0.8935712575912476 + ], + [ + 2.7195382118225098, + 0.8351325392723083 + ], + [ + 2.7655739784240723, + 0.7628029584884644 + ], + [ + 2.7955899238586426, + 0.6807453632354736 + ], + [ + 2.829982280731201, + 0.6168544888496399 + ], + [ + 2.8581137657165527, + 0.538804829120636 + ], + [ + 2.889735698699951, + 0.4630218744277954 + ], + [ + 2.9193005561828613, + 0.3800201416015625 + ], + [ + 2.948359727859497, + 0.29613617062568665 + ], + [ + 2.9684951305389404, + 0.20782488584518433 + ], + [ + 3.000218152999878, + 0.12198688089847565 + ], + [ + 3.0217325687408447, + 0.03142319619655609 + ], + [ + 3.045511245727539, + -0.06487647444009781 + ], + [ + 3.0460352897644043, + -0.14036421477794647 + ], + [ + 3.058229684829712, + -0.2300051897764206 + ], + [ + 3.079805850982666, + -0.3216644525527954 + ], + [ + 3.0902833938598633, + -0.42159315943717957 + ], + [ + 3.090718984603882, + -0.5077506899833679 + ], + [ + 3.0955865383148193, + -0.6067076325416565 + ], + [ + 3.097529172897339, + -0.7039830684661865 + ], + [ + 3.1028051376342773, + -0.8013229966163635 + ], + [ + 3.0955312252044678, + -0.9044585824012756 + ], + [ + 3.0934295654296875, + -1.0075933933258057 + ], + [ + 3.0832741260528564, + -1.1146950721740723 + ], + [ + 3.076805353164673, + -1.2261617183685303 + ], + [ + 3.0751819610595703, + -1.3362665176391602 + ], + [ + 3.0754971504211426, + -1.4560726881027222 + ], + [ + 3.014509677886963, + -1.5269591808319092 + ], + [ + 2.9847373962402344, + -1.6404539346694946 + ], + [ + 2.946702480316162, + -1.7503511905670166 + ], + [ + 2.900275707244873, + -1.8441591262817383 + ], + [ + 2.8524551391601562, + -1.9643250703811646 + ], + [ + 2.8231019973754883, + -2.072808265686035 + ], + [ + 2.7650814056396484, + -2.1800851821899414 + ], + [ + 2.7038183212280273, + -2.2937002182006836 + ], + [ + 2.645848512649536, + -2.404895544052124 + ], + [ + 2.561894416809082, + -2.5093536376953125 + ], + [ + 2.500335216522217, + -2.620445489883423 + ], + [ + 2.410123586654663, + -2.726806163787842 + ], + [ + 2.270482063293457, + -2.8333029747009277 + ], + [ + 2.201957941055298, + -2.8957021236419678 + ], + [ + 2.136942148208618, + -3.0040125846862793 + ], + [ + 2.024168014526367, + -3.1082284450531006 + ], + [ + 1.9148718118667603, + -3.1709301471710205 + ], + [ + 1.8106225728988647, + -3.2769107818603516 + ], + [ + 1.6913504600524902, + -3.3605289459228516 + ], + [ + 1.5654969215393066, + -3.430734872817993 + ], + [ + 1.4234001636505127, + -3.520102024078369 + ], + [ + 1.2560296058654785, + -3.582613706588745 + ], + [ + 1.0903170108795166, + -3.596350908279419 + ], + [ + 0.9169342517852783, + -3.5893301963806152 + ], + [ + 0.701367199420929, + -3.6350929737091064 + ], + [ + 0.5097681879997253, + -3.636725664138794 + ], + [ + 0.4784690737724304, + -3.6943578720092773 + ], + [ + 0.3449876010417938, + -3.7533657550811768 + ], + [ + 0.1965716928243637, + -3.8127543926239014 + ], + [ + 0.0830964744091034, + -3.9074316024780273 + ], + [ + -0.0814841017127037, + -3.9415621757507324 + ], + [ + -0.2178017646074295, + -3.969921588897705 + ], + [ + -0.38107481598854065, + -4.029063701629639 + ], + [ + -0.5660316348075867, + -4.000732421875 + ], + [ + -0.7196700572967529, + -3.976536273956299 + ], + [ + -0.9106118679046631, + -3.9504780769348145 + ], + [ + -1.0998752117156982, + -3.9075562953948975 + ], + [ + -1.2563295364379883, + -3.8200831413269043 + ], + [ + -1.4544214010238647, + -3.7071053981781006 + ], + [ + -3.0006213188171387, + -7.207033634185791 + ], + [ + -3.4433045387268066, + -7.032714366912842 + ], + [ + -3.43412184715271, + -7.545030117034912 + ], + [ + -3.825704574584961, + -7.590828895568848 + ], + [ + -4.113344669342041, + -7.517468452453613 + ], + [ + -4.368183135986328, + -7.506117820739746 + ], + [ + -4.8009867668151855, + -7.406807899475098 + ], + [ + -5.047353744506836, + -7.236881256103516 + ], + [ + -5.356578350067139, + -7.1335601806640625 + ], + [ + -5.647794246673584, + -6.922834873199463 + ], + [ + -5.931471824645996, + -6.773493766784668 + ], + [ + -6.162847518920898, + -6.5040178298950195 + ], + [ + -6.425640106201172, + -6.250199317932129 + ], + [ + -6.6294965744018555, + -5.955855846405029 + ], + [ + -6.857776641845703, + -5.586231708526611 + ], + [ + -7.068276405334473, + -5.20672607421875 + ], + [ + -7.437286853790283, + -5.641544818878174 + ], + [ + -7.696932315826416, + -5.457540035247803 + ], + [ + -7.9060587882995605, + -5.2242584228515625 + ], + [ + -8.066984176635742, + -4.946529388427734 + ], + [ + -8.336150169372559, + -4.7649970054626465 + ], + [ + -8.52597713470459, + -4.450690746307373 + ], + [ + -8.681577682495117, + -4.149618625640869 + ], + [ + -8.788962364196777, + -3.88460373878479 + ], + [ + -8.94499683380127, + -3.620978355407715 + ], + [ + -9.00985336303711, + -3.3398890495300293 + ], + [ + -9.162784576416016, + -3.038771152496338 + ], + [ + -9.188023567199707, + -2.7745771408081055 + ], + [ + -9.269676208496094, + -2.492663860321045 + ], + [ + -9.298174858093262, + -2.2071080207824707 + ], + [ + -9.301246643066406, + -1.9218449592590332 + ], + [ + -9.279318809509277, + -1.6178292036056519 + ], + [ + -9.617018699645996, + -1.3741966485977173 + ], + [ + -9.661920547485352, + -1.098971962928772 + ], + [ + -9.64769458770752, + -0.8025069832801819 + ], + [ + -9.675349235534668, + -0.549736499786377 + ], + [ + -9.680461883544922, + -0.32157254219055176 + ], + [ + -9.676546096801758, + -0.04465971514582634 + ], + [ + -9.685470581054688, + 0.24179793894290924 + ], + [ + -9.667086601257324, + 0.4546229839324951 + ], + [ + -9.610819816589355, + 0.6807534098625183 + ], + [ + -9.549544334411621, + 0.9478676319122314 + ], + [ + -9.535961151123047, + 1.2063448429107666 + ], + [ + -9.573528289794922, + 1.42529296875 + ], + [ + -9.505254745483398, + 1.6640177965164185 + ], + [ + -9.41240406036377, + 1.925183653831482 + ] + ], + "total_points": 1000 +} \ No newline at end of file diff --git a/vna_system/calibration/s11_start100_stop8800_points1000_bw1khz/еуыеуые/short_metadata.json b/vna_system/calibration/s11_start100_stop8800_points1000_bw1khz/еуыеуые/short_metadata.json new file mode 100644 index 0000000..4d1820c --- /dev/null +++ b/vna_system/calibration/s11_start100_stop8800_points1000_bw1khz/еуыеуые/short_metadata.json @@ -0,0 +1,16 @@ +{ + "preset": { + "filename": "s11_start100_stop8800_points1000_bw1khz.bin", + "mode": "s11", + "start_freq": 100000000.0, + "stop_freq": 8800000000.0, + "points": 1000, + "bandwidth": 1000.0 + }, + "calibration_name": "еуыеуые", + "standard": "short", + "sweep_number": 13, + "sweep_timestamp": 1758896378.4093437, + "created_timestamp": "2025-09-26T17:19:50.019159", + "total_points": 1000 +} \ No newline at end of file diff --git a/vna_system/calibration/s11_start100_stop8800_points1000_bw1khz/яыф/calibration_info.json b/vna_system/calibration/s11_start100_stop8800_points1000_bw1khz/яыф/calibration_info.json new file mode 100644 index 0000000..41b6e70 --- /dev/null +++ b/vna_system/calibration/s11_start100_stop8800_points1000_bw1khz/яыф/calibration_info.json @@ -0,0 +1,18 @@ +{ + "preset": { + "filename": "s11_start100_stop8800_points1000_bw1khz.bin", + "mode": "s11", + "start_freq": 100000000.0, + "stop_freq": 8800000000.0, + "points": 1000, + "bandwidth": 1000.0 + }, + "calibration_name": "яыф", + "standards": [ + "open", + "load", + "short" + ], + "created_timestamp": "2025-09-26T17:20:00.022650", + "is_complete": true +} \ No newline at end of file diff --git a/vna_system/calibration/s11_start100_stop8800_points1000_bw1khz/яыф/load.json b/vna_system/calibration/s11_start100_stop8800_points1000_bw1khz/яыф/load.json new file mode 100644 index 0000000..9824a6b --- /dev/null +++ b/vna_system/calibration/s11_start100_stop8800_points1000_bw1khz/яыф/load.json @@ -0,0 +1,4007 @@ +{ + "sweep_number": 12, + "timestamp": 1758896376.33808, + "points": [ + [ + -2.672412872314453, + 0.44942471385002136 + ], + [ + -2.665140151977539, + 0.5138063430786133 + ], + [ + -2.6549153327941895, + 0.5751491785049438 + ], + [ + -2.6450717449188232, + 0.6348942518234253 + ], + [ + -2.633969783782959, + 0.6958639621734619 + ], + [ + -3.4072988033294678, + 0.9295109510421753 + ], + [ + -3.3898448944091797, + 1.0027321577072144 + ], + [ + -3.37446665763855, + 1.0809111595153809 + ], + [ + -3.351916790008545, + 1.1594840288162231 + ], + [ + -3.3281760215759277, + 1.2352432012557983 + ], + [ + -3.3081307411193848, + 1.3111613988876343 + ], + [ + -3.285163164138794, + 1.3833891153335571 + ], + [ + -3.25860333442688, + 1.4568874835968018 + ], + [ + -3.233642101287842, + 1.534937858581543 + ], + [ + -3.211621046066284, + 1.6109647750854492 + ], + [ + -3.1775434017181396, + 1.6917634010314941 + ], + [ + -3.147634744644165, + 1.7618643045425415 + ], + [ + -3.1176207065582275, + 1.8333007097244263 + ], + [ + -3.0827629566192627, + 1.9087711572647095 + ], + [ + -3.040661096572876, + 1.9821110963821411 + ], + [ + -3.00249981880188, + 2.0553479194641113 + ], + [ + -2.971890687942505, + 2.124830961227417 + ], + [ + -2.927703619003296, + 2.2003092765808105 + ], + [ + -2.885180950164795, + 2.274610996246338 + ], + [ + -2.8362882137298584, + 2.3481907844543457 + ], + [ + -2.798276662826538, + 2.413817882537842 + ], + [ + -2.755201578140259, + 2.4848906993865967 + ], + [ + -2.707097291946411, + 2.5589077472686768 + ], + [ + -2.653110980987549, + 2.6352760791778564 + ], + [ + -2.604438066482544, + 2.7032837867736816 + ], + [ + -2.5570480823516846, + 2.7709240913391113 + ], + [ + -2.508699893951416, + 2.835637092590332 + ], + [ + -2.452873468399048, + 2.907918691635132 + ], + [ + -2.395895004272461, + 2.9703681468963623 + ], + [ + -2.338472843170166, + 3.032949686050415 + ], + [ + -2.267284631729126, + 3.100571870803833 + ], + [ + -2.2003400325775146, + 3.165201425552368 + ], + [ + -2.130265712738037, + 3.233243703842163 + ], + [ + -2.0604138374328613, + 3.2860169410705566 + ], + [ + -1.9926751852035522, + 3.354316234588623 + ], + [ + -1.9244656562805176, + 3.414196014404297 + ], + [ + -1.8528647422790527, + 3.476970672607422 + ], + [ + -1.775537133216858, + 3.531400442123413 + ], + [ + -1.698214054107666, + 3.5915467739105225 + ], + [ + -1.6211034059524536, + 3.649618148803711 + ], + [ + -1.535129427909851, + 3.7091827392578125 + ], + [ + -1.449792504310608, + 3.757904052734375 + ], + [ + -1.3677159547805786, + 3.814706563949585 + ], + [ + -1.2757837772369385, + 3.861318349838257 + ], + [ + -1.1859837770462036, + 3.9188220500946045 + ], + [ + -1.092786431312561, + 3.9637033939361572 + ], + [ + -1.0051831007003784, + 4.010341644287109 + ], + [ + -0.89798903465271, + 4.0582275390625 + ], + [ + -0.8046980500221252, + 4.096992492675781 + ], + [ + -0.7105773091316223, + 4.143339157104492 + ], + [ + -0.608837902545929, + 4.182793617248535 + ], + [ + -0.5078397989273071, + 4.2201385498046875 + ], + [ + -0.40349194407463074, + 4.259609699249268 + ], + [ + -0.29068517684936523, + 4.292464733123779 + ], + [ + -0.17644040286540985, + 4.321564674377441 + ], + [ + -0.06537165492773056, + 4.347588539123535 + ], + [ + 0.05515637621283531, + 4.369880676269531 + ], + [ + 0.17611534893512726, + 4.379391193389893 + ], + [ + 0.29344743490219116, + 4.395306587219238 + ], + [ + 0.4191119074821472, + 4.413814544677734 + ], + [ + 0.5425008535385132, + 4.418741226196289 + ], + [ + 0.6587525606155396, + 4.433247089385986 + ], + [ + 0.7864275574684143, + 4.443286895751953 + ], + [ + 0.919674813747406, + 4.438477039337158 + ], + [ + 1.0481877326965332, + 4.434279918670654 + ], + [ + 1.1820579767227173, + 4.434950828552246 + ], + [ + 1.325274109840393, + 4.420563220977783 + ], + [ + 1.4506641626358032, + 4.406406879425049 + ], + [ + 1.5851094722747803, + 4.379190921783447 + ], + [ + 1.724495530128479, + 4.353355884552002 + ], + [ + 1.862963080406189, + 4.324624538421631 + ], + [ + 1.9926867485046387, + 4.288524150848389 + ], + [ + 2.12930965423584, + 4.251039505004883 + ], + [ + 2.2634921073913574, + 4.208732604980469 + ], + [ + 2.396778106689453, + 4.160767078399658 + ], + [ + 2.5294203758239746, + 4.109339714050293 + ], + [ + 2.655141592025757, + 4.0571208000183105 + ], + [ + 2.776848077774048, + 3.990960121154785 + ], + [ + 2.9058425426483154, + 3.925051212310791 + ], + [ + 3.0261900424957275, + 3.8497705459594727 + ], + [ + 3.1437149047851562, + 3.785703659057617 + ], + [ + 3.267310380935669, + 3.7046878337860107 + ], + [ + 3.3856406211853027, + 3.620727062225342 + ], + [ + 3.4874134063720703, + 3.529554843902588 + ], + [ + 3.609124183654785, + 3.4315907955169678 + ], + [ + 3.7178878784179688, + 3.3342206478118896 + ], + [ + 3.816277503967285, + 3.230572462081909 + ], + [ + 3.9382593631744385, + 3.1181538105010986 + ], + [ + 4.044654369354248, + 3.0044479370117188 + ], + [ + 4.155239582061768, + 2.877293825149536 + ], + [ + 4.251413822174072, + 2.7394824028015137 + ], + [ + 4.3388800621032715, + 2.622138261795044 + ], + [ + 4.439864158630371, + 2.4807515144348145 + ], + [ + 4.521735668182373, + 2.3513152599334717 + ], + [ + 4.593135833740234, + 2.204052686691284 + ], + [ + 4.6642985343933105, + 2.053229808807373 + ], + [ + 4.733786106109619, + 1.9070507287979126 + ], + [ + 4.784759044647217, + 1.759527564048767 + ], + [ + 4.843936443328857, + 1.59331214427948 + ], + [ + 4.898230075836182, + 1.4377585649490356 + ], + [ + 4.940882682800293, + 1.2707183361053467 + ], + [ + 4.975884437561035, + 1.1043983697891235 + ], + [ + 5.014648914337158, + 0.941770076751709 + ], + [ + 5.037928581237793, + 0.7779365181922913 + ], + [ + 5.056427001953125, + 0.6137372255325317 + ], + [ + 5.071547031402588, + 0.4381324350833893 + ], + [ + 5.090205669403076, + 0.2855481207370758 + ], + [ + 5.080108642578125, + 0.1063629686832428 + ], + [ + 5.070316314697266, + -0.05431445315480232 + ], + [ + 5.0558671951293945, + -0.207890123128891 + ], + [ + 5.029526233673096, + -0.3491782248020172 + ], + [ + 4.995769023895264, + -0.49604901671409607 + ], + [ + 4.974265098571777, + -0.6504014134407043 + ], + [ + 4.929023265838623, + -0.7893060445785522 + ], + [ + 4.868687629699707, + -0.9384287595748901 + ], + [ + 4.813848972320557, + -1.0797019004821777 + ], + [ + 4.744615077972412, + -1.2186343669891357 + ], + [ + 4.676766872406006, + -1.3487859964370728 + ], + [ + 4.593881130218506, + -1.4832743406295776 + ], + [ + 4.514934539794922, + -1.6201449632644653 + ], + [ + 4.430294513702393, + -1.7410017251968384 + ], + [ + 4.3437933921813965, + -1.8810490369796753 + ], + [ + 4.244453430175781, + -2.0108401775360107 + ], + [ + 4.148582935333252, + -2.138638496398926 + ], + [ + 4.056083679199219, + -2.270153522491455 + ], + [ + 3.9542436599731445, + -2.3845231533050537 + ], + [ + 3.853040933609009, + -2.5266377925872803 + ], + [ + 3.7614054679870605, + -2.6316466331481934 + ], + [ + 3.6557321548461914, + -2.7465944290161133 + ], + [ + 3.567324638366699, + -2.8408336639404297 + ], + [ + 3.455432415008545, + -2.930814027786255 + ], + [ + 3.3636744022369385, + -3.018575429916382 + ], + [ + 3.2565643787384033, + -3.084285259246826 + ], + [ + 3.161194086074829, + -3.156050682067871 + ], + [ + 3.0584988594055176, + -3.1846697330474854 + ], + [ + 2.960036516189575, + -3.227187395095825 + ], + [ + 2.8606131076812744, + -3.2711758613586426 + ], + [ + 2.7450449466705322, + -3.294323205947876 + ], + [ + 2.633589029312134, + -3.304173707962036 + ], + [ + 2.532041311264038, + -3.3372957706451416 + ], + [ + 2.416548728942871, + -3.3474135398864746 + ], + [ + 2.294229745864868, + -3.3516571521759033 + ], + [ + 2.2010910511016846, + -3.375875949859619 + ], + [ + 2.0861196517944336, + -3.367797374725342 + ], + [ + 1.9566923379898071, + -3.3809123039245605 + ], + [ + 1.862547755241394, + -3.3903965950012207 + ], + [ + 1.7353124618530273, + -3.4044573307037354 + ], + [ + 1.6217120885849, + -3.418888807296753 + ], + [ + 1.4697421789169312, + -3.6198036670684814 + ], + [ + 1.3651553392410278, + -3.635737180709839 + ], + [ + 1.2654904127120972, + -3.6339120864868164 + ], + [ + 1.1774555444717407, + -3.6060092449188232 + ], + [ + 1.0734139680862427, + -3.613830089569092 + ], + [ + 0.979674220085144, + -3.6030185222625732 + ], + [ + 0.8761454820632935, + -3.5985333919525146 + ], + [ + 0.7879981994628906, + -3.5754876136779785 + ], + [ + 0.6847778558731079, + -3.5718307495117188 + ], + [ + 0.6000930666923523, + -3.5531673431396484 + ], + [ + 0.4990699589252472, + -3.5412752628326416 + ], + [ + 0.4146011471748352, + -3.5257134437561035 + ], + [ + 0.32755935192108154, + -3.500272512435913 + ], + [ + 0.24657753109931946, + -3.4741697311401367 + ], + [ + 0.16803881525993347, + -3.4575114250183105 + ], + [ + 0.09345711022615433, + -3.4291741847991943 + ], + [ + 0.0022887317463755608, + -3.4094700813293457 + ], + [ + -0.057056330144405365, + -3.3856565952301025 + ], + [ + -0.1329173743724823, + -3.3531155586242676 + ], + [ + -0.2088886946439743, + -3.32807993888855 + ], + [ + -0.26992514729499817, + -3.2984018325805664 + ], + [ + -0.34073227643966675, + -3.275977373123169 + ], + [ + -0.4053002893924713, + -3.2447474002838135 + ], + [ + -0.4613828957080841, + -3.214855909347534 + ], + [ + -0.5255600214004517, + -3.1891062259674072 + ], + [ + -0.5953307151794434, + -3.1630845069885254 + ], + [ + -0.6431891322135925, + -3.128786087036133 + ], + [ + -0.7025863528251648, + -3.0989537239074707 + ], + [ + -0.7591955661773682, + -3.067817211151123 + ], + [ + -0.8138955235481262, + -3.02962327003479 + ], + [ + -0.8665670156478882, + -2.993196487426758 + ], + [ + -0.9244861006736755, + -2.965233564376831 + ], + [ + -0.978937029838562, + -2.9244863986968994 + ], + [ + -1.0342904329299927, + -2.8943440914154053 + ], + [ + -1.0855157375335693, + -2.856853485107422 + ], + [ + -1.1341140270233154, + -2.8258163928985596 + ], + [ + -1.1844428777694702, + -2.7875776290893555 + ], + [ + -1.23549222946167, + -2.7584996223449707 + ], + [ + -1.282921314239502, + -2.7211763858795166 + ], + [ + -1.3237563371658325, + -2.682608127593994 + ], + [ + -1.3692548274993896, + -2.6461188793182373 + ], + [ + -1.4059221744537354, + -2.6106350421905518 + ], + [ + -1.4455393552780151, + -2.570465087890625 + ], + [ + -1.4918361902236938, + -2.5273120403289795 + ], + [ + -1.5309549570083618, + -2.48526668548584 + ], + [ + -1.5699880123138428, + -2.443796157836914 + ], + [ + -1.6006845235824585, + -2.3941171169281006 + ], + [ + -1.6119121313095093, + -2.328874111175537 + ], + [ + -1.6615164279937744, + -2.2707836627960205 + ], + [ + -1.7099251747131348, + -2.228250741958618 + ], + [ + -1.7486892938613892, + -2.1776859760284424 + ], + [ + -1.798826813697815, + -2.120507001876831 + ], + [ + -1.8356176614761353, + -2.075648784637451 + ], + [ + -1.8820902109146118, + -2.019679546356201 + ], + [ + -1.9287985563278198, + -1.9699498414993286 + ], + [ + -1.9618436098098755, + -1.9203039407730103 + ], + [ + -2.006582260131836, + -1.866355538368225 + ], + [ + -2.0462899208068848, + -1.8188000917434692 + ], + [ + -2.0794010162353516, + -1.7730387449264526 + ], + [ + -2.114780902862549, + -1.716410517692566 + ], + [ + -2.1508870124816895, + -1.661577582359314 + ], + [ + -2.177006244659424, + -1.618638038635254 + ], + [ + -2.2129456996917725, + -1.5621641874313354 + ], + [ + -2.239290475845337, + -1.512711763381958 + ], + [ + -2.258457899093628, + -1.470788836479187 + ], + [ + -2.2874667644500732, + -1.410704493522644 + ], + [ + -2.3052868843078613, + -1.361812710762024 + ], + [ + -2.321857213973999, + -1.3169584274291992 + ], + [ + -2.3434555530548096, + -1.266066551208496 + ], + [ + -2.3562746047973633, + -1.2173861265182495 + ], + [ + -2.3685810565948486, + -1.1712769269943237 + ], + [ + -2.376680850982666, + -1.1234360933303833 + ], + [ + -2.3945863246917725, + -1.0710558891296387 + ], + [ + -2.4027750492095947, + -1.0249954462051392 + ], + [ + -2.409137487411499, + -0.9744507670402527 + ], + [ + -2.4202983379364014, + -0.92059725522995 + ], + [ + -2.427290678024292, + -0.8681397438049316 + ], + [ + -2.43591046333313, + -0.8146946430206299 + ], + [ + -2.4493472576141357, + -0.755174458026886 + ], + [ + -2.4590554237365723, + -0.7009482979774475 + ], + [ + -2.4691128730773926, + -0.6405749320983887 + ], + [ + -2.4789717197418213, + -0.5809928774833679 + ], + [ + -2.491446018218994, + -0.5165635347366333 + ], + [ + -2.5009407997131348, + -0.45797818899154663 + ], + [ + -2.5161654949188232, + -0.39766326546669006 + ], + [ + -2.522209405899048, + -0.3381291627883911 + ], + [ + -2.532291889190674, + -0.27920281887054443 + ], + [ + -2.5393848419189453, + -0.21943187713623047 + ], + [ + -2.5431716442108154, + -0.1623566746711731 + ], + [ + -2.53035831451416, + -0.10841787606477737 + ], + [ + -2.5240185260772705, + -0.054554760456085205 + ], + [ + -2.5196309089660645, + 0.0005839953082613647 + ], + [ + -2.5186665058135986, + 0.05507070943713188 + ], + [ + -2.5115649700164795, + 0.11332162469625473 + ], + [ + -2.5050342082977295, + 0.16904401779174805 + ], + [ + -2.4960529804229736, + 0.22937336564064026 + ], + [ + -2.493055820465088, + 0.2873798608779907 + ], + [ + -2.4837512969970703, + 0.33945825695991516 + ], + [ + -2.4726574420928955, + 0.3984595239162445 + ], + [ + -2.463252305984497, + 0.45446890592575073 + ], + [ + -2.456223964691162, + 0.5183476805686951 + ], + [ + -2.4486215114593506, + 0.5806308388710022 + ], + [ + -2.4322755336761475, + 0.6317009925842285 + ], + [ + -2.418165445327759, + 0.6931613087654114 + ], + [ + -2.4122791290283203, + 0.7552086710929871 + ], + [ + -2.404672145843506, + 0.8158265948295593 + ], + [ + -2.3955321311950684, + 0.8753899335861206 + ], + [ + -2.374551773071289, + 0.9307690262794495 + ], + [ + -2.3685660362243652, + 0.9893108606338501 + ], + [ + -2.3576600551605225, + 1.0486433506011963 + ], + [ + -2.3484387397766113, + 1.104414463043213 + ], + [ + -2.3445301055908203, + 1.1570032835006714 + ], + [ + -2.3328933715820312, + 1.2014226913452148 + ], + [ + -2.3077712059020996, + 1.263383388519287 + ], + [ + -2.2995731830596924, + 1.313030481338501 + ], + [ + -2.292541742324829, + 1.353027105331421 + ], + [ + -2.276519298553467, + 1.3915609121322632 + ], + [ + -2.2608678340911865, + 1.4306423664093018 + ], + [ + -2.2396578788757324, + 1.4902138710021973 + ], + [ + -2.2214953899383545, + 1.5249607563018799 + ], + [ + -2.198178291320801, + 1.560704231262207 + ], + [ + -2.1727616786956787, + 1.5866310596466064 + ], + [ + -2.140048027038574, + 1.6220717430114746 + ], + [ + -2.1120855808258057, + 1.6724121570587158 + ], + [ + -2.0751969814300537, + 1.7093777656555176 + ], + [ + -2.0301389694213867, + 1.7423040866851807 + ], + [ + -1.9805330038070679, + 1.779166340827942 + ], + [ + -1.9263598918914795, + 1.8140712976455688 + ], + [ + -1.869299054145813, + 1.859695553779602 + ], + [ + -1.8313579559326172, + 1.9058629274368286 + ], + [ + -1.771677017211914, + 1.9492803812026978 + ], + [ + -1.7108889818191528, + 1.9945214986801147 + ], + [ + -1.6472153663635254, + 2.0433297157287598 + ], + [ + -1.5802081823349, + 2.1042966842651367 + ], + [ + -1.5330379009246826, + 2.1566061973571777 + ], + [ + -1.4707579612731934, + 2.2150795459747314 + ], + [ + -1.4062886238098145, + 2.2799277305603027 + ], + [ + -1.3448680639266968, + 2.3366637229919434 + ], + [ + -1.2860314846038818, + 2.4060957431793213 + ], + [ + -1.235167384147644, + 2.4832816123962402 + ], + [ + -1.1883561611175537, + 2.5211234092712402 + ], + [ + -1.1233900785446167, + 2.590672731399536 + ], + [ + -1.0729283094406128, + 2.6388049125671387 + ], + [ + -1.0146491527557373, + 2.699958086013794 + ], + [ + -0.9592975974082947, + 2.7593612670898438 + ], + [ + -0.9109231233596802, + 2.8192312717437744 + ], + [ + -0.8413457274436951, + 2.858060359954834 + ], + [ + -0.7893630266189575, + 2.9040117263793945 + ], + [ + -0.7232140302658081, + 2.950082540512085 + ], + [ + -0.66054767370224, + 2.995304584503174 + ], + [ + -0.6067798137664795, + 3.043498992919922 + ], + [ + -0.5319972038269043, + 3.072779655456543 + ], + [ + -0.45669662952423096, + 3.1054911613464355 + ], + [ + -0.3879760801792145, + 3.1452856063842773 + ], + [ + -0.3163839280605316, + 3.178647756576538 + ], + [ + -0.23881268501281738, + 3.2143428325653076 + ], + [ + -0.16235657036304474, + 3.242783546447754 + ], + [ + -0.09107659012079239, + 3.2678940296173096 + ], + [ + -0.0015662735095247626, + 3.2931182384490967 + ], + [ + 0.07648210972547531, + 3.3010752201080322 + ], + [ + 0.15851885080337524, + 3.3261008262634277 + ], + [ + 0.2328532338142395, + 3.3402082920074463 + ], + [ + 0.30398327112197876, + 3.3425846099853516 + ], + [ + 0.39275306463241577, + 3.3504340648651123 + ], + [ + 0.5901356339454651, + 3.2232682704925537 + ], + [ + 0.7015319466590881, + 3.2192459106445312 + ], + [ + 0.7880183458328247, + 3.217802047729492 + ], + [ + 0.8911440968513489, + 3.2070109844207764 + ], + [ + 0.9743718504905701, + 3.2074365615844727 + ], + [ + 1.0823267698287964, + 3.199828624725342 + ], + [ + 1.174919843673706, + 3.179307460784912 + ], + [ + 1.2711454629898071, + 3.1628990173339844 + ], + [ + 1.377198576927185, + 3.1466429233551025 + ], + [ + 1.4639960527420044, + 3.1196913719177246 + ], + [ + 1.5541223287582397, + 3.104910135269165 + ], + [ + 1.6455168724060059, + 3.073697805404663 + ], + [ + 1.757059097290039, + 3.033984422683716 + ], + [ + 1.8448561429977417, + 3.0031070709228516 + ], + [ + 1.922029733657837, + 2.9642581939697266 + ], + [ + 2.003798246383667, + 2.911041259765625 + ], + [ + 2.073415756225586, + 2.855860948562622 + ], + [ + 2.1812610626220703, + 2.802154541015625 + ], + [ + 2.2501232624053955, + 2.742271900177002 + ], + [ + 2.3271467685699463, + 2.6747283935546875 + ], + [ + 2.398401975631714, + 2.6032512187957764 + ], + [ + 2.4678356647491455, + 2.5214154720306396 + ], + [ + 2.548351526260376, + 2.4564192295074463 + ], + [ + 2.61041522026062, + 2.373455762863159 + ], + [ + 2.6830625534057617, + 2.28041934967041 + ], + [ + 2.747586488723755, + 2.1921510696411133 + ], + [ + 2.8138184547424316, + 2.095742702484131 + ], + [ + 2.876384735107422, + 1.9926830530166626 + ], + [ + 2.932926654815674, + 1.9086298942565918 + ], + [ + 2.996795654296875, + 1.805037260055542 + ], + [ + 3.0548367500305176, + 1.6983861923217773 + ], + [ + 3.109464406967163, + 1.5877350568771362 + ], + [ + 3.1727302074432373, + 1.481256127357483 + ], + [ + 3.211042881011963, + 1.3843567371368408 + ], + [ + 3.2633306980133057, + 1.2765963077545166 + ], + [ + 3.308006525039673, + 1.1727060079574585 + ], + [ + 3.3526527881622314, + 1.069777488708496 + ], + [ + 3.3911781311035156, + 0.9681896567344666 + ], + [ + 3.424661636352539, + 0.8653106689453125 + ], + [ + 3.4479520320892334, + 0.7716711163520813 + ], + [ + 3.4718735218048096, + 0.6715928316116333 + ], + [ + 3.4897162914276123, + 0.5798554420471191 + ], + [ + 3.506943941116333, + 0.49197688698768616 + ], + [ + 3.5154800415039062, + 0.3985064923763275 + ], + [ + 3.5168020725250244, + 0.30777284502983093 + ], + [ + 3.513289451599121, + 0.22126562893390656 + ], + [ + 3.505326747894287, + 0.13551683723926544 + ], + [ + 3.493556499481201, + 0.043961625546216965 + ], + [ + 3.477113962173462, + -0.04401038959622383 + ], + [ + 3.4577229022979736, + -0.1369541734457016 + ], + [ + 3.4318063259124756, + -0.23035143315792084 + ], + [ + 3.408052921295166, + -0.33046427369117737 + ], + [ + 3.3775947093963623, + -0.41722720861434937 + ], + [ + 3.348123788833618, + -0.5172374844551086 + ], + [ + 3.320546865463257, + -0.6228078007698059 + ], + [ + 3.2952959537506104, + -0.7236150503158569 + ], + [ + 3.281160593032837, + -0.8302838206291199 + ], + [ + 3.271047830581665, + -0.9291787147521973 + ], + [ + 3.2429566383361816, + -1.0215719938278198 + ], + [ + 3.2416298389434814, + -1.1140131950378418 + ], + [ + 3.2357163429260254, + -1.1951252222061157 + ], + [ + 3.229006767272949, + -1.266624093055725 + ], + [ + 3.2191643714904785, + -1.3270381689071655 + ], + [ + 3.2097315788269043, + -1.3761764764785767 + ], + [ + 3.1899614334106445, + -1.4148547649383545 + ], + [ + 3.1712594032287598, + -1.4739134311676025 + ], + [ + 3.1417198181152344, + -1.5053458213806152 + ], + [ + 3.10054874420166, + -1.535404086112976 + ], + [ + 3.0659308433532715, + -1.5642060041427612 + ], + [ + 3.0132031440734863, + -1.5909934043884277 + ], + [ + 2.9598066806793213, + -1.6177518367767334 + ], + [ + 2.8843512535095215, + -1.6470000743865967 + ], + [ + 2.834927558898926, + -1.6705498695373535 + ], + [ + 2.7684693336486816, + -1.6994338035583496 + ], + [ + 2.7022452354431152, + -1.7357183694839478 + ], + [ + 2.6399872303009033, + -1.7731074094772339 + ], + [ + 2.5782599449157715, + -1.8069785833358765 + ], + [ + 2.497802972793579, + -1.8426717519760132 + ], + [ + 2.4158599376678467, + -1.8773146867752075 + ], + [ + 2.3536558151245117, + -1.8955771923065186 + ], + [ + 2.2751362323760986, + -1.9319634437561035 + ], + [ + 2.1982662677764893, + -1.9802165031433105 + ], + [ + 2.121298313140869, + -2.0171074867248535 + ], + [ + 2.0398170948028564, + -2.0653862953186035 + ], + [ + 1.965449333190918, + -2.1093950271606445 + ], + [ + 1.8994574546813965, + -2.1758220195770264 + ], + [ + 1.8282287120819092, + -2.2104318141937256 + ], + [ + 1.7667295932769775, + -2.2617740631103516 + ], + [ + 1.7051221132278442, + -2.3088021278381348 + ], + [ + 1.6403290033340454, + -2.3601555824279785 + ], + [ + 1.5714662075042725, + -2.405578136444092 + ], + [ + 1.525888204574585, + -2.449364423751831 + ], + [ + 1.4739958047866821, + -2.5005486011505127 + ], + [ + 1.510084867477417, + -2.4275670051574707 + ], + [ + 1.452736735343933, + -2.456312656402588 + ], + [ + 1.3698203563690186, + -2.4733352661132812 + ], + [ + 1.3051291704177856, + -2.5106418132781982 + ], + [ + 1.233035922050476, + -2.5337891578674316 + ], + [ + 1.1664057970046997, + -2.560462713241577 + ], + [ + 1.1379961967468262, + -2.581568479537964 + ], + [ + 1.0613441467285156, + -2.5792932510375977 + ], + [ + 0.9942167401313782, + -2.6124143600463867 + ], + [ + 0.9359543919563293, + -2.640059471130371 + ], + [ + 0.8627748489379883, + -2.671437978744507 + ], + [ + 0.808817982673645, + -2.6853275299072266 + ], + [ + 0.7592597007751465, + -2.670433282852173 + ], + [ + 0.6895032525062561, + -2.6909897327423096 + ], + [ + 0.6419966220855713, + -2.703969955444336 + ], + [ + 0.5750437378883362, + -2.72550368309021 + ], + [ + 0.5192556381225586, + -2.7417449951171875 + ], + [ + 0.4641278386116028, + -2.764291763305664 + ], + [ + 0.40754878520965576, + -2.731346845626831 + ], + [ + 0.34376391768455505, + -2.7541184425354004 + ], + [ + 0.2953405976295471, + -2.759856700897217 + ], + [ + 0.2482239305973053, + -2.771167516708374 + ], + [ + 0.19947369396686554, + -2.779921054840088 + ], + [ + 0.16243195533752441, + -2.786778211593628 + ], + [ + 0.0934247225522995, + -2.7600200176239014 + ], + [ + 0.03526142239570618, + -2.7666730880737305 + ], + [ + -0.007865983992815018, + -2.7630529403686523 + ], + [ + -0.05507233738899231, + -2.7645680904388428 + ], + [ + -0.08994065970182419, + -2.765259027481079 + ], + [ + -0.13178949058055878, + -2.7686474323272705 + ], + [ + -0.1968163549900055, + -2.742597818374634 + ], + [ + -0.24626262485980988, + -2.7446844577789307 + ], + [ + -0.2884788513183594, + -2.738398790359497 + ], + [ + -0.3255704939365387, + -2.7313430309295654 + ], + [ + -0.3582229018211365, + -2.7168257236480713 + ], + [ + -0.3956122398376465, + -2.706683874130249 + ], + [ + -0.43911507725715637, + -2.6870875358581543 + ], + [ + -0.5026808977127075, + -2.679696798324585 + ], + [ + -0.5519200563430786, + -2.6719422340393066 + ], + [ + -0.5743615031242371, + -2.655754327774048 + ], + [ + -0.6148557066917419, + -2.621581554412842 + ], + [ + -0.6489402651786804, + -2.606370687484741 + ], + [ + -0.6866077780723572, + -2.5727932453155518 + ], + [ + -0.7350509762763977, + -2.5579111576080322 + ], + [ + -0.7733362317085266, + -2.559326171875 + ], + [ + -0.8110785484313965, + -2.5323524475097656 + ], + [ + -0.8458943963050842, + -2.5049662590026855 + ], + [ + -0.8852884769439697, + -2.4748716354370117 + ], + [ + -0.9210420846939087, + -2.436002731323242 + ], + [ + -0.9677043557167053, + -2.4143435955047607 + ], + [ + -0.9985753297805786, + -2.398808717727661 + ], + [ + -1.0431288480758667, + -2.3674793243408203 + ], + [ + -1.0734139680862427, + -2.339211940765381 + ], + [ + -1.1192092895507812, + -2.289523124694824 + ], + [ + -1.1682292222976685, + -2.2517383098602295 + ], + [ + -1.2169394493103027, + -2.2200450897216797 + ], + [ + -1.26090407371521, + -2.1744117736816406 + ], + [ + -1.2952524423599243, + -2.164081573486328 + ], + [ + -1.3416997194290161, + -2.1214489936828613 + ], + [ + -1.3893687725067139, + -2.0872302055358887 + ], + [ + -1.449247121810913, + -2.054952621459961 + ], + [ + -1.5069382190704346, + -2.022207736968994 + ], + [ + -1.558609962463379, + -1.9946846961975098 + ], + [ + -1.6166878938674927, + -1.9706171751022339 + ], + [ + -1.675876498222351, + -1.9509732723236084 + ], + [ + -1.6974897384643555, + -1.9095323085784912 + ], + [ + -1.7507046461105347, + -1.886737585067749 + ], + [ + -1.7968331575393677, + -1.8695569038391113 + ], + [ + -1.846699833869934, + -1.851417064666748 + ], + [ + -1.8882246017456055, + -1.8381776809692383 + ], + [ + -1.9294058084487915, + -1.8208487033843994 + ], + [ + -1.959072470664978, + -1.8054554462432861 + ], + [ + -1.9954005479812622, + -1.7631641626358032 + ], + [ + -2.035001277923584, + -1.7467588186264038 + ], + [ + -2.0675790309906006, + -1.7271302938461304 + ], + [ + -2.0923659801483154, + -1.7105809450149536 + ], + [ + -2.1157710552215576, + -1.6959792375564575 + ], + [ + -2.1374080181121826, + -1.6704037189483643 + ], + [ + -2.153512716293335, + -1.6433185338974 + ], + [ + -2.165675401687622, + -1.6169507503509521 + ], + [ + -2.205427646636963, + -1.578442931175232 + ], + [ + -2.2238967418670654, + -1.5464286804199219 + ], + [ + -2.236910343170166, + -1.5166398286819458 + ], + [ + -2.2520265579223633, + -1.475869059562683 + ], + [ + -2.780294895172119, + -1.921571969985962 + ], + [ + -2.814448833465576, + -1.872692584991455 + ], + [ + -2.8520143032073975, + -1.8159303665161133 + ], + [ + -2.8915493488311768, + -1.758445382118225 + ], + [ + -2.9299585819244385, + -1.707815170288086 + ], + [ + -2.9612579345703125, + -1.6501107215881348 + ], + [ + -2.9927852153778076, + -1.5900700092315674 + ], + [ + -3.0286331176757812, + -1.5370652675628662 + ], + [ + -3.0627458095550537, + -1.46896231174469 + ], + [ + -3.093890428543091, + -1.4011098146438599 + ], + [ + -3.1280016899108887, + -1.33651602268219 + ], + [ + -3.1599416732788086, + -1.2726335525512695 + ], + [ + -1.93692946434021, + -0.688139021396637 + ], + [ + -1.951135516166687, + -0.6450985074043274 + ], + [ + -1.9691035747528076, + -0.600355327129364 + ], + [ + -1.9830117225646973, + -0.5563389658927917 + ], + [ + -1.996295690536499, + -0.5098227262496948 + ], + [ + -2.008678436279297, + -0.4671855866909027 + ], + [ + -2.018731117248535, + -0.41933777928352356 + ], + [ + -2.029167652130127, + -0.3717145025730133 + ], + [ + -2.0384998321533203, + -0.3248966932296753 + ], + [ + -2.0453851222991943, + -0.27763110399246216 + ], + [ + -2.0543158054351807, + -0.2302936464548111 + ], + [ + -2.06024432182312, + -0.181417778134346 + ], + [ + -2.0660252571105957, + -0.13402564823627472 + ], + [ + -2.0701818466186523, + -0.08482204377651215 + ], + [ + -2.073856830596924, + -0.036377981305122375 + ], + [ + -2.0757954120635986, + 0.013498243875801563 + ], + [ + -2.078766345977783, + 0.06260792165994644 + ], + [ + -2.079815626144409, + 0.11445926874876022 + ], + [ + -2.078620433807373, + 0.16460341215133667 + ], + [ + -2.0784027576446533, + 0.2157268226146698 + ], + [ + -2.0738449096679688, + 0.2678883373737335 + ], + [ + -2.07157564163208, + 0.3169556260108948 + ], + [ + -2.066638231277466, + 0.369326114654541 + ], + [ + -2.0593175888061523, + 0.4226098358631134 + ], + [ + -2.0466578006744385, + 0.47601255774497986 + ], + [ + -2.0334091186523438, + 0.5240135192871094 + ], + [ + -2.02695369720459, + 0.5774964094161987 + ], + [ + -2.014389991760254, + 0.628721296787262 + ], + [ + -1.9990944862365723, + 0.684299111366272 + ], + [ + -1.9853901863098145, + 0.7344710826873779 + ], + [ + -1.9689271450042725, + 0.7822098135948181 + ], + [ + -1.945559024810791, + 0.834809422492981 + ], + [ + -1.926823377609253, + 0.8859231472015381 + ], + [ + -1.9049760103225708, + 0.9356061816215515 + ], + [ + -1.881211757659912, + 0.9852762222290039 + ], + [ + -1.8544278144836426, + 1.0322664976119995 + ], + [ + -1.822708010673523, + 1.0785863399505615 + ], + [ + -1.7999520301818848, + 1.1303937435150146 + ], + [ + -1.7705137729644775, + 1.1707130670547485 + ], + [ + -1.7396730184555054, + 1.2202078104019165 + ], + [ + -1.714820384979248, + 1.2667555809020996 + ], + [ + -1.6777173280715942, + 1.3068474531173706 + ], + [ + -1.6406227350234985, + 1.3570568561553955 + ], + [ + -1.605550765991211, + 1.3950676918029785 + ], + [ + -1.5687322616577148, + 1.4354667663574219 + ], + [ + -1.530615210533142, + 1.4838550090789795 + ], + [ + -1.4922969341278076, + 1.5142518281936646 + ], + [ + -1.4502902030944824, + 1.5600910186767578 + ], + [ + -1.4131070375442505, + 1.595806360244751 + ], + [ + -1.3702269792556763, + 1.627675175666809 + ], + [ + -1.3253364562988281, + 1.6643174886703491 + ], + [ + -1.2857098579406738, + 1.6992449760437012 + ], + [ + -1.2352697849273682, + 1.734252691268921 + ], + [ + -1.1980395317077637, + 1.755337119102478 + ], + [ + -1.153885841369629, + 1.7906246185302734 + ], + [ + -1.1073788404464722, + 1.8209370374679565 + ], + [ + -1.0621074438095093, + 1.8425730466842651 + ], + [ + -1.0196586847305298, + 1.8691282272338867 + ], + [ + -0.9618881940841675, + 1.8960304260253906 + ], + [ + -0.9235616326332092, + 1.9144785404205322 + ], + [ + -0.8682800531387329, + 1.9332228899002075 + ], + [ + -0.8256640434265137, + 1.9428532123565674 + ], + [ + -0.7759353518486023, + 1.9702941179275513 + ], + [ + -0.725291907787323, + 1.987788200378418 + ], + [ + -0.6876645088195801, + 2.0082032680511475 + ], + [ + -0.6292517185211182, + 2.0249319076538086 + ], + [ + -0.5802642703056335, + 2.0265984535217285 + ], + [ + -0.5282400846481323, + 2.038886547088623 + ], + [ + -0.48228719830513, + 2.0465712547302246 + ], + [ + -0.4277693033218384, + 2.0460712909698486 + ], + [ + -0.377517968416214, + 2.064807176589966 + ], + [ + -0.33057844638824463, + 2.05850887298584 + ], + [ + -0.27055439352989197, + 2.0662715435028076 + ], + [ + -0.21040573716163635, + 2.065749168395996 + ], + [ + -0.1696169674396515, + 2.074981451034546 + ], + [ + -0.1197386160492897, + 2.077733278274536 + ], + [ + -0.06094830483198166, + 2.0679469108581543 + ], + [ + -0.011662371456623077, + 2.0676372051239014 + ], + [ + 0.039039935916662216, + 2.0678250789642334 + ], + [ + 0.08889462798833847, + 2.073586940765381 + ], + [ + 0.13304537534713745, + 2.064265727996826 + ], + [ + 0.189015731215477, + 2.0514655113220215 + ], + [ + 0.24343793094158173, + 2.0448896884918213 + ], + [ + 0.2927638590335846, + 2.036569118499756 + ], + [ + 0.33531835675239563, + 2.0193405151367188 + ], + [ + 0.39725443720817566, + 2.0078935623168945 + ], + [ + 0.44500455260276794, + 1.9839231967926025 + ], + [ + 0.4850606918334961, + 1.9698652029037476 + ], + [ + 0.5412566661834717, + 1.9597039222717285 + ], + [ + 0.5927621126174927, + 1.9369587898254395 + ], + [ + 0.6447550058364868, + 1.9127733707427979 + ], + [ + 0.688443660736084, + 1.8987480401992798 + ], + [ + 0.7454437017440796, + 1.8653645515441895 + ], + [ + 0.7987039685249329, + 1.848548412322998 + ], + [ + 0.8304269909858704, + 1.8188258409500122 + ], + [ + 0.8865737915039062, + 1.8037256002426147 + ], + [ + 0.9273987412452698, + 1.7660380601882935 + ], + [ + 0.9767124652862549, + 1.7300115823745728 + ], + [ + 1.0236610174179077, + 1.705960750579834 + ], + [ + 1.068193793296814, + 1.671668529510498 + ], + [ + 1.11372709274292, + 1.6482442617416382 + ], + [ + 1.1559734344482422, + 1.6099097728729248 + ], + [ + 1.2066575288772583, + 1.5819576978683472 + ], + [ + 1.2415891885757446, + 1.5444457530975342 + ], + [ + 1.2930335998535156, + 1.49643874168396 + ], + [ + 1.322836995124817, + 1.4761070013046265 + ], + [ + 1.371530532836914, + 1.428163766860962 + ], + [ + 1.4088071584701538, + 1.3926481008529663 + ], + [ + 1.4491121768951416, + 1.360991358757019 + ], + [ + 1.4858574867248535, + 1.3063172101974487 + ], + [ + 1.5176845788955688, + 1.2624571323394775 + ], + [ + 1.5545073747634888, + 1.2285226583480835 + ], + [ + 1.5879948139190674, + 1.17943274974823 + ], + [ + 1.6243985891342163, + 1.1317617893218994 + ], + [ + 1.6615341901779175, + 1.08260178565979 + ], + [ + 1.6900712251663208, + 1.0333431959152222 + ], + [ + 1.717814326286316, + 0.9902201890945435 + ], + [ + 1.746445655822754, + 0.942279040813446 + ], + [ + 1.772727131843567, + 0.8898627161979675 + ], + [ + 1.8032939434051514, + 0.8373379707336426 + ], + [ + 1.8328804969787598, + 0.7871468663215637 + ], + [ + 1.8513412475585938, + 0.7346880435943604 + ], + [ + 1.8755710124969482, + 0.6825049519538879 + ], + [ + 1.8961644172668457, + 0.6306540966033936 + ], + [ + 1.9181969165802002, + 0.5768918991088867 + ], + [ + 1.936019778251648, + 0.5236983299255371 + ], + [ + 1.9539722204208374, + 0.47032448649406433 + ], + [ + 1.9702845811843872, + 0.414725661277771 + ], + [ + 1.9834765195846558, + 0.3605348765850067 + ], + [ + 1.9971245527267456, + 0.3065274953842163 + ], + [ + 2.008385181427002, + 0.2496398538351059 + ], + [ + 2.0193004608154297, + 0.1949463188648224 + ], + [ + 2.0279579162597656, + 0.13844212889671326 + ], + [ + 2.0361175537109375, + 0.08258921653032303 + ], + [ + 2.0439209938049316, + 0.02562468871474266 + ], + [ + 2.047374963760376, + -0.028325144201517105 + ], + [ + 2.0530107021331787, + -0.0829746350646019 + ], + [ + 2.055759906768799, + -0.13882683217525482 + ], + [ + 2.057039499282837, + -0.1936911642551422 + ], + [ + 2.0530734062194824, + -0.24340954422950745 + ], + [ + 2.050746440887451, + -0.297834575176239 + ], + [ + 2.0459911823272705, + -0.3541272282600403 + ], + [ + 2.0453693866729736, + -0.4127858877182007 + ], + [ + 2.0373477935791016, + -0.46628135442733765 + ], + [ + 2.0328099727630615, + -0.5220854878425598 + ], + [ + 2.0264673233032227, + -0.5758885741233826 + ], + [ + 2.0134334564208984, + -0.6362519860267639 + ], + [ + 2.0051519870758057, + -0.686268150806427 + ], + [ + 1.9915666580200195, + -0.7295870184898376 + ], + [ + 1.9772893190383911, + -0.7930265069007874 + ], + [ + 1.9589542150497437, + -0.851529061794281 + ], + [ + 1.9407579898834229, + -0.8976286053657532 + ], + [ + 1.9251834154129028, + -0.9423039555549622 + ], + [ + 1.9118725061416626, + -0.9959063529968262 + ], + [ + 1.8908127546310425, + -1.0471693277359009 + ], + [ + 1.8672717809677124, + -1.0982557535171509 + ], + [ + 1.8457963466644287, + -1.1430846452713013 + ], + [ + 1.8223048448562622, + -1.1954636573791504 + ], + [ + 1.8043832778930664, + -1.242423176765442 + ], + [ + 1.7639611959457397, + -1.28315007686615 + ], + [ + 1.7371305227279663, + -1.3349566459655762 + ], + [ + 1.7197831869125366, + -1.3766576051712036 + ], + [ + 1.6784757375717163, + -1.4153554439544678 + ], + [ + 1.6463868618011475, + -1.4576956033706665 + ], + [ + 1.6202188730239868, + -1.4995262622833252 + ], + [ + 1.5804072618484497, + -1.541324496269226 + ], + [ + 1.5511451959609985, + -1.5842128992080688 + ], + [ + 1.5204912424087524, + -1.6195735931396484 + ], + [ + 1.4792982339859009, + -1.6671792268753052 + ], + [ + 1.4310437440872192, + -1.6790533065795898 + ], + [ + 1.387775182723999, + -1.7118169069290161 + ], + [ + 1.3452465534210205, + -1.7541178464889526 + ], + [ + 1.3051905632019043, + -1.777711272239685 + ], + [ + 1.269614577293396, + -1.8160505294799805 + ], + [ + 1.2290723323822021, + -1.8326092958450317 + ], + [ + 1.1756011247634888, + -1.8672785758972168 + ], + [ + 1.1443504095077515, + -1.902449131011963 + ], + [ + 1.102105975151062, + -1.920470118522644 + ], + [ + 1.0602314472198486, + -1.954665184020996 + ], + [ + 0.9790259003639221, + -1.9163408279418945 + ], + [ + 0.9420793056488037, + -1.943117380142212 + ], + [ + 0.8876888751983643, + -1.9600069522857666 + ], + [ + 0.8578128218650818, + -1.9957979917526245 + ], + [ + 0.8114399313926697, + -2.0363433361053467 + ], + [ + 0.7715330123901367, + -2.0771844387054443 + ], + [ + 0.7246339321136475, + -2.127476692199707 + ], + [ + 0.6680493354797363, + -2.148742437362671 + ], + [ + 0.615401566028595, + -2.198784828186035 + ], + [ + 0.5356854796409607, + -2.2125742435455322 + ], + [ + 0.45131540298461914, + -2.185903310775757 + ], + [ + 0.35771453380584717, + -2.18733549118042 + ], + [ + 0.2594391405582428, + -2.152716875076294 + ], + [ + 0.11931879073381424, + -2.114509344100952 + ], + [ + -0.05228176340460777, + -2.037353754043579 + ], + [ + -0.2330012023448944, + -1.8894004821777344 + ], + [ + -0.37270742654800415, + -1.7548279762268066 + ], + [ + -0.4824005961418152, + -1.6316970586776733 + ], + [ + -0.5308865904808044, + -1.5764117240905762 + ], + [ + -0.5550938248634338, + -1.5765622854232788 + ], + [ + -0.5972840189933777, + -1.8951325416564941 + ], + [ + -0.6266809701919556, + -1.961323857307434 + ], + [ + -0.6396424770355225, + -1.9779587984085083 + ], + [ + -0.6692653298377991, + -1.9492883682250977 + ], + [ + -0.6722683906555176, + -1.9039932489395142 + ], + [ + -0.6764839887619019, + -1.8050397634506226 + ], + [ + -0.6515088081359863, + -1.7225184440612793 + ], + [ + -0.6263872981071472, + -1.6341053247451782 + ], + [ + -0.587630569934845, + -1.5433638095855713 + ], + [ + -0.5498902201652527, + -1.485793113708496 + ], + [ + -0.506751298904419, + -1.4429348707199097 + ], + [ + -0.579936683177948, + -1.5312026739120483 + ], + [ + -0.5408642888069153, + -1.4762648344039917 + ], + [ + -0.521812379360199, + -1.4505494832992554 + ], + [ + -0.49930599331855774, + -1.4371663331985474 + ], + [ + -0.49079829454421997, + -1.454301118850708 + ], + [ + -0.5385971069335938, + -1.5405988693237305 + ], + [ + -0.6471798419952393, + -1.6939311027526855 + ], + [ + -0.791558563709259, + -1.8816765546798706 + ], + [ + -0.9543705582618713, + -2.057443380355835 + ], + [ + -1.084699034690857, + -2.168057680130005 + ], + [ + -1.1849048137664795, + -2.1777665615081787 + ], + [ + -1.2744269371032715, + -2.159170627593994 + ], + [ + -1.2871183156967163, + -2.1215929985046387 + ], + [ + -1.3741954565048218, + -2.106874942779541 + ], + [ + -1.4468402862548828, + -2.0609853267669678 + ], + [ + -1.5122511386871338, + -2.0195114612579346 + ], + [ + -1.576588749885559, + -1.970413327217102 + ], + [ + -1.6401374340057373, + -1.9090458154678345 + ], + [ + -1.676909327507019, + -1.821027398109436 + ], + [ + -1.711119294166565, + -1.7426294088363647 + ], + [ + -1.7298743724822998, + -1.6583516597747803 + ], + [ + -1.7481632232666016, + -1.5831114053726196 + ], + [ + -1.7637975215911865, + -1.5254923105239868 + ], + [ + -1.7908180952072144, + -1.4974889755249023 + ], + [ + -1.8756924867630005, + -1.4893426895141602 + ], + [ + -1.9129077196121216, + -1.4807029962539673 + ], + [ + -1.9693275690078735, + -1.4795637130737305 + ], + [ + -2.037893533706665, + -1.4828743934631348 + ], + [ + -2.110341787338257, + -1.5002020597457886 + ], + [ + -2.1947784423828125, + -1.500933051109314 + ], + [ + -2.259775400161743, + -1.4907984733581543 + ], + [ + -2.3349084854125977, + -1.4713819026947021 + ], + [ + -2.4125165939331055, + -1.4283255338668823 + ], + [ + -2.471870183944702, + -1.3826944828033447 + ], + [ + -2.53313946723938, + -1.326074481010437 + ], + [ + -2.579136371612549, + -1.2634663581848145 + ], + [ + -2.624403715133667, + -1.19972562789917 + ], + [ + -2.6804511547088623, + -1.1423391103744507 + ], + [ + -2.7289047241210938, + -1.075713038444519 + ], + [ + -2.771232843399048, + -0.9997217059135437 + ], + [ + -2.8056182861328125, + -0.9291902184486389 + ], + [ + -2.837981700897217, + -0.8571382164955139 + ], + [ + -2.861341953277588, + -0.7772646546363831 + ], + [ + -2.8806822299957275, + -0.7099368572235107 + ], + [ + -2.896350383758545, + -0.6319923400878906 + ], + [ + -2.9077041149139404, + -0.5589340925216675 + ], + [ + -2.9155611991882324, + -0.48309653997421265 + ], + [ + -2.919671058654785, + -0.4111967980861664 + ], + [ + -2.9211626052856445, + -0.33548834919929504 + ], + [ + -3.0138392448425293, + -0.25426730513572693 + ], + [ + -3.026895523071289, + -0.17562679946422577 + ], + [ + -3.0333735942840576, + -0.09418465942144394 + ], + [ + -3.0378265380859375, + -0.019998816773295403 + ], + [ + -3.039696216583252, + 0.05766826495528221 + ], + [ + -3.036749839782715, + 0.134446382522583 + ], + [ + -3.0267417430877686, + 0.21114985644817352 + ], + [ + -3.021972417831421, + 0.28294607996940613 + ], + [ + -3.0155367851257324, + 0.3623282015323639 + ], + [ + -2.9996933937072754, + 0.43712347745895386 + ], + [ + -2.9907610416412354, + 0.5138086080551147 + ], + [ + -2.9789650440216064, + 0.5894693732261658 + ], + [ + -2.955921173095703, + 0.6568942666053772 + ], + [ + -2.975410223007202, + 0.7644335627555847 + ], + [ + -2.9585471153259277, + 0.8408146500587463 + ], + [ + -2.9425251483917236, + 0.908227264881134 + ], + [ + -2.9227073192596436, + 0.9782958030700684 + ], + [ + -2.9067611694335938, + 1.0512185096740723 + ], + [ + -2.8807168006896973, + 1.1195088624954224 + ], + [ + -2.85424542427063, + 1.1936523914337158 + ], + [ + -2.8270833492279053, + 1.2662007808685303 + ], + [ + -2.814448833465576, + 1.3580150604248047 + ], + [ + -2.7690584659576416, + 1.4343712329864502 + ], + [ + -2.707697868347168, + 1.5138766765594482 + ], + [ + -2.665834903717041, + 1.574691653251648 + ], + [ + -2.583801746368408, + 1.6460704803466797 + ], + [ + -2.513245105743408, + 1.69454026222229 + ], + [ + -2.475759983062744, + 1.769864797592163 + ], + [ + -2.4156627655029297, + 1.7967053651809692 + ], + [ + -2.3722758293151855, + 1.8330044746398926 + ], + [ + -2.316722869873047, + 1.866292953491211 + ], + [ + -2.279439687728882, + 1.9071019887924194 + ], + [ + -2.226262092590332, + 1.9400603771209717 + ], + [ + -2.1896634101867676, + 1.9803316593170166 + ], + [ + -2.1247670650482178, + 2.0155563354492188 + ], + [ + -2.0847055912017822, + 2.0536720752716064 + ], + [ + -2.0230491161346436, + 2.1191983222961426 + ], + [ + -1.9615904092788696, + 2.139298439025879 + ], + [ + -1.898754596710205, + 2.1596462726593018 + ], + [ + -1.8539307117462158, + 2.19799542427063 + ], + [ + -1.778117060661316, + 2.212709665298462 + ], + [ + -1.736876368522644, + 2.2493553161621094 + ], + [ + -1.6549112796783447, + 2.282167911529541 + ], + [ + -1.613140344619751, + 2.291808605194092 + ], + [ + -1.5526442527770996, + 2.3036253452301025 + ], + [ + -1.51134192943573, + 2.3046796321868896 + ], + [ + -1.4463485479354858, + 2.3146743774414062 + ], + [ + -1.3800686597824097, + 2.3403472900390625 + ], + [ + -1.333465814590454, + 2.330880641937256 + ], + [ + -1.2867395877838135, + 2.342862367630005 + ], + [ + -1.2384792566299438, + 2.3392555713653564 + ], + [ + -1.1968265771865845, + 2.353299379348755 + ], + [ + -1.1462433338165283, + 2.3524646759033203 + ], + [ + -1.0893385410308838, + 2.3619916439056396 + ], + [ + -1.0446783304214478, + 2.36442232131958 + ], + [ + -1.0102226734161377, + 2.3693816661834717 + ], + [ + -0.9800311923027039, + 2.3836965560913086 + ], + [ + -0.9358634352684021, + 2.401972770690918 + ], + [ + -0.8795412182807922, + 2.4004368782043457 + ], + [ + -0.8409472703933716, + 2.4108643531799316 + ], + [ + -0.8039640784263611, + 2.424617290496826 + ], + [ + -0.7709384560585022, + 2.434352159500122 + ], + [ + -0.7341862916946411, + 2.4453024864196777 + ], + [ + -0.6874551177024841, + 2.4448821544647217 + ], + [ + -0.6509413719177246, + 2.473461627960205 + ], + [ + -0.5877283811569214, + 2.478449583053589 + ], + [ + -0.5396758913993835, + 2.487039566040039 + ], + [ + -0.5012562274932861, + 2.491401433944702 + ], + [ + -0.4478049576282501, + 2.5037076473236084 + ], + [ + -0.39794421195983887, + 2.518535614013672 + ], + [ + -0.34363117814064026, + 2.524292469024658 + ], + [ + -0.3036492168903351, + 2.5309927463531494 + ], + [ + -0.2469555139541626, + 2.5450353622436523 + ], + [ + -0.17544643580913544, + 2.539271831512451 + ], + [ + -0.10084348917007446, + 2.554676055908203 + ], + [ + -0.05391861870884895, + 2.542248249053955 + ], + [ + 0.011995027773082256, + 2.550614595413208 + ], + [ + 0.07806886732578278, + 2.5571911334991455 + ], + [ + 0.11975415050983429, + 2.547701835632324 + ], + [ + 0.16011224687099457, + 2.550675392150879 + ], + [ + 0.23179209232330322, + 2.544069766998291 + ], + [ + 0.30070701241493225, + 2.5384163856506348 + ], + [ + 0.3597598075866699, + 2.535822868347168 + ], + [ + 0.4035032093524933, + 2.5177619457244873 + ], + [ + 0.4544868767261505, + 2.5180065631866455 + ], + [ + 0.5448375344276428, + 2.496636390686035 + ], + [ + 0.6129027009010315, + 2.49289870262146 + ], + [ + 0.66318678855896, + 2.4798190593719482 + ], + [ + 0.7213486433029175, + 2.4671852588653564 + ], + [ + 0.776491105556488, + 2.4450807571411133 + ], + [ + 0.8486360907554626, + 2.4312968254089355 + ], + [ + 0.9200431704521179, + 2.4158709049224854 + ], + [ + 0.9822791218757629, + 2.3846287727355957 + ], + [ + 1.0507348775863647, + 2.366086721420288 + ], + [ + 1.109632134437561, + 2.3459889888763428 + ], + [ + 1.1991487741470337, + 2.312267780303955 + ], + [ + 1.2450958490371704, + 2.2846975326538086 + ], + [ + 1.3176641464233398, + 2.245155096054077 + ], + [ + 1.3781532049179077, + 2.2081799507141113 + ], + [ + 1.4392364025115967, + 2.18155837059021 + ], + [ + 1.4881616830825806, + 2.1472420692443848 + ], + [ + 1.5598158836364746, + 2.117340564727783 + ], + [ + 1.621751308441162, + 2.082244873046875 + ], + [ + 1.681108832359314, + 2.0241453647613525 + ], + [ + 1.763067364692688, + 1.9836277961730957 + ], + [ + 1.8027411699295044, + 1.9297118186950684 + ], + [ + 1.8608843088150024, + 1.8849177360534668 + ], + [ + 1.9157190322875977, + 1.846092700958252 + ], + [ + 1.9747368097305298, + 1.799984335899353 + ], + [ + 2.0320544242858887, + 1.7373936176300049 + ], + [ + 2.0969173908233643, + 1.6881911754608154 + ], + [ + 2.1467387676239014, + 1.6389353275299072 + ], + [ + 2.190516710281372, + 1.5842288732528687 + ], + [ + 2.253933906555176, + 1.5260403156280518 + ], + [ + 2.300490379333496, + 1.466659426689148 + ], + [ + 2.339001178741455, + 1.419132947921753 + ], + [ + 2.377389907836914, + 1.3612295389175415 + ], + [ + 2.429159641265869, + 1.2937220335006714 + ], + [ + 2.4760777950286865, + 1.2321645021438599 + ], + [ + 2.52648663520813, + 1.1711915731430054 + ], + [ + 2.5685079097747803, + 1.10277259349823 + ], + [ + 2.612246513366699, + 1.0412447452545166 + ], + [ + 2.6590631008148193, + 0.96451735496521 + ], + [ + 2.6936771869659424, + 0.8945825695991516 + ], + [ + 2.728400468826294, + 0.835950493812561 + ], + [ + 2.7612099647521973, + 0.7599547505378723 + ], + [ + 2.789625883102417, + 0.6861118674278259 + ], + [ + 2.8285393714904785, + 0.6172971725463867 + ], + [ + 2.8627073764801025, + 0.5425089001655579 + ], + [ + 2.8916571140289307, + 0.4606771767139435 + ], + [ + 2.9197311401367188, + 0.3780616521835327 + ], + [ + 2.9487524032592773, + 0.292915403842926 + ], + [ + 2.971808433532715, + 0.20933648943901062 + ], + [ + 2.995140790939331, + 0.11864086240530014 + ], + [ + 3.0181756019592285, + 0.030580004677176476 + ], + [ + 3.0452840328216553, + -0.060586899518966675 + ], + [ + 3.0503077507019043, + -0.13604934513568878 + ], + [ + 3.0698914527893066, + -0.23995622992515564 + ], + [ + 3.078491687774658, + -0.32350262999534607 + ], + [ + 3.0818393230438232, + -0.4170595109462738 + ], + [ + 3.08833646774292, + -0.5095797181129456 + ], + [ + 3.1032161712646484, + -0.6094707250595093 + ], + [ + 3.100677967071533, + -0.7035835385322571 + ], + [ + 3.0946531295776367, + -0.800666093826294 + ], + [ + 3.097914218902588, + -0.9062707424163818 + ], + [ + 3.0996203422546387, + -1.015777349472046 + ], + [ + 3.0824952125549316, + -1.1148368120193481 + ], + [ + 3.077432155609131, + -1.2232158184051514 + ], + [ + 3.066650152206421, + -1.3216910362243652 + ], + [ + 3.083028793334961, + -1.439587950706482 + ], + [ + 2.9883933067321777, + -1.5217981338500977 + ], + [ + 2.9640846252441406, + -1.6210706233978271 + ], + [ + 2.949012041091919, + -1.7401691675186157 + ], + [ + 2.9057304859161377, + -1.8667677640914917 + ], + [ + 2.8564324378967285, + -1.9638339281082153 + ], + [ + 2.8124847412109375, + -2.0664730072021484 + ], + [ + 2.7607383728027344, + -2.186269760131836 + ], + [ + 2.724405288696289, + -2.292771816253662 + ], + [ + 2.6438026428222656, + -2.3951282501220703 + ], + [ + 2.5644590854644775, + -2.51100754737854 + ], + [ + 2.513843059539795, + -2.621408462524414 + ], + [ + 2.406449794769287, + -2.7302536964416504 + ], + [ + 2.281958818435669, + -2.83337664604187 + ], + [ + 2.217024326324463, + -2.889907121658325 + ], + [ + 2.101747989654541, + -2.9808201789855957 + ], + [ + 2.0203118324279785, + -3.1442370414733887 + ], + [ + 1.9015345573425293, + -3.200127601623535 + ], + [ + 1.8035457134246826, + -3.288121223449707 + ], + [ + 1.6917238235473633, + -3.3516671657562256 + ], + [ + 1.5539387464523315, + -3.430612564086914 + ], + [ + 1.4255461692810059, + -3.506840944290161 + ], + [ + 1.2691807746887207, + -3.5530495643615723 + ], + [ + 1.0836812257766724, + -3.6132383346557617 + ], + [ + 0.9056865572929382, + -3.6305294036865234 + ], + [ + 0.7062676548957825, + -3.6409237384796143 + ], + [ + 0.48008227348327637, + -3.651737689971924 + ], + [ + 0.2848135530948639, + -3.645282506942749 + ], + [ + 0.35217246413230896, + -3.7474567890167236 + ], + [ + 0.21195350587368011, + -3.8631370067596436 + ], + [ + 0.043717242777347565, + -3.9295217990875244 + ], + [ + -0.055949967354536057, + -3.8955061435699463 + ], + [ + -0.2313389629125595, + -3.936713218688965 + ], + [ + -0.36753740906715393, + -4.001667022705078 + ], + [ + -0.5701069831848145, + -4.031083106994629 + ], + [ + -0.7193638682365417, + -4.010928630828857 + ], + [ + -0.9123112559318542, + -3.9432568550109863 + ], + [ + -1.0961499214172363, + -3.883634090423584 + ], + [ + -1.2699546813964844, + -3.8151633739471436 + ], + [ + -1.4612833261489868, + -3.751002073287964 + ], + [ + -3.075299024581909, + -7.190287113189697 + ], + [ + -3.478497266769409, + -7.030949592590332 + ], + [ + -3.4163830280303955, + -7.509958744049072 + ], + [ + -3.755155324935913, + -7.513199329376221 + ], + [ + -4.123136043548584, + -7.524814605712891 + ], + [ + -4.453611850738525, + -7.46895170211792 + ], + [ + -4.782583713531494, + -7.421286106109619 + ], + [ + -5.113187789916992, + -7.304635047912598 + ], + [ + -5.412776470184326, + -7.137959003448486 + ], + [ + -5.60633659362793, + -6.936783790588379 + ], + [ + -5.931177616119385, + -6.782471656799316 + ], + [ + -6.1928277015686035, + -6.5194807052612305 + ], + [ + -6.454876899719238, + -6.213492393493652 + ], + [ + -6.648608684539795, + -5.914278984069824 + ], + [ + -6.844915866851807, + -5.5787482261657715 + ], + [ + -7.04181432723999, + -5.181842803955078 + ], + [ + -7.4386162757873535, + -5.66335916519165 + ], + [ + -7.738227367401123, + -5.4609293937683105 + ], + [ + -7.9573893547058105, + -5.193496227264404 + ], + [ + -8.105751991271973, + -4.965923309326172 + ], + [ + -8.291110038757324, + -4.7123703956604 + ], + [ + -8.525086402893066, + -4.458969593048096 + ], + [ + -8.684398651123047, + -4.192453861236572 + ], + [ + -8.80959415435791, + -3.8892505168914795 + ], + [ + -8.951833724975586, + -3.600395917892456 + ], + [ + -9.040789604187012, + -3.326841115951538 + ], + [ + -9.11397933959961, + -3.053290605545044 + ], + [ + -9.198204040527344, + -2.7775681018829346 + ], + [ + -9.268774032592773, + -2.502626657485962 + ], + [ + -9.31387996673584, + -2.18566632270813 + ], + [ + -9.316969871520996, + -1.9154131412506104 + ], + [ + -9.575827598571777, + -1.6899380683898926 + ], + [ + -9.635106086730957, + -1.3736650943756104 + ], + [ + -9.617280006408691, + -1.0886234045028687 + ], + [ + -9.64592170715332, + -0.8348332047462463 + ], + [ + -9.649589538574219, + -0.5451606512069702 + ], + [ + -9.675400733947754, + -0.26295775175094604 + ], + [ + -9.678749084472656, + -0.02756967954337597 + ], + [ + -9.631559371948242, + 0.20831765234470367 + ], + [ + -9.624733924865723, + 0.47894811630249023 + ], + [ + -9.615409851074219, + 0.718176007270813 + ], + [ + -9.581632614135742, + 0.9181302189826965 + ], + [ + -9.554632186889648, + 1.2302730083465576 + ], + [ + -9.550939559936523, + 1.4048774242401123 + ], + [ + -9.48068904876709, + 1.6939939260482788 + ], + [ + -9.420056343078613, + 1.8948835134506226 + ] + ], + "total_points": 1000 +} \ No newline at end of file diff --git a/vna_system/calibration/s11_start100_stop8800_points1000_bw1khz/яыф/load_metadata.json b/vna_system/calibration/s11_start100_stop8800_points1000_bw1khz/яыф/load_metadata.json new file mode 100644 index 0000000..3187faf --- /dev/null +++ b/vna_system/calibration/s11_start100_stop8800_points1000_bw1khz/яыф/load_metadata.json @@ -0,0 +1,16 @@ +{ + "preset": { + "filename": "s11_start100_stop8800_points1000_bw1khz.bin", + "mode": "s11", + "start_freq": 100000000.0, + "stop_freq": 8800000000.0, + "points": 1000, + "bandwidth": 1000.0 + }, + "calibration_name": "яыф", + "standard": "load", + "sweep_number": 12, + "sweep_timestamp": 1758896376.33808, + "created_timestamp": "2025-09-26T17:20:00.020322", + "total_points": 1000 +} \ No newline at end of file diff --git a/vna_system/calibration/s11_start100_stop8800_points1000_bw1khz/яыф/open.json b/vna_system/calibration/s11_start100_stop8800_points1000_bw1khz/яыф/open.json new file mode 100644 index 0000000..ff27788 --- /dev/null +++ b/vna_system/calibration/s11_start100_stop8800_points1000_bw1khz/яыф/open.json @@ -0,0 +1,4007 @@ +{ + "sweep_number": 17, + "timestamp": 1758896395.4880857, + "points": [ + [ + -2.6740200519561768, + 0.45213583111763 + ], + [ + -2.6665968894958496, + 0.5122238993644714 + ], + [ + -2.656026601791382, + 0.5752711296081543 + ], + [ + -2.644921064376831, + 0.6361588835716248 + ], + [ + -2.634294271469116, + 0.6959936022758484 + ], + [ + -3.405562162399292, + 0.9240829348564148 + ], + [ + -3.3900253772735596, + 1.003711462020874 + ], + [ + -3.3761484622955322, + 1.0849004983901978 + ], + [ + -3.3548781871795654, + 1.156516194343567 + ], + [ + -3.333176612854004, + 1.233156681060791 + ], + [ + -3.307567596435547, + 1.309905767440796 + ], + [ + -3.283580780029297, + 1.3837534189224243 + ], + [ + -3.258148193359375, + 1.4651267528533936 + ], + [ + -3.234358072280884, + 1.5365701913833618 + ], + [ + -3.2071938514709473, + 1.6131095886230469 + ], + [ + -3.1735079288482666, + 1.685621976852417 + ], + [ + -3.145838975906372, + 1.761563777923584 + ], + [ + -3.1105332374572754, + 1.8358595371246338 + ], + [ + -3.0794174671173096, + 1.9105722904205322 + ], + [ + -3.0433051586151123, + 1.9809499979019165 + ], + [ + -3.006446599960327, + 2.0523056983947754 + ], + [ + -2.964648723602295, + 2.12691330909729 + ], + [ + -2.924546241760254, + 2.201700448989868 + ], + [ + -2.884993553161621, + 2.2728748321533203 + ], + [ + -2.837334156036377, + 2.3444769382476807 + ], + [ + -2.80426025390625, + 2.419173240661621 + ], + [ + -2.754749298095703, + 2.4896976947784424 + ], + [ + -2.7044754028320312, + 2.557685613632202 + ], + [ + -2.6568896770477295, + 2.634589195251465 + ], + [ + -2.6013567447662354, + 2.7060353755950928 + ], + [ + -2.5632123947143555, + 2.7692432403564453 + ], + [ + -2.5103330612182617, + 2.8370912075042725 + ], + [ + -2.4555537700653076, + 2.902379274368286 + ], + [ + -2.399548053741455, + 2.9658637046813965 + ], + [ + -2.330949068069458, + 3.0365118980407715 + ], + [ + -2.2724459171295166, + 3.1018383502960205 + ], + [ + -2.204742193222046, + 3.1618735790252686 + ], + [ + -2.1338651180267334, + 3.22880220413208 + ], + [ + -2.06632661819458, + 3.290440082550049 + ], + [ + -1.9907554388046265, + 3.3555855751037598 + ], + [ + -1.9234503507614136, + 3.4166452884674072 + ], + [ + -1.8499846458435059, + 3.4811244010925293 + ], + [ + -1.7805100679397583, + 3.5361011028289795 + ], + [ + -1.7031164169311523, + 3.5941169261932373 + ], + [ + -1.6220723390579224, + 3.64884877204895 + ], + [ + -1.5387048721313477, + 3.7059624195098877 + ], + [ + -1.4497042894363403, + 3.7637641429901123 + ], + [ + -1.3656229972839355, + 3.8104960918426514 + ], + [ + -1.273634433746338, + 3.862128973007202 + ], + [ + -1.189271330833435, + 3.916393280029297 + ], + [ + -1.0922220945358276, + 3.966796875 + ], + [ + -1.0012896060943604, + 4.008524417877197 + ], + [ + -0.91019606590271, + 4.061906337738037 + ], + [ + -0.7994781136512756, + 4.1051177978515625 + ], + [ + -0.7080296874046326, + 4.143758773803711 + ], + [ + -0.6139460206031799, + 4.185637950897217 + ], + [ + -0.5030912756919861, + 4.222401142120361 + ], + [ + -0.4034191966056824, + 4.257406711578369 + ], + [ + -0.2940066158771515, + 4.293758869171143 + ], + [ + -0.17842009663581848, + 4.313080787658691 + ], + [ + -0.07110679149627686, + 4.350997447967529 + ], + [ + 0.050012677907943726, + 4.367427349090576 + ], + [ + 0.17086486518383026, + 4.382813930511475 + ], + [ + 0.29098716378211975, + 4.398787021636963 + ], + [ + 0.421750009059906, + 4.411935329437256 + ], + [ + 0.5422607660293579, + 4.42132568359375 + ], + [ + 0.6613946557044983, + 4.426125526428223 + ], + [ + 0.7917270064353943, + 4.437415599822998 + ], + [ + 0.9130176901817322, + 4.439211845397949 + ], + [ + 1.0453459024429321, + 4.436264991760254 + ], + [ + 1.1833360195159912, + 4.441579818725586 + ], + [ + 1.313025712966919, + 4.418928146362305 + ], + [ + 1.458267331123352, + 4.403620719909668 + ], + [ + 1.5936939716339111, + 4.3868794441223145 + ], + [ + 1.7230734825134277, + 4.354174613952637 + ], + [ + 1.8612607717514038, + 4.325182914733887 + ], + [ + 1.9991223812103271, + 4.296128273010254 + ], + [ + 2.1353561878204346, + 4.251694679260254 + ], + [ + 2.2596278190612793, + 4.207988739013672 + ], + [ + 2.4003665447235107, + 4.166022300720215 + ], + [ + 2.526296854019165, + 4.108114719390869 + ], + [ + 2.6622750759124756, + 4.0568156242370605 + ], + [ + 2.7814388275146484, + 3.9965627193450928 + ], + [ + 2.913621664047241, + 3.9195830821990967 + ], + [ + 3.0241127014160156, + 3.8560867309570312 + ], + [ + 3.146780490875244, + 3.7760837078094482 + ], + [ + 3.264918804168701, + 3.6969282627105713 + ], + [ + 3.3822038173675537, + 3.615262269973755 + ], + [ + 3.4986722469329834, + 3.5317223072052 + ], + [ + 3.609560012817383, + 3.428884267807007 + ], + [ + 3.716632127761841, + 3.3400981426239014 + ], + [ + 3.825396776199341, + 3.2360901832580566 + ], + [ + 3.9323270320892334, + 3.12019681930542 + ], + [ + 4.04083251953125, + 2.9971234798431396 + ], + [ + 4.150185585021973, + 2.877512216567993 + ], + [ + 4.252536296844482, + 2.7469029426574707 + ], + [ + 4.343535900115967, + 2.618891477584839 + ], + [ + 4.443363666534424, + 2.483614206314087 + ], + [ + 4.521478652954102, + 2.342622995376587 + ], + [ + 4.593520164489746, + 2.198260545730591 + ], + [ + 4.668550491333008, + 2.062562942504883 + ], + [ + 4.738902568817139, + 1.9052455425262451 + ], + [ + 4.7900071144104, + 1.7580559253692627 + ], + [ + 4.854331970214844, + 1.597257137298584 + ], + [ + 4.8997111320495605, + 1.4372702836990356 + ], + [ + 4.9376606941223145, + 1.2668554782867432 + ], + [ + 4.98169469833374, + 1.1089773178100586 + ], + [ + 5.01936674118042, + 0.9442558288574219 + ], + [ + 5.046026706695557, + 0.7657347917556763 + ], + [ + 5.064160346984863, + 0.6033061146736145 + ], + [ + 5.06731653213501, + 0.4379490911960602 + ], + [ + 5.087487697601318, + 0.2801513373851776 + ], + [ + 5.085384368896484, + 0.11089878529310226 + ], + [ + 5.073779106140137, + -0.049927111715078354 + ], + [ + 5.056911468505859, + -0.21982882916927338 + ], + [ + 5.034821033477783, + -0.3494519889354706 + ], + [ + 5.00844669342041, + -0.49107763171195984 + ], + [ + 4.967347621917725, + -0.641101598739624 + ], + [ + 4.925406455993652, + -0.7953404784202576 + ], + [ + 4.870513916015625, + -0.941711962223053 + ], + [ + 4.809291839599609, + -1.0819206237792969 + ], + [ + 4.749701023101807, + -1.2111862897872925 + ], + [ + 4.675460338592529, + -1.3515260219573975 + ], + [ + 4.598371982574463, + -1.4823840856552124 + ], + [ + 4.516035556793213, + -1.6218260526657104 + ], + [ + 4.428529262542725, + -1.7470506429672241 + ], + [ + 4.33791446685791, + -1.884670615196228 + ], + [ + 4.243622303009033, + -2.0083906650543213 + ], + [ + 4.149678707122803, + -2.1436660289764404 + ], + [ + 4.057736396789551, + -2.2711868286132812 + ], + [ + 3.9454379081726074, + -2.387525796890259 + ], + [ + 3.8471884727478027, + -2.5174005031585693 + ], + [ + 3.7574427127838135, + -2.628059148788452 + ], + [ + 3.6562387943267822, + -2.7488081455230713 + ], + [ + 3.557023286819458, + -2.844059467315674 + ], + [ + 3.452885627746582, + -2.93546462059021 + ], + [ + 3.3631293773651123, + -3.024224042892456 + ], + [ + 3.2703287601470947, + -3.0815179347991943 + ], + [ + 3.1592886447906494, + -3.150083303451538 + ], + [ + 3.0639045238494873, + -3.2031002044677734 + ], + [ + 2.9570436477661133, + -3.2224068641662598 + ], + [ + 2.8493995666503906, + -3.271688938140869 + ], + [ + 2.7441670894622803, + -3.2978057861328125 + ], + [ + 2.6243135929107666, + -3.3015823364257812 + ], + [ + 2.527113914489746, + -3.340095043182373 + ], + [ + 2.4150760173797607, + -3.3436625003814697 + ], + [ + 2.296837329864502, + -3.3565590381622314 + ], + [ + 2.195249557495117, + -3.3752548694610596 + ], + [ + 2.0849530696868896, + -3.369567394256592 + ], + [ + 1.9650825262069702, + -3.376197338104248 + ], + [ + 1.8654838800430298, + -3.387206554412842 + ], + [ + 1.7458726167678833, + -3.391411066055298 + ], + [ + 1.6237214803695679, + -3.42691707611084 + ], + [ + 1.466076374053955, + -3.6305623054504395 + ], + [ + 1.3652923107147217, + -3.636094331741333 + ], + [ + 1.2705862522125244, + -3.6250038146972656 + ], + [ + 1.1820985078811646, + -3.60909104347229 + ], + [ + 1.0760929584503174, + -3.614158868789673 + ], + [ + 0.9785314202308655, + -3.5973331928253174 + ], + [ + 0.883355975151062, + -3.591306209564209 + ], + [ + 0.7815086841583252, + -3.579641819000244 + ], + [ + 0.685430645942688, + -3.563727855682373 + ], + [ + 0.5948621034622192, + -3.552913188934326 + ], + [ + 0.5066621899604797, + -3.5338170528411865 + ], + [ + 0.4165983498096466, + -3.5179367065429688 + ], + [ + 0.3293857276439667, + -3.5008671283721924 + ], + [ + 0.24589458107948303, + -3.4770636558532715 + ], + [ + 0.16873659193515778, + -3.454771041870117 + ], + [ + 0.08709707856178284, + -3.4325485229492188 + ], + [ + 0.013243863359093666, + -3.404546022415161 + ], + [ + -0.05734001472592354, + -3.382359743118286 + ], + [ + -0.14299166202545166, + -3.3552000522613525 + ], + [ + -0.21170248091220856, + -3.3281543254852295 + ], + [ + -0.2723718285560608, + -3.302432060241699 + ], + [ + -0.34380969405174255, + -3.275749921798706 + ], + [ + -0.3992260694503784, + -3.246654748916626 + ], + [ + -0.46620404720306396, + -3.2180066108703613 + ], + [ + -0.5265814661979675, + -3.1866307258605957 + ], + [ + -0.5939381718635559, + -3.163337469100952 + ], + [ + -0.6460328102111816, + -3.124067544937134 + ], + [ + -0.7015077471733093, + -3.0965065956115723 + ], + [ + -0.7640082836151123, + -3.0675580501556396 + ], + [ + -0.8160923719406128, + -3.0326144695281982 + ], + [ + -0.8679012060165405, + -2.9941489696502686 + ], + [ + -0.9287607073783875, + -2.962002754211426 + ], + [ + -0.9755229949951172, + -2.9234461784362793 + ], + [ + -1.0304805040359497, + -2.8904242515563965 + ], + [ + -1.0864734649658203, + -2.8560640811920166 + ], + [ + -1.1415740251541138, + -2.8213930130004883 + ], + [ + -1.183717966079712, + -2.784888982772827 + ], + [ + -1.2368931770324707, + -2.755326747894287 + ], + [ + -1.2737987041473389, + -2.7229831218719482 + ], + [ + -1.3212560415267944, + -2.685758113861084 + ], + [ + -1.3653281927108765, + -2.64980411529541 + ], + [ + -1.405971646308899, + -2.6100387573242188 + ], + [ + -1.4464161396026611, + -2.567636013031006 + ], + [ + -1.493051528930664, + -2.525590658187866 + ], + [ + -1.5327030420303345, + -2.4819538593292236 + ], + [ + -1.5684620141983032, + -2.4432735443115234 + ], + [ + -1.605922818183899, + -2.39829158782959 + ], + [ + -1.6048132181167603, + -2.3229587078094482 + ], + [ + -1.6605039834976196, + -2.2744462490081787 + ], + [ + -1.7071318626403809, + -2.227574348449707 + ], + [ + -1.7500349283218384, + -2.1794633865356445 + ], + [ + -1.7993409633636475, + -2.1189398765563965 + ], + [ + -1.836386799812317, + -2.072486639022827 + ], + [ + -1.8808753490447998, + -2.020357847213745 + ], + [ + -1.92780339717865, + -1.969286322593689 + ], + [ + -1.9594755172729492, + -1.9207892417907715 + ], + [ + -2.0088436603546143, + -1.8682963848114014 + ], + [ + -2.0492091178894043, + -1.8175262212753296 + ], + [ + -2.084040403366089, + -1.7681670188903809 + ], + [ + -2.115699291229248, + -1.713012933731079 + ], + [ + -2.1510543823242188, + -1.664438009262085 + ], + [ + -2.1793766021728516, + -1.6171830892562866 + ], + [ + -2.212108850479126, + -1.5620712041854858 + ], + [ + -2.240870237350464, + -1.513466238975525 + ], + [ + -2.2614545822143555, + -1.467106580734253 + ], + [ + -2.2861928939819336, + -1.4108941555023193 + ], + [ + -2.3061304092407227, + -1.3649297952651978 + ], + [ + -2.321974754333496, + -1.3184778690338135 + ], + [ + -2.3419272899627686, + -1.266212821006775 + ], + [ + -2.359661102294922, + -1.2157666683197021 + ], + [ + -2.370184898376465, + -1.1728568077087402 + ], + [ + -2.3765292167663574, + -1.123663067817688 + ], + [ + -2.394838333129883, + -1.070611834526062 + ], + [ + -2.4011104106903076, + -1.0235037803649902 + ], + [ + -2.4086596965789795, + -0.9745588898658752 + ], + [ + -2.4220168590545654, + -0.9217925071716309 + ], + [ + -2.4296045303344727, + -0.8675931096076965 + ], + [ + -2.4402730464935303, + -0.8134230375289917 + ], + [ + -2.449079751968384, + -0.7521125674247742 + ], + [ + -2.456794500350952, + -0.6988786458969116 + ], + [ + -2.4677929878234863, + -0.6402480602264404 + ], + [ + -2.480638265609741, + -0.580808162689209 + ], + [ + -2.490950584411621, + -0.5173661708831787 + ], + [ + -2.504044771194458, + -0.4566658139228821 + ], + [ + -2.5147287845611572, + -0.396787166595459 + ], + [ + -2.5251951217651367, + -0.33640173077583313 + ], + [ + -2.5316245555877686, + -0.2792854309082031 + ], + [ + -2.538483142852783, + -0.21798326075077057 + ], + [ + -2.5426151752471924, + -0.16182969510555267 + ], + [ + -2.529221534729004, + -0.1060233786702156 + ], + [ + -2.526434898376465, + -0.054749179631471634 + ], + [ + -2.5205626487731934, + 0.001243671285919845 + ], + [ + -2.5191307067871094, + 0.055930376052856445 + ], + [ + -2.510812997817993, + 0.11084281653165817 + ], + [ + -2.504183053970337, + 0.17086169123649597 + ], + [ + -2.499048948287964, + 0.22724038362503052 + ], + [ + -2.4935545921325684, + 0.2874954044818878 + ], + [ + -2.4819817543029785, + 0.3392045497894287 + ], + [ + -2.471379280090332, + 0.3965985178947449 + ], + [ + -2.463444948196411, + 0.45932573080062866 + ], + [ + -2.456040143966675, + 0.5179884433746338 + ], + [ + -2.448241949081421, + 0.5816112756729126 + ], + [ + -2.4314777851104736, + 0.630145788192749 + ], + [ + -2.4205219745635986, + 0.6895127296447754 + ], + [ + -2.409992218017578, + 0.7514999508857727 + ], + [ + -2.4032039642333984, + 0.8135987520217896 + ], + [ + -2.39882230758667, + 0.8755843639373779 + ], + [ + -2.37736439704895, + 0.9305745363235474 + ], + [ + -2.366499662399292, + 0.990943431854248 + ], + [ + -2.357231616973877, + 1.0467411279678345 + ], + [ + -2.350327968597412, + 1.104521632194519 + ], + [ + -2.3441240787506104, + 1.1588865518569946 + ], + [ + -2.3343863487243652, + 1.205670952796936 + ], + [ + -2.308683156967163, + 1.2629003524780273 + ], + [ + -2.303203582763672, + 1.3128381967544556 + ], + [ + -2.289451837539673, + 1.3636188507080078 + ], + [ + -2.2774157524108887, + 1.3961243629455566 + ], + [ + -2.2628729343414307, + 1.4268147945404053 + ], + [ + -2.2421505451202393, + 1.4900184869766235 + ], + [ + -2.2219769954681396, + 1.5293556451797485 + ], + [ + -2.2009596824645996, + 1.5621479749679565 + ], + [ + -2.1731245517730713, + 1.5913102626800537 + ], + [ + -2.1377811431884766, + 1.6258437633514404 + ], + [ + -2.1103458404541016, + 1.6767975091934204 + ], + [ + -2.0711004734039307, + 1.710074782371521 + ], + [ + -2.0301361083984375, + 1.7411441802978516 + ], + [ + -1.9808874130249023, + 1.7769041061401367 + ], + [ + -1.922986388206482, + 1.810672640800476 + ], + [ + -1.8686940670013428, + 1.8575408458709717 + ], + [ + -1.8298639059066772, + 1.907584547996521 + ], + [ + -1.7712719440460205, + 1.9500510692596436 + ], + [ + -1.7097042798995972, + 1.9956791400909424 + ], + [ + -1.6437488794326782, + 2.0589041709899902 + ], + [ + -1.5757232904434204, + 2.1094532012939453 + ], + [ + -1.5365235805511475, + 2.15700364112854 + ], + [ + -1.472760558128357, + 2.2160351276397705 + ], + [ + -1.4064444303512573, + 2.2732596397399902 + ], + [ + -1.3496158123016357, + 2.3316357135772705 + ], + [ + -1.2916313409805298, + 2.4088077545166016 + ], + [ + -1.2360960245132446, + 2.473083257675171 + ], + [ + -1.175458550453186, + 2.5230300426483154 + ], + [ + -1.1244251728057861, + 2.5934834480285645 + ], + [ + -1.064170241355896, + 2.635878801345825 + ], + [ + -1.0121403932571411, + 2.7022128105163574 + ], + [ + -0.9610819816589355, + 2.7678210735321045 + ], + [ + -0.9144902229309082, + 2.8268446922302246 + ], + [ + -0.842418909072876, + 2.8539211750030518 + ], + [ + -0.7861678600311279, + 2.9098942279815674 + ], + [ + -0.7291125059127808, + 2.950701951980591 + ], + [ + -0.6611655354499817, + 2.9964077472686768 + ], + [ + -0.6038023233413696, + 3.041938066482544 + ], + [ + -0.5423814058303833, + 3.0768930912017822 + ], + [ + -0.4600488245487213, + 3.106074810028076 + ], + [ + -0.38289114832878113, + 3.144099712371826 + ], + [ + -0.309813529253006, + 3.173097610473633 + ], + [ + -0.24277359247207642, + 3.2140707969665527 + ], + [ + -0.15723039209842682, + 3.243960380554199 + ], + [ + -0.08828762918710709, + 3.267181873321533 + ], + [ + -0.008930840529501438, + 3.287355661392212 + ], + [ + 0.07178688794374466, + 3.310429573059082 + ], + [ + 0.15234000980854034, + 3.3186588287353516 + ], + [ + 0.23271732032299042, + 3.3436827659606934 + ], + [ + 0.3166075646877289, + 3.3398520946502686 + ], + [ + 0.3897148668766022, + 3.343669891357422 + ], + [ + 0.5955437421798706, + 3.218120574951172 + ], + [ + 0.6851454377174377, + 3.226724863052368 + ], + [ + 0.7826934456825256, + 3.204862594604492 + ], + [ + 0.8815785646438599, + 3.2045650482177734 + ], + [ + 0.9851165413856506, + 3.2020394802093506 + ], + [ + 1.0844064950942993, + 3.2026255130767822 + ], + [ + 1.173680067062378, + 3.183821201324463 + ], + [ + 1.2785944938659668, + 3.1728577613830566 + ], + [ + 1.370327353477478, + 3.14701771736145 + ], + [ + 1.468676209449768, + 3.128272771835327 + ], + [ + 1.553820013999939, + 3.106248378753662 + ], + [ + 1.641091227531433, + 3.0704269409179688 + ], + [ + 1.7534809112548828, + 3.0373518466949463 + ], + [ + 1.8497077226638794, + 3.0063400268554688 + ], + [ + 1.9224870204925537, + 2.9584290981292725 + ], + [ + 2.003308057785034, + 2.9078426361083984 + ], + [ + 2.0791003704071045, + 2.865837574005127 + ], + [ + 2.175090789794922, + 2.814455032348633 + ], + [ + 2.2520110607147217, + 2.7419815063476562 + ], + [ + 2.32849383354187, + 2.671598434448242 + ], + [ + 2.399407386779785, + 2.6100258827209473 + ], + [ + 2.4672396183013916, + 2.517745018005371 + ], + [ + 2.545997142791748, + 2.4587039947509766 + ], + [ + 2.6144697666168213, + 2.378220796585083 + ], + [ + 2.681084632873535, + 2.2854955196380615 + ], + [ + 2.750967502593994, + 2.189547061920166 + ], + [ + 2.8138821125030518, + 2.0939536094665527 + ], + [ + 2.876966953277588, + 1.988460659980774 + ], + [ + 2.938584566116333, + 1.9027365446090698 + ], + [ + 2.996422290802002, + 1.8035085201263428 + ], + [ + 3.0549073219299316, + 1.6967881917953491 + ], + [ + 3.1184253692626953, + 1.5862998962402344 + ], + [ + 3.1695399284362793, + 1.4834251403808594 + ], + [ + 3.2144312858581543, + 1.3839423656463623 + ], + [ + 3.2623813152313232, + 1.2791887521743774 + ], + [ + 3.3066582679748535, + 1.1730176210403442 + ], + [ + 3.350222110748291, + 1.070255994796753 + ], + [ + 3.3910858631134033, + 0.9672503471374512 + ], + [ + 3.4249937534332275, + 0.8665592074394226 + ], + [ + 3.445951461791992, + 0.7716286778450012 + ], + [ + 3.474893093109131, + 0.6704950928688049 + ], + [ + 3.4899792671203613, + 0.5799676775932312 + ], + [ + 3.505995988845825, + 0.48729121685028076 + ], + [ + 3.5125479698181152, + 0.39767056703567505 + ], + [ + 3.518134832382202, + 0.3076687157154083 + ], + [ + 3.5149588584899902, + 0.22046197950839996 + ], + [ + 3.5032877922058105, + 0.13283494114875793 + ], + [ + 3.494771718978882, + 0.043862033635377884 + ], + [ + 3.476810932159424, + -0.04312371090054512 + ], + [ + 3.4544477462768555, + -0.1354731321334839 + ], + [ + 3.435561418533325, + -0.22908951342105865 + ], + [ + 3.4097483158111572, + -0.32553237676620483 + ], + [ + 3.3786540031433105, + -0.4162972569465637 + ], + [ + 3.3496816158294678, + -0.5202358961105347 + ], + [ + 3.3243372440338135, + -0.6182951331138611 + ], + [ + 3.3002586364746094, + -0.7227246761322021 + ], + [ + 3.2827959060668945, + -0.8269885778427124 + ], + [ + 3.27213978767395, + -0.9291151165962219 + ], + [ + 3.2417151927948, + -1.025143027305603 + ], + [ + 3.237226963043213, + -1.1158994436264038 + ], + [ + 3.23699951171875, + -1.1956021785736084 + ], + [ + 3.2257206439971924, + -1.26841402053833 + ], + [ + 3.2159929275512695, + -1.3283185958862305 + ], + [ + 3.2120769023895264, + -1.3763760328292847 + ], + [ + 3.1949729919433594, + -1.41744065284729 + ], + [ + 3.17425799369812, + -1.4698892831802368 + ], + [ + 3.1441164016723633, + -1.5058162212371826 + ], + [ + 3.1047325134277344, + -1.5348694324493408 + ], + [ + 3.0676915645599365, + -1.5614029169082642 + ], + [ + 3.016495704650879, + -1.5883408784866333 + ], + [ + 2.9508306980133057, + -1.6194665431976318 + ], + [ + 2.885591506958008, + -1.6466929912567139 + ], + [ + 2.8349356651306152, + -1.6702629327774048 + ], + [ + 2.7654080390930176, + -1.7033709287643433 + ], + [ + 2.6996731758117676, + -1.7352293729782104 + ], + [ + 2.636242389678955, + -1.7713606357574463 + ], + [ + 2.5768725872039795, + -1.8075677156448364 + ], + [ + 2.4974255561828613, + -1.8423837423324585 + ], + [ + 2.4330191612243652, + -1.8636884689331055 + ], + [ + 2.3536198139190674, + -1.8981739282608032 + ], + [ + 2.2794363498687744, + -1.9323822259902954 + ], + [ + 2.206479072570801, + -1.9795141220092773 + ], + [ + 2.1204702854156494, + -2.0155320167541504 + ], + [ + 2.046868324279785, + -2.0643913745880127 + ], + [ + 1.9649845361709595, + -2.1055781841278076 + ], + [ + 1.8975412845611572, + -2.179184913635254 + ], + [ + 1.8286213874816895, + -2.2107667922973633 + ], + [ + 1.7608011960983276, + -2.257697105407715 + ], + [ + 1.7032718658447266, + -2.307563066482544 + ], + [ + 1.6386715173721313, + -2.354464292526245 + ], + [ + 1.5691574811935425, + -2.4087562561035156 + ], + [ + 1.5212318897247314, + -2.449023723602295 + ], + [ + 1.4672671556472778, + -2.4996225833892822 + ], + [ + 1.5009409189224243, + -2.4192283153533936 + ], + [ + 1.4500819444656372, + -2.456528663635254 + ], + [ + 1.3855098485946655, + -2.4812490940093994 + ], + [ + 1.3002737760543823, + -2.504312515258789 + ], + [ + 1.22319495677948, + -2.537794828414917 + ], + [ + 1.1494805812835693, + -2.55678129196167 + ], + [ + 1.133719563484192, + -2.5704128742218018 + ], + [ + 1.0643234252929688, + -2.5888798236846924 + ], + [ + 0.995461106300354, + -2.6118075847625732 + ], + [ + 0.9267024993896484, + -2.64353609085083 + ], + [ + 0.8668304681777954, + -2.669434070587158 + ], + [ + 0.7998504638671875, + -2.6822879314422607 + ], + [ + 0.7546790242195129, + -2.675503730773926 + ], + [ + 0.697958767414093, + -2.6988062858581543 + ], + [ + 0.638871431350708, + -2.712935209274292 + ], + [ + 0.578364372253418, + -2.7236483097076416 + ], + [ + 0.5223606824874878, + -2.746241807937622 + ], + [ + 0.47130319476127625, + -2.7622056007385254 + ], + [ + 0.4051983654499054, + -2.7417197227478027 + ], + [ + 0.3466250002384186, + -2.744666814804077 + ], + [ + 0.29724279046058655, + -2.7546770572662354 + ], + [ + 0.25007909536361694, + -2.7691895961761475 + ], + [ + 0.20525386929512024, + -2.781912326812744 + ], + [ + 0.15940922498703003, + -2.783461570739746 + ], + [ + 0.09599704295396805, + -2.768907308578491 + ], + [ + 0.03733213618397713, + -2.7654531002044678 + ], + [ + -0.008323164656758308, + -2.7677056789398193 + ], + [ + -0.046334780752658844, + -2.7688887119293213 + ], + [ + -0.08804736286401749, + -2.7702887058258057 + ], + [ + -0.1298413723707199, + -2.761005401611328 + ], + [ + -0.19627666473388672, + -2.740018844604492 + ], + [ + -0.24418671429157257, + -2.7336792945861816 + ], + [ + -0.28433552384376526, + -2.741023063659668 + ], + [ + -0.3271116018295288, + -2.730717420578003 + ], + [ + -0.3580382764339447, + -2.715604782104492 + ], + [ + -0.40478000044822693, + -2.695084810256958 + ], + [ + -0.4276863932609558, + -2.682771921157837 + ], + [ + -0.496025025844574, + -2.676379442214966 + ], + [ + -0.5495452880859375, + -2.6579699516296387 + ], + [ + -0.5784173607826233, + -2.6480791568756104 + ], + [ + -0.6109502911567688, + -2.6307339668273926 + ], + [ + -0.647429347038269, + -2.6043572425842285 + ], + [ + -0.6884409785270691, + -2.57822322845459 + ], + [ + -0.7192516326904297, + -2.556623935699463 + ], + [ + -0.7797537446022034, + -2.552372932434082 + ], + [ + -0.8116699457168579, + -2.540623188018799 + ], + [ + -0.8420299291610718, + -2.4984960556030273 + ], + [ + -0.8794967532157898, + -2.4755544662475586 + ], + [ + -0.9332261681556702, + -2.4403457641601562 + ], + [ + -0.9615112543106079, + -2.406348705291748 + ], + [ + -0.9980156421661377, + -2.395333766937256 + ], + [ + -1.033725380897522, + -2.369969606399536 + ], + [ + -1.0806766748428345, + -2.3278517723083496 + ], + [ + -1.1194381713867188, + -2.2923967838287354 + ], + [ + -1.1609915494918823, + -2.2569589614868164 + ], + [ + -1.2230334281921387, + -2.217268705368042 + ], + [ + -1.2706917524337769, + -2.186044692993164 + ], + [ + -1.2996994256973267, + -2.1634130477905273 + ], + [ + -1.3376612663269043, + -2.124155282974243 + ], + [ + -1.3976279497146606, + -2.085653781890869 + ], + [ + -1.4516701698303223, + -2.049926280975342 + ], + [ + -1.5081223249435425, + -2.0267317295074463 + ], + [ + -1.5665534734725952, + -1.993950605392456 + ], + [ + -1.6138639450073242, + -1.9741146564483643 + ], + [ + -1.6731669902801514, + -1.9527398347854614 + ], + [ + -1.6983003616333008, + -1.9092656373977661 + ], + [ + -1.744866132736206, + -1.884913682937622 + ], + [ + -1.8000377416610718, + -1.8678312301635742 + ], + [ + -1.8452894687652588, + -1.849016785621643 + ], + [ + -1.885560154914856, + -1.8317625522613525 + ], + [ + -1.9316139221191406, + -1.8239861726760864 + ], + [ + -1.959079384803772, + -1.8154456615447998 + ], + [ + -1.9968845844268799, + -1.7626343965530396 + ], + [ + -2.0348501205444336, + -1.7445290088653564 + ], + [ + -2.0650062561035156, + -1.7291451692581177 + ], + [ + -2.091242790222168, + -1.710782766342163 + ], + [ + -2.11623215675354, + -1.6973191499710083 + ], + [ + -2.134791851043701, + -1.6707322597503662 + ], + [ + -2.1473960876464844, + -1.6441712379455566 + ], + [ + -2.162141799926758, + -1.6190418004989624 + ], + [ + -2.2083170413970947, + -1.5839571952819824 + ], + [ + -2.226473808288574, + -1.549389362335205 + ], + [ + -2.23994779586792, + -1.5129443407058716 + ], + [ + -2.252565622329712, + -1.477996587753296 + ], + [ + -2.78383207321167, + -1.9184504747390747 + ], + [ + -2.81541109085083, + -1.8691060543060303 + ], + [ + -2.852649211883545, + -1.8160136938095093 + ], + [ + -2.892374277114868, + -1.762527585029602 + ], + [ + -2.9250311851501465, + -1.704882264137268 + ], + [ + -2.9609439373016357, + -1.6493961811065674 + ], + [ + -2.9955637454986572, + -1.5960826873779297 + ], + [ + -3.0291807651519775, + -1.5283302068710327 + ], + [ + -3.0681416988372803, + -1.4694125652313232 + ], + [ + -3.0982275009155273, + -1.406285285949707 + ], + [ + -3.1307730674743652, + -1.3378543853759766 + ], + [ + -3.1572413444519043, + -1.270751953125 + ], + [ + -1.9380855560302734, + -0.6883788108825684 + ], + [ + -1.9539645910263062, + -0.6436565518379211 + ], + [ + -1.9698492288589478, + -0.6022300124168396 + ], + [ + -1.984263300895691, + -0.5572729110717773 + ], + [ + -1.99543297290802, + -0.5110287070274353 + ], + [ + -2.009932518005371, + -0.46588271856307983 + ], + [ + -2.0193886756896973, + -0.41902682185173035 + ], + [ + -2.029484987258911, + -0.37220147252082825 + ], + [ + -2.0378780364990234, + -0.3251928389072418 + ], + [ + -2.046769142150879, + -0.276787132024765 + ], + [ + -2.052847146987915, + -0.22963036596775055 + ], + [ + -2.0610249042510986, + -0.18195399641990662 + ], + [ + -2.0661861896514893, + -0.13325776159763336 + ], + [ + -2.0708963871002197, + -0.08549626171588898 + ], + [ + -2.0733466148376465, + -0.03532441332936287 + ], + [ + -2.0761170387268066, + 0.013022692874073982 + ], + [ + -2.079572916030884, + 0.062113918364048004 + ], + [ + -2.080350637435913, + 0.11314381659030914 + ], + [ + -2.0780787467956543, + 0.16448721289634705 + ], + [ + -2.0765087604522705, + 0.2175370454788208 + ], + [ + -2.0738766193389893, + 0.2669138014316559 + ], + [ + -2.071141481399536, + 0.31845659017562866 + ], + [ + -2.065922737121582, + 0.37100738286972046 + ], + [ + -2.057194232940674, + 0.42432793974876404 + ], + [ + -2.047513723373413, + 0.4752269685268402 + ], + [ + -2.0371851921081543, + 0.5302570462226868 + ], + [ + -2.0283968448638916, + 0.5772792100906372 + ], + [ + -2.0118343830108643, + 0.628349781036377 + ], + [ + -1.9993886947631836, + 0.6841157078742981 + ], + [ + -1.9844900369644165, + 0.7354881167411804 + ], + [ + -1.9636952877044678, + 0.7873414158821106 + ], + [ + -1.948403239250183, + 0.8365822434425354 + ], + [ + -1.9277675151824951, + 0.8878859877586365 + ], + [ + -1.9058691263198853, + 0.9357561469078064 + ], + [ + -1.8817299604415894, + 0.9855124950408936 + ], + [ + -1.8545794486999512, + 1.0340702533721924 + ], + [ + -1.824047327041626, + 1.0801208019256592 + ], + [ + -1.7984544038772583, + 1.1288622617721558 + ], + [ + -1.7695046663284302, + 1.1742796897888184 + ], + [ + -1.743006706237793, + 1.216750144958496 + ], + [ + -1.7113457918167114, + 1.2655538320541382 + ], + [ + -1.6754268407821655, + 1.3096429109573364 + ], + [ + -1.6407458782196045, + 1.349297046661377 + ], + [ + -1.6049975156784058, + 1.399564266204834 + ], + [ + -1.5673831701278687, + 1.4378405809402466 + ], + [ + -1.5314748287200928, + 1.478584885597229 + ], + [ + -1.4941333532333374, + 1.5177613496780396 + ], + [ + -1.451605200767517, + 1.553012490272522 + ], + [ + -1.4090631008148193, + 1.5914047956466675 + ], + [ + -1.3660334348678589, + 1.6314921379089355 + ], + [ + -1.3212428092956543, + 1.6584669351577759 + ], + [ + -1.2847487926483154, + 1.695683479309082 + ], + [ + -1.239618182182312, + 1.7258050441741943 + ], + [ + -1.1955772638320923, + 1.7601600885391235 + ], + [ + -1.1494011878967285, + 1.7910526990890503 + ], + [ + -1.1041163206100464, + 1.820495843887329 + ], + [ + -1.0585615634918213, + 1.8393077850341797 + ], + [ + -1.0019176006317139, + 1.8761601448059082 + ], + [ + -0.9682443737983704, + 1.8880077600479126 + ], + [ + -0.9219959378242493, + 1.912929892539978 + ], + [ + -0.8795483708381653, + 1.9264955520629883 + ], + [ + -0.8209273219108582, + 1.9531574249267578 + ], + [ + -0.7849046587944031, + 1.9620777368545532 + ], + [ + -0.7301197648048401, + 1.9839946031570435 + ], + [ + -0.682068407535553, + 1.9913098812103271 + ], + [ + -0.6285606026649475, + 2.0201992988586426 + ], + [ + -0.5745037198066711, + 2.0337696075439453 + ], + [ + -0.5288074612617493, + 2.0397353172302246 + ], + [ + -0.48121413588523865, + 2.0474658012390137 + ], + [ + -0.43760737776756287, + 2.0541484355926514 + ], + [ + -0.371258944272995, + 2.061300277709961 + ], + [ + -0.3241967260837555, + 2.0577597618103027 + ], + [ + -0.27276894450187683, + 2.0671439170837402 + ], + [ + -0.20828048884868622, + 2.078331232070923 + ], + [ + -0.17114131152629852, + 2.0709071159362793 + ], + [ + -0.1264704018831253, + 2.0672523975372314 + ], + [ + -0.05756198242306709, + 2.068589687347412 + ], + [ + -0.004726169630885124, + 2.069282293319702 + ], + [ + 0.041941333562135696, + 2.0694549083709717 + ], + [ + 0.09481298923492432, + 2.0708913803100586 + ], + [ + 0.14318425953388214, + 2.0630621910095215 + ], + [ + 0.19452641904354095, + 2.054288864135742 + ], + [ + 0.23503521084785461, + 2.0475995540618896 + ], + [ + 0.2940577268600464, + 2.0348284244537354 + ], + [ + 0.3435291647911072, + 2.0185084342956543 + ], + [ + 0.3899754285812378, + 1.9940866231918335 + ], + [ + 0.44514045119285583, + 1.987296223640442 + ], + [ + 0.49963778257369995, + 1.9780362844467163 + ], + [ + 0.5432239174842834, + 1.9556283950805664 + ], + [ + 0.597311794757843, + 1.9338351488113403 + ], + [ + 0.638418436050415, + 1.9164409637451172 + ], + [ + 0.7020017504692078, + 1.8963285684585571 + ], + [ + 0.7493473291397095, + 1.872326135635376 + ], + [ + 0.7867827415466309, + 1.8511407375335693 + ], + [ + 0.8330151438713074, + 1.8203294277191162 + ], + [ + 0.8834162950515747, + 1.8019412755966187 + ], + [ + 0.9229590892791748, + 1.766094446182251 + ], + [ + 0.9782407879829407, + 1.7372257709503174 + ], + [ + 1.0288684368133545, + 1.7072659730911255 + ], + [ + 1.065182089805603, + 1.6753075122833252 + ], + [ + 1.11155104637146, + 1.6489750146865845 + ], + [ + 1.151719331741333, + 1.6148185729980469 + ], + [ + 1.1954255104064941, + 1.5863491296768188 + ], + [ + 1.236830472946167, + 1.541528582572937 + ], + [ + 1.2737972736358643, + 1.5131182670593262 + ], + [ + 1.3260818719863892, + 1.4746484756469727 + ], + [ + 1.36090886592865, + 1.4285876750946045 + ], + [ + 1.402835726737976, + 1.3900694847106934 + ], + [ + 1.4457191228866577, + 1.3517640829086304 + ], + [ + 1.4818195104599, + 1.3147666454315186 + ], + [ + 1.517524003982544, + 1.2623660564422607 + ], + [ + 1.5570950508117676, + 1.2226229906082153 + ], + [ + 1.5941731929779053, + 1.1743744611740112 + ], + [ + 1.624515175819397, + 1.1314665079116821 + ], + [ + 1.6562050580978394, + 1.08854079246521 + ], + [ + 1.687606930732727, + 1.038882851600647 + ], + [ + 1.717451572418213, + 0.9889068007469177 + ], + [ + 1.7500394582748413, + 0.9415645003318787 + ], + [ + 1.7694522142410278, + 0.8920074701309204 + ], + [ + 1.8013734817504883, + 0.8403857946395874 + ], + [ + 1.8279688358306885, + 0.7857481837272644 + ], + [ + 1.8541896343231201, + 0.7365115284919739 + ], + [ + 1.8755598068237305, + 0.6822115182876587 + ], + [ + 1.8985124826431274, + 0.6294991374015808 + ], + [ + 1.9172627925872803, + 0.5765904188156128 + ], + [ + 1.9349926710128784, + 0.5222132205963135 + ], + [ + 1.9525282382965088, + 0.4689784049987793 + ], + [ + 1.9680323600769043, + 0.4149859547615051 + ], + [ + 1.9855445623397827, + 0.3596999943256378 + ], + [ + 1.9973862171173096, + 0.30578136444091797 + ], + [ + 2.009310245513916, + 0.24962782859802246 + ], + [ + 2.0185320377349854, + 0.19416746497154236 + ], + [ + 2.028869152069092, + 0.13947853446006775 + ], + [ + 2.036054849624634, + 0.08381349593400955 + ], + [ + 2.043839693069458, + 0.026876620948314667 + ], + [ + 2.047823190689087, + -0.026117859408259392 + ], + [ + 2.0524981021881104, + -0.08355418592691422 + ], + [ + 2.054903030395508, + -0.13745705783367157 + ], + [ + 2.056946277618408, + -0.19462838768959045 + ], + [ + 2.055304765701294, + -0.24314460158348083 + ], + [ + 2.054277181625366, + -0.29815205931663513 + ], + [ + 2.0460102558135986, + -0.35359829664230347 + ], + [ + 2.04443621635437, + -0.41113266348838806 + ], + [ + 2.0418765544891357, + -0.46590274572372437 + ], + [ + 2.033726692199707, + -0.5201364159584045 + ], + [ + 2.0248093605041504, + -0.574977695941925 + ], + [ + 2.016324520111084, + -0.6304615139961243 + ], + [ + 2.0082128047943115, + -0.6856181025505066 + ], + [ + 1.9933602809906006, + -0.7404115200042725 + ], + [ + 1.9723544120788574, + -0.7907381057739258 + ], + [ + 1.958863377571106, + -0.8481918573379517 + ], + [ + 1.9404971599578857, + -0.89897620677948 + ], + [ + 1.935922622680664, + -0.9510582089424133 + ], + [ + 1.908974051475525, + -0.9920832514762878 + ], + [ + 1.8878103494644165, + -1.0427801609039307 + ], + [ + 1.8676782846450806, + -1.0958209037780762 + ], + [ + 1.8463996648788452, + -1.1454715728759766 + ], + [ + 1.8212183713912964, + -1.1958879232406616 + ], + [ + 1.8029154539108276, + -1.2402688264846802 + ], + [ + 1.7619487047195435, + -1.2830486297607422 + ], + [ + 1.7421542406082153, + -1.3255712985992432 + ], + [ + 1.7084834575653076, + -1.3678600788116455 + ], + [ + 1.6844680309295654, + -1.4156501293182373 + ], + [ + 1.6508656740188599, + -1.4516429901123047 + ], + [ + 1.6228188276290894, + -1.5020347833633423 + ], + [ + 1.5825233459472656, + -1.549485445022583 + ], + [ + 1.5508432388305664, + -1.5798356533050537 + ], + [ + 1.509741187095642, + -1.6315580606460571 + ], + [ + 1.4766863584518433, + -1.6636579036712646 + ], + [ + 1.435693621635437, + -1.67301607131958 + ], + [ + 1.4002169370651245, + -1.7054946422576904 + ], + [ + 1.3483387231826782, + -1.7377771139144897 + ], + [ + 1.2997816801071167, + -1.7787861824035645 + ], + [ + 1.2730140686035156, + -1.8117561340332031 + ], + [ + 1.2179744243621826, + -1.8475978374481201 + ], + [ + 1.1754355430603027, + -1.8653144836425781 + ], + [ + 1.139968991279602, + -1.9006057977676392 + ], + [ + 1.0985162258148193, + -1.9248286485671997 + ], + [ + 1.0543622970581055, + -1.9512182474136353 + ], + [ + 0.9737867116928101, + -1.9225974082946777 + ], + [ + 0.9292001128196716, + -1.9363741874694824 + ], + [ + 0.8985954523086548, + -1.9590561389923096 + ], + [ + 0.8628448843955994, + -1.9969673156738281 + ], + [ + 0.8132723569869995, + -2.0270328521728516 + ], + [ + 0.7748539447784424, + -2.0811333656311035 + ], + [ + 0.7201080322265625, + -2.128350257873535 + ], + [ + 0.674480140209198, + -2.164024591445923 + ], + [ + 0.6097591519355774, + -2.1993448734283447 + ], + [ + 0.5379068851470947, + -2.2151191234588623 + ], + [ + 0.4605502486228943, + -2.186469554901123 + ], + [ + 0.374421089887619, + -2.1796953678131104 + ], + [ + 0.24945984780788422, + -2.156703472137451 + ], + [ + 0.12590625882148743, + -2.103966236114502 + ], + [ + -0.04627525061368942, + -2.0166218280792236 + ], + [ + -0.21604974567890167, + -1.8991401195526123 + ], + [ + -0.3773510158061981, + -1.7553536891937256 + ], + [ + -0.4773394763469696, + -1.6348859071731567 + ], + [ + -0.5326268076896667, + -1.5850635766983032 + ], + [ + -0.5514856576919556, + -1.5728226900100708 + ], + [ + -0.598037600517273, + -1.8903489112854004 + ], + [ + -0.622115433216095, + -1.9592177867889404 + ], + [ + -0.6437075138092041, + -1.988045573234558 + ], + [ + -0.6556848883628845, + -1.9551438093185425 + ], + [ + -0.6759403347969055, + -1.8992161750793457 + ], + [ + -0.6707873940467834, + -1.808581829071045 + ], + [ + -0.6468885540962219, + -1.7211400270462036 + ], + [ + -0.6272684335708618, + -1.6360712051391602 + ], + [ + -0.5944616794586182, + -1.5511319637298584 + ], + [ + -0.5465524792671204, + -1.4786964654922485 + ], + [ + -0.5037870407104492, + -1.4354517459869385 + ], + [ + -0.5725539326667786, + -1.5349169969558716 + ], + [ + -0.5471444725990295, + -1.4766018390655518 + ], + [ + -0.519547700881958, + -1.4369913339614868 + ], + [ + -0.4901757836341858, + -1.424714207649231 + ], + [ + -0.4900718331336975, + -1.4539103507995605 + ], + [ + -0.53978431224823, + -1.5410423278808594 + ], + [ + -0.637194812297821, + -1.7019968032836914 + ], + [ + -0.8000913262367249, + -1.8834871053695679 + ], + [ + -0.9615679979324341, + -2.0561747550964355 + ], + [ + -1.0844463109970093, + -2.1618261337280273 + ], + [ + -1.1968845129013062, + -2.181901454925537 + ], + [ + -1.274216651916504, + -2.159606456756592 + ], + [ + -1.2934643030166626, + -2.129103660583496 + ], + [ + -1.366523265838623, + -2.1082522869110107 + ], + [ + -1.4462443590164185, + -2.0791194438934326 + ], + [ + -1.5177831649780273, + -2.0226950645446777 + ], + [ + -1.575477957725525, + -1.9703705310821533 + ], + [ + -1.629645586013794, + -1.9028712511062622 + ], + [ + -1.6782840490341187, + -1.8251471519470215 + ], + [ + -1.7094380855560303, + -1.7280670404434204 + ], + [ + -1.732791781425476, + -1.65084969997406 + ], + [ + -1.750014305114746, + -1.579086184501648 + ], + [ + -1.7655457258224487, + -1.5224220752716064 + ], + [ + -1.7894172668457031, + -1.497114896774292 + ], + [ + -1.8682295083999634, + -1.4840717315673828 + ], + [ + -1.9241061210632324, + -1.4779654741287231 + ], + [ + -1.9716140031814575, + -1.4744826555252075 + ], + [ + -2.040992021560669, + -1.4951095581054688 + ], + [ + -2.1071548461914062, + -1.4898571968078613 + ], + [ + -2.2005820274353027, + -1.502853512763977 + ], + [ + -2.2576258182525635, + -1.495966911315918 + ], + [ + -2.337153196334839, + -1.4704077243804932 + ], + [ + -2.4135353565216064, + -1.437909483909607 + ], + [ + -2.4689152240753174, + -1.388046145439148 + ], + [ + -2.5360958576202393, + -1.3233281373977661 + ], + [ + -2.583467483520508, + -1.263997197151184 + ], + [ + -2.6233677864074707, + -1.196539282798767 + ], + [ + -2.682339906692505, + -1.1468843221664429 + ], + [ + -2.723759889602661, + -1.072885513305664 + ], + [ + -2.7704527378082275, + -0.9998670220375061 + ], + [ + -2.8042404651641846, + -0.9299346208572388 + ], + [ + -2.837991952896118, + -0.8568917512893677 + ], + [ + -2.861842155456543, + -0.7851209044456482 + ], + [ + -2.88008451461792, + -0.7079487442970276 + ], + [ + -2.893794536590576, + -0.634796142578125 + ], + [ + -2.904224395751953, + -0.5563355684280396 + ], + [ + -2.915236473083496, + -0.4878695011138916 + ], + [ + -2.9202823638916016, + -0.41744235157966614 + ], + [ + -2.921903371810913, + -0.3397843539714813 + ], + [ + -3.0145175457000732, + -0.2529560625553131 + ], + [ + -3.0264415740966797, + -0.17502547800540924 + ], + [ + -3.0318305492401123, + -0.09972938150167465 + ], + [ + -3.038008689880371, + -0.016703523695468903 + ], + [ + -3.0404345989227295, + 0.059328556060791016 + ], + [ + -3.0353798866271973, + 0.1343202292919159 + ], + [ + -3.0316519737243652, + 0.20866142213344574 + ], + [ + -3.0256175994873047, + 0.2845892608165741 + ], + [ + -3.010704278945923, + 0.3639020025730133 + ], + [ + -2.9976322650909424, + 0.4364193379878998 + ], + [ + -2.9898602962493896, + 0.5105920433998108 + ], + [ + -2.971163272857666, + 0.5888691544532776 + ], + [ + -2.9598042964935303, + 0.6607742309570312 + ], + [ + -2.978879928588867, + 0.762128472328186 + ], + [ + -2.9655888080596924, + 0.8466154336929321 + ], + [ + -2.9351940155029297, + 0.9054494500160217 + ], + [ + -2.928161382675171, + 0.9873949289321899 + ], + [ + -2.8943119049072266, + 1.0515342950820923 + ], + [ + -2.875150442123413, + 1.1282998323440552 + ], + [ + -2.855342388153076, + 1.192117691040039 + ], + [ + -2.8341405391693115, + 1.2762222290039062 + ], + [ + -2.7973663806915283, + 1.3636690378189087 + ], + [ + -2.754195213317871, + 1.4278630018234253 + ], + [ + -2.7152647972106934, + 1.5083065032958984 + ], + [ + -2.6492249965667725, + 1.5968408584594727 + ], + [ + -2.599494218826294, + 1.6504764556884766 + ], + [ + -2.522571325302124, + 1.7046879529953003 + ], + [ + -2.4791362285614014, + 1.7740017175674438 + ], + [ + -2.4095921516418457, + 1.800781011581421 + ], + [ + -2.3618650436401367, + 1.8412598371505737 + ], + [ + -2.307298183441162, + 1.8686833381652832 + ], + [ + -2.2835962772369385, + 1.8974324464797974 + ], + [ + -2.2305243015289307, + 1.9392350912094116 + ], + [ + -2.1853830814361572, + 1.981205701828003 + ], + [ + -2.1281871795654297, + 2.0150463581085205 + ], + [ + -2.076122522354126, + 2.0725135803222656 + ], + [ + -2.0110578536987305, + 2.0940842628479004 + ], + [ + -1.9517617225646973, + 2.1355323791503906 + ], + [ + -1.9108619689941406, + 2.160658836364746 + ], + [ + -1.8512316942214966, + 2.19598650932312 + ], + [ + -1.7941250801086426, + 2.2212038040161133 + ], + [ + -1.7142581939697266, + 2.239269733428955 + ], + [ + -1.6714472770690918, + 2.280702829360962 + ], + [ + -1.6131047010421753, + 2.2862355709075928 + ], + [ + -1.562179684638977, + 2.308950185775757 + ], + [ + -1.498357892036438, + 2.312562942504883 + ], + [ + -1.449854850769043, + 2.316478967666626 + ], + [ + -1.4023306369781494, + 2.3446264266967773 + ], + [ + -1.334855079650879, + 2.3224024772644043 + ], + [ + -1.29624342918396, + 2.3476991653442383 + ], + [ + -1.2471070289611816, + 2.354393243789673 + ], + [ + -1.1984647512435913, + 2.3637397289276123 + ], + [ + -1.1420395374298096, + 2.3655200004577637 + ], + [ + -1.0960220098495483, + 2.366576671600342 + ], + [ + -1.0511646270751953, + 2.37448787689209 + ], + [ + -1.010246992111206, + 2.375934600830078 + ], + [ + -0.968824565410614, + 2.379575252532959 + ], + [ + -0.9229269027709961, + 2.4052062034606934 + ], + [ + -0.8862336874008179, + 2.401733160018921 + ], + [ + -0.842303454875946, + 2.4060678482055664 + ], + [ + -0.8037586212158203, + 2.4109411239624023 + ], + [ + -0.7627965807914734, + 2.420011281967163 + ], + [ + -0.7253597378730774, + 2.4441001415252686 + ], + [ + -0.6782451272010803, + 2.452685594558716 + ], + [ + -0.6327608227729797, + 2.4661078453063965 + ], + [ + -0.5909157991409302, + 2.480522632598877 + ], + [ + -0.5482114553451538, + 2.486630439758301 + ], + [ + -0.5011916160583496, + 2.492614507675171 + ], + [ + -0.45574095845222473, + 2.5048725605010986 + ], + [ + -0.390829861164093, + 2.511174201965332 + ], + [ + -0.342649906873703, + 2.5371549129486084 + ], + [ + -0.2797778844833374, + 2.541555404663086 + ], + [ + -0.2286921888589859, + 2.5403940677642822 + ], + [ + -0.18279117345809937, + 2.551239490509033 + ], + [ + -0.13283418118953705, + 2.5483908653259277 + ], + [ + -0.0708540603518486, + 2.560777187347412 + ], + [ + 0.024043936282396317, + 2.5515761375427246 + ], + [ + 0.03028048388659954, + 2.5083272457122803 + ], + [ + 0.10710986703634262, + 2.5486557483673096 + ], + [ + 0.17008113861083984, + 2.549680233001709 + ], + [ + 0.24953307211399078, + 2.5418004989624023 + ], + [ + 0.30024293065071106, + 2.5391008853912354 + ], + [ + 0.3429979085922241, + 2.5217323303222656 + ], + [ + 0.4159901738166809, + 2.521519422531128 + ], + [ + 0.47373107075691223, + 2.5157485008239746 + ], + [ + 0.524078369140625, + 2.509305477142334 + ], + [ + 0.5962390899658203, + 2.4918675422668457 + ], + [ + 0.6588370203971863, + 2.4890174865722656 + ], + [ + 0.7404631972312927, + 2.4751152992248535 + ], + [ + 0.8030050992965698, + 2.4839816093444824 + ], + [ + 0.8635808825492859, + 2.422895669937134 + ], + [ + 0.91105717420578, + 2.4169883728027344 + ], + [ + 0.9947924613952637, + 2.3888330459594727 + ], + [ + 1.0439144372940063, + 2.3685131072998047 + ], + [ + 1.107153296470642, + 2.343599319458008 + ], + [ + 1.1876583099365234, + 2.3209259510040283 + ], + [ + 1.2479437589645386, + 2.2808032035827637 + ], + [ + 1.3218940496444702, + 2.250570774078369 + ], + [ + 1.373680591583252, + 2.2055141925811768 + ], + [ + 1.4432079792022705, + 2.1708872318267822 + ], + [ + 1.4946486949920654, + 2.162463426589966 + ], + [ + 1.553925633430481, + 2.123990058898926 + ], + [ + 1.6181914806365967, + 2.058317184448242 + ], + [ + 1.6876637935638428, + 2.02586030960083 + ], + [ + 1.7481547594070435, + 1.9890433549880981 + ], + [ + 1.809153437614441, + 1.933681845664978 + ], + [ + 1.8669540882110596, + 1.8942006826400757 + ], + [ + 1.919399619102478, + 1.841854214668274 + ], + [ + 1.9755386114120483, + 1.7956392765045166 + ], + [ + 2.0300326347351074, + 1.7439833879470825 + ], + [ + 2.091309070587158, + 1.695483684539795 + ], + [ + 2.148446559906006, + 1.6328012943267822 + ], + [ + 2.1839499473571777, + 1.5836869478225708 + ], + [ + 2.238593101501465, + 1.5243022441864014 + ], + [ + 2.294283628463745, + 1.4749318361282349 + ], + [ + 2.3304941654205322, + 1.4199213981628418 + ], + [ + 2.388575553894043, + 1.365835189819336 + ], + [ + 2.4338157176971436, + 1.296130657196045 + ], + [ + 2.4821925163269043, + 1.2409878969192505 + ], + [ + 2.5278828144073486, + 1.1672979593276978 + ], + [ + 2.564948320388794, + 1.1020289659500122 + ], + [ + 2.6156561374664307, + 1.0373183488845825 + ], + [ + 2.6563796997070312, + 0.9668243527412415 + ], + [ + 2.692079782485962, + 0.8934832811355591 + ], + [ + 2.724677085876465, + 0.8367851376533508 + ], + [ + 2.7628159523010254, + 0.7641658782958984 + ], + [ + 2.797292470932007, + 0.686201274394989 + ], + [ + 2.8267428874969482, + 0.6147071719169617 + ], + [ + 2.8618571758270264, + 0.5417126417160034 + ], + [ + 2.890450954437256, + 0.46134036779403687 + ], + [ + 2.918351411819458, + 0.3803557753562927 + ], + [ + 2.9475486278533936, + 0.29778286814689636 + ], + [ + 2.9705750942230225, + 0.20889297127723694 + ], + [ + 2.998361825942993, + 0.11736880987882614 + ], + [ + 3.022660493850708, + 0.02709048055112362 + ], + [ + 3.0429635047912598, + -0.0681716650724411 + ], + [ + 3.0612332820892334, + -0.14247366786003113 + ], + [ + 3.063608407974243, + -0.22682476043701172 + ], + [ + 3.0752410888671875, + -0.32700252532958984 + ], + [ + 3.0852322578430176, + -0.41678643226623535 + ], + [ + 3.0866007804870605, + -0.5074594020843506 + ], + [ + 3.097771644592285, + -0.6009349822998047 + ], + [ + 3.0955634117126465, + -0.7009536623954773 + ], + [ + 3.101332902908325, + -0.8072454333305359 + ], + [ + 3.0885508060455322, + -0.9024137854576111 + ], + [ + 3.093280792236328, + -1.0160462856292725 + ], + [ + 3.089223861694336, + -1.1252834796905518 + ], + [ + 3.078591823577881, + -1.2293174266815186 + ], + [ + 3.0712246894836426, + -1.344851016998291 + ], + [ + 3.087702751159668, + -1.4397118091583252 + ], + [ + 3.0100061893463135, + -1.509589433670044 + ], + [ + 2.971369504928589, + -1.6382838487625122 + ], + [ + 2.933138608932495, + -1.7576050758361816 + ], + [ + 2.9044198989868164, + -1.854831576347351 + ], + [ + 2.839939832687378, + -1.9654569625854492 + ], + [ + 2.812039852142334, + -2.0830345153808594 + ], + [ + 2.759403705596924, + -2.1885666847229004 + ], + [ + 2.709089756011963, + -2.296311616897583 + ], + [ + 2.634334087371826, + -2.3959479331970215 + ], + [ + 2.58689284324646, + -2.5042874813079834 + ], + [ + 2.505211591720581, + -2.635150909423828 + ], + [ + 2.4041032791137695, + -2.7511534690856934 + ], + [ + 2.2947466373443604, + -2.8496689796447754 + ], + [ + 2.2071056365966797, + -2.8912932872772217 + ], + [ + 2.096127510070801, + -3.0130624771118164 + ], + [ + 2.034186363220215, + -3.127345085144043 + ], + [ + 1.9279834032058716, + -3.1662635803222656 + ], + [ + 1.8161029815673828, + -3.275080442428589 + ], + [ + 1.6862918138504028, + -3.367151975631714 + ], + [ + 1.573021411895752, + -3.4410619735717773 + ], + [ + 1.4285846948623657, + -3.501758575439453 + ], + [ + 1.2665865421295166, + -3.558960199356079 + ], + [ + 1.080338716506958, + -3.6193201541900635 + ], + [ + 0.9051820039749146, + -3.638575553894043 + ], + [ + 0.714117169380188, + -3.6355979442596436 + ], + [ + 0.48350632190704346, + -3.6179797649383545 + ], + [ + 0.28889456391334534, + -3.641801357269287 + ], + [ + 0.3463749289512634, + -3.7614617347717285 + ], + [ + 0.19415786862373352, + -3.832094430923462 + ], + [ + 0.06601367890834808, + -3.859314441680908 + ], + [ + -0.08902833610773087, + -3.9271328449249268 + ], + [ + -0.21761690080165863, + -3.936556577682495 + ], + [ + -0.3878876268863678, + -4.0205912590026855 + ], + [ + -0.5356045961380005, + -4.003159999847412 + ], + [ + -0.7266702055931091, + -3.9932456016540527 + ], + [ + -0.9083345532417297, + -3.9520962238311768 + ], + [ + -1.066603422164917, + -3.899672508239746 + ], + [ + -1.2488170862197876, + -3.815174102783203 + ], + [ + -1.4770792722702026, + -3.717351198196411 + ], + [ + -3.060886859893799, + -7.234931468963623 + ], + [ + -3.4835469722747803, + -6.977844715118408 + ], + [ + -3.416165828704834, + -7.557537078857422 + ], + [ + -3.822901487350464, + -7.578333854675293 + ], + [ + -4.057675838470459, + -7.499009132385254 + ], + [ + -4.427459239959717, + -7.489191055297852 + ], + [ + -4.693297863006592, + -7.356758117675781 + ], + [ + -5.10871696472168, + -7.3122453689575195 + ], + [ + -5.426568031311035, + -7.1040825843811035 + ], + [ + -5.630316734313965, + -6.956383228302002 + ], + [ + -5.920839786529541, + -6.786628246307373 + ], + [ + -6.189432621002197, + -6.5080437660217285 + ], + [ + -6.4154744148254395, + -6.216953277587891 + ], + [ + -6.670583724975586, + -5.913576126098633 + ], + [ + -6.839602470397949, + -5.607996940612793 + ], + [ + -7.057131290435791, + -5.214391231536865 + ], + [ + -7.516590595245361, + -5.637393474578857 + ], + [ + -7.720203399658203, + -5.427697658538818 + ], + [ + -7.967331409454346, + -5.253963947296143 + ], + [ + -8.173371315002441, + -4.976185321807861 + ], + [ + -8.301654815673828, + -4.74743127822876 + ], + [ + -8.532371520996094, + -4.452219009399414 + ], + [ + -8.702978134155273, + -4.176283836364746 + ], + [ + -8.789374351501465, + -3.903578519821167 + ], + [ + -8.935059547424316, + -3.6104936599731445 + ], + [ + -9.013216972351074, + -3.335780143737793 + ], + [ + -9.159911155700684, + -3.0597574710845947 + ], + [ + -9.214734077453613, + -2.7713637351989746 + ], + [ + -9.268516540527344, + -2.4912338256835938 + ], + [ + -9.348994255065918, + -2.205791473388672 + ], + [ + -9.30864429473877, + -1.8963912725448608 + ], + [ + -9.588296890258789, + -1.6531492471694946 + ], + [ + -9.588993072509766, + -1.372212529182434 + ], + [ + -9.6458101272583, + -1.0818467140197754 + ], + [ + -9.662166595458984, + -0.8472455739974976 + ], + [ + -9.700322151184082, + -0.5518494248390198 + ], + [ + -9.664124488830566, + -0.2990831732749939 + ], + [ + -9.659528732299805, + -0.0371159166097641 + ], + [ + -9.628993034362793, + 0.22887304425239563 + ], + [ + -9.645108222961426, + 0.4597034752368927 + ], + [ + -9.615674018859863, + 0.7504839301109314 + ], + [ + -9.638134002685547, + 0.9717745780944824 + ], + [ + -9.570538520812988, + 1.2174322605133057 + ], + [ + -9.553570747375488, + 1.4698270559310913 + ], + [ + -9.459393501281738, + 1.723694086074829 + ], + [ + -9.403464317321777, + 1.9552561044692993 + ] + ], + "total_points": 1000 +} \ No newline at end of file diff --git a/vna_system/calibration/s11_start100_stop8800_points1000_bw1khz/яыф/open_metadata.json b/vna_system/calibration/s11_start100_stop8800_points1000_bw1khz/яыф/open_metadata.json new file mode 100644 index 0000000..d4fba35 --- /dev/null +++ b/vna_system/calibration/s11_start100_stop8800_points1000_bw1khz/яыф/open_metadata.json @@ -0,0 +1,16 @@ +{ + "preset": { + "filename": "s11_start100_stop8800_points1000_bw1khz.bin", + "mode": "s11", + "start_freq": 100000000.0, + "stop_freq": 8800000000.0, + "points": 1000, + "bandwidth": 1000.0 + }, + "calibration_name": "яыф", + "standard": "open", + "sweep_number": 17, + "sweep_timestamp": 1758896395.4880857, + "created_timestamp": "2025-09-26T17:20:00.016886", + "total_points": 1000 +} \ No newline at end of file diff --git a/vna_system/calibration/s11_start100_stop8800_points1000_bw1khz/яыф/short.json b/vna_system/calibration/s11_start100_stop8800_points1000_bw1khz/яыф/short.json new file mode 100644 index 0000000..02a24fe --- /dev/null +++ b/vna_system/calibration/s11_start100_stop8800_points1000_bw1khz/яыф/short.json @@ -0,0 +1,4007 @@ +{ + "sweep_number": 13, + "timestamp": 1758896378.4093437, + "points": [ + [ + -2.673182249069214, + 0.4526049792766571 + ], + [ + -2.664034366607666, + 0.5132845640182495 + ], + [ + -2.655735731124878, + 0.5743225812911987 + ], + [ + -2.6458590030670166, + 0.6349809765815735 + ], + [ + -2.634361982345581, + 0.695916473865509 + ], + [ + -3.4052376747131348, + 0.9254970550537109 + ], + [ + -3.395155906677246, + 1.005311369895935 + ], + [ + -3.374450206756592, + 1.0801655054092407 + ], + [ + -3.3507912158966064, + 1.15727961063385 + ], + [ + -3.3300724029541016, + 1.235087513923645 + ], + [ + -3.3067891597747803, + 1.3097753524780273 + ], + [ + -3.283984422683716, + 1.3847987651824951 + ], + [ + -3.25875186920166, + 1.4610011577606201 + ], + [ + -3.2363553047180176, + 1.5382307767868042 + ], + [ + -3.2065091133117676, + 1.6121679544448853 + ], + [ + -3.1773478984832764, + 1.6901707649230957 + ], + [ + -3.1499924659729004, + 1.7628757953643799 + ], + [ + -3.1139655113220215, + 1.833876132965088 + ], + [ + -3.0769565105438232, + 1.914526343345642 + ], + [ + -3.042905330657959, + 1.9799810647964478 + ], + [ + -3.0091936588287354, + 2.0521206855773926 + ], + [ + -2.9654510021209717, + 2.1246461868286133 + ], + [ + -2.9285709857940674, + 2.196747303009033 + ], + [ + -2.8818817138671875, + 2.2762978076934814 + ], + [ + -2.845154285430908, + 2.344907522201538 + ], + [ + -2.8012142181396484, + 2.417104959487915 + ], + [ + -2.7593495845794678, + 2.485837936401367 + ], + [ + -2.708976984024048, + 2.557717800140381 + ], + [ + -2.6601366996765137, + 2.630138874053955 + ], + [ + -2.611405849456787, + 2.707428455352783 + ], + [ + -2.5598292350769043, + 2.7706453800201416 + ], + [ + -2.5039029121398926, + 2.839930772781372 + ], + [ + -2.4566142559051514, + 2.9033286571502686 + ], + [ + -2.3961703777313232, + 2.9676992893218994 + ], + [ + -2.333775043487549, + 3.034329414367676 + ], + [ + -2.2696292400360107, + 3.100053310394287 + ], + [ + -2.19866943359375, + 3.1644294261932373 + ], + [ + -2.134021759033203, + 3.2304770946502686 + ], + [ + -2.0648105144500732, + 3.29374361038208 + ], + [ + -1.9910874366760254, + 3.3556854724884033 + ], + [ + -1.922908902168274, + 3.4146387577056885 + ], + [ + -1.8499655723571777, + 3.4767093658447266 + ], + [ + -1.7743914127349854, + 3.536162853240967 + ], + [ + -1.7014591693878174, + 3.592197895050049 + ], + [ + -1.615335464477539, + 3.649122953414917 + ], + [ + -1.5358545780181885, + 3.7070083618164062 + ], + [ + -1.445051670074463, + 3.7634963989257812 + ], + [ + -1.3620245456695557, + 3.815241813659668 + ], + [ + -1.2775665521621704, + 3.8688762187957764 + ], + [ + -1.1896209716796875, + 3.9140381813049316 + ], + [ + -1.0998587608337402, + 3.9655003547668457 + ], + [ + -0.9990155696868896, + 4.009896755218506 + ], + [ + -0.9009591937065125, + 4.054059028625488 + ], + [ + -0.807556688785553, + 4.105104923248291 + ], + [ + -0.7030119299888611, + 4.147378444671631 + ], + [ + -0.6066522598266602, + 4.1889801025390625 + ], + [ + -0.5006924271583557, + 4.220681667327881 + ], + [ + -0.3956588804721832, + 4.258335113525391 + ], + [ + -0.28977978229522705, + 4.28523063659668 + ], + [ + -0.18176065385341644, + 4.3160881996154785 + ], + [ + -0.05864642187952995, + 4.342520713806152 + ], + [ + 0.0496070459485054, + 4.363901615142822 + ], + [ + 0.17840063571929932, + 4.385037899017334 + ], + [ + 0.2935994565486908, + 4.398932456970215 + ], + [ + 0.4185701906681061, + 4.4109721183776855 + ], + [ + 0.5423102974891663, + 4.418863296508789 + ], + [ + 0.66508549451828, + 4.425356388092041 + ], + [ + 0.7866483926773071, + 4.424631595611572 + ], + [ + 0.9205178618431091, + 4.4424262046813965 + ], + [ + 1.046618103981018, + 4.436233997344971 + ], + [ + 1.1802787780761719, + 4.4440741539001465 + ], + [ + 1.3159068822860718, + 4.417740821838379 + ], + [ + 1.460447072982788, + 4.3973188400268555 + ], + [ + 1.5849770307540894, + 4.380573272705078 + ], + [ + 1.7220685482025146, + 4.357413291931152 + ], + [ + 1.8599116802215576, + 4.320777416229248 + ], + [ + 1.9986697435379028, + 4.294105529785156 + ], + [ + 2.1329915523529053, + 4.255446434020996 + ], + [ + 2.2709624767303467, + 4.2123188972473145 + ], + [ + 2.3979651927948, + 4.151188850402832 + ], + [ + 2.5227243900299072, + 4.108695030212402 + ], + [ + 2.659486770629883, + 4.052158355712891 + ], + [ + 2.7887051105499268, + 3.987877130508423 + ], + [ + 2.906116247177124, + 3.919907331466675 + ], + [ + 3.0215811729431152, + 3.849973201751709 + ], + [ + 3.1460373401641846, + 3.782819986343384 + ], + [ + 3.267817735671997, + 3.7028074264526367 + ], + [ + 3.378697156906128, + 3.618018627166748 + ], + [ + 3.495452404022217, + 3.5282583236694336 + ], + [ + 3.6076154708862305, + 3.4318997859954834 + ], + [ + 3.7200639247894287, + 3.334930419921875 + ], + [ + 3.8343679904937744, + 3.231701612472534 + ], + [ + 3.942572832107544, + 3.1166374683380127 + ], + [ + 4.039266109466553, + 2.99684739112854 + ], + [ + 4.153839588165283, + 2.8691771030426025 + ], + [ + 4.257083415985107, + 2.742621421813965 + ], + [ + 4.353559970855713, + 2.617739677429199 + ], + [ + 4.441986083984375, + 2.48197078704834 + ], + [ + 4.52557373046875, + 2.3450729846954346 + ], + [ + 4.591869354248047, + 2.2022571563720703 + ], + [ + 4.665722846984863, + 2.0598435401916504 + ], + [ + 4.738101959228516, + 1.9026832580566406 + ], + [ + 4.794832706451416, + 1.7572259902954102 + ], + [ + 4.845154762268066, + 1.5968844890594482 + ], + [ + 4.90429162979126, + 1.438180923461914 + ], + [ + 4.938620090484619, + 1.271759033203125 + ], + [ + 4.973180770874023, + 1.1124613285064697 + ], + [ + 5.01839017868042, + 0.941400945186615 + ], + [ + 5.032951354980469, + 0.7707509994506836 + ], + [ + 5.0646185874938965, + 0.6067417860031128 + ], + [ + 5.078636169433594, + 0.43243736028671265 + ], + [ + 5.088210582733154, + 0.2722599506378174 + ], + [ + 5.077387809753418, + 0.10976143926382065 + ], + [ + 5.076402187347412, + -0.056312985718250275 + ], + [ + 5.058142185211182, + -0.21401184797286987 + ], + [ + 5.026561737060547, + -0.34496769309043884 + ], + [ + 4.999899387359619, + -0.49822258949279785 + ], + [ + 4.967226028442383, + -0.645676851272583 + ], + [ + 4.923960208892822, + -0.7984857559204102 + ], + [ + 4.867866516113281, + -0.9335814714431763 + ], + [ + 4.809844017028809, + -1.0838066339492798 + ], + [ + 4.741298675537109, + -1.2189158201217651 + ], + [ + 4.668980121612549, + -1.350603461265564 + ], + [ + 4.602053642272949, + -1.4819140434265137 + ], + [ + 4.514710903167725, + -1.620599627494812 + ], + [ + 4.4300537109375, + -1.7464057207107544 + ], + [ + 4.339680194854736, + -1.8790059089660645 + ], + [ + 4.237917900085449, + -2.0014591217041016 + ], + [ + 4.148985862731934, + -2.139927625656128 + ], + [ + 4.056626319885254, + -2.2732622623443604 + ], + [ + 3.9556679725646973, + -2.3923707008361816 + ], + [ + 3.857477903366089, + -2.51560378074646 + ], + [ + 3.7648003101348877, + -2.629596710205078 + ], + [ + 3.6510813236236572, + -2.739619731903076 + ], + [ + 3.5633087158203125, + -2.841643810272217 + ], + [ + 3.4544761180877686, + -2.9344141483306885 + ], + [ + 3.3673555850982666, + -3.024390459060669 + ], + [ + 3.2654435634613037, + -3.0797317028045654 + ], + [ + 3.164827346801758, + -3.150209426879883 + ], + [ + 3.063897132873535, + -3.1965482234954834 + ], + [ + 2.952057123184204, + -3.2245943546295166 + ], + [ + 2.856443405151367, + -3.2749805450439453 + ], + [ + 2.7456510066986084, + -3.2942886352539062 + ], + [ + 2.6304144859313965, + -3.3073441982269287 + ], + [ + 2.5269925594329834, + -3.3382651805877686 + ], + [ + 2.415584087371826, + -3.3440864086151123 + ], + [ + 2.297959089279175, + -3.3568880558013916 + ], + [ + 2.2026796340942383, + -3.3695178031921387 + ], + [ + 2.0875866413116455, + -3.373654365539551 + ], + [ + 1.9661145210266113, + -3.3805530071258545 + ], + [ + 1.8646941184997559, + -3.3887622356414795 + ], + [ + 1.7419407367706299, + -3.4012157917022705 + ], + [ + 1.6218788623809814, + -3.4237658977508545 + ], + [ + 1.4743952751159668, + -3.6106114387512207 + ], + [ + 1.3657457828521729, + -3.6342482566833496 + ], + [ + 1.2740747928619385, + -3.6237294673919678 + ], + [ + 1.1761966943740845, + -3.6070613861083984 + ], + [ + 1.0804895162582397, + -3.618767738342285 + ], + [ + 0.9801827669143677, + -3.5969154834747314 + ], + [ + 0.8770717978477478, + -3.60530686378479 + ], + [ + 0.781680703163147, + -3.581618547439575 + ], + [ + 0.6918584108352661, + -3.5595405101776123 + ], + [ + 0.5921069979667664, + -3.5595414638519287 + ], + [ + 0.5056436061859131, + -3.531352996826172 + ], + [ + 0.42071250081062317, + -3.5172648429870605 + ], + [ + 0.3273966312408447, + -3.500552177429199 + ], + [ + 0.24874982237815857, + -3.4709088802337646 + ], + [ + 0.16427558660507202, + -3.4581565856933594 + ], + [ + 0.09205229580402374, + -3.4318172931671143 + ], + [ + 0.008539530448615551, + -3.407423973083496 + ], + [ + -0.06903084367513657, + -3.384385108947754 + ], + [ + -0.13350863754749298, + -3.3539860248565674 + ], + [ + -0.20439986884593964, + -3.3272244930267334 + ], + [ + -0.2684410810470581, + -3.30094838142395 + ], + [ + -0.34321293234825134, + -3.2741923332214355 + ], + [ + -0.39875319600105286, + -3.2431230545043945 + ], + [ + -0.4613335132598877, + -3.210358142852783 + ], + [ + -0.5248931050300598, + -3.185352325439453 + ], + [ + -0.5931600332260132, + -3.1653990745544434 + ], + [ + -0.6398776769638062, + -3.1249661445617676 + ], + [ + -0.7001591920852661, + -3.0916523933410645 + ], + [ + -0.7636449933052063, + -3.063239097595215 + ], + [ + -0.8128881454467773, + -3.0300707817077637 + ], + [ + -0.8683986067771912, + -2.998833179473877 + ], + [ + -0.9263790249824524, + -2.965181350708008 + ], + [ + -0.9759135842323303, + -2.922837734222412 + ], + [ + -1.0341508388519287, + -2.8908348083496094 + ], + [ + -1.0867713689804077, + -2.856797218322754 + ], + [ + -1.1402214765548706, + -2.827364444732666 + ], + [ + -1.186988353729248, + -2.7884135246276855 + ], + [ + -1.232167363166809, + -2.757401943206787 + ], + [ + -1.2791557312011719, + -2.7225444316864014 + ], + [ + -1.3236093521118164, + -2.6816565990448 + ], + [ + -1.3567805290222168, + -2.6507019996643066 + ], + [ + -1.4071881771087646, + -2.610079288482666 + ], + [ + -1.446117877960205, + -2.5702223777770996 + ], + [ + -1.4979808330535889, + -2.5301907062530518 + ], + [ + -1.5319688320159912, + -2.486398696899414 + ], + [ + -1.5736669301986694, + -2.4392106533050537 + ], + [ + -1.6006675958633423, + -2.394244432449341 + ], + [ + -1.6032633781433105, + -2.3215057849884033 + ], + [ + -1.6616684198379517, + -2.2746148109436035 + ], + [ + -1.7068790197372437, + -2.223567247390747 + ], + [ + -1.7490354776382446, + -2.1755223274230957 + ], + [ + -1.7988929748535156, + -2.1212801933288574 + ], + [ + -1.8376071453094482, + -2.074448585510254 + ], + [ + -1.8857108354568481, + -2.0204172134399414 + ], + [ + -1.92911696434021, + -1.9718801975250244 + ], + [ + -1.9663833379745483, + -1.9226932525634766 + ], + [ + -2.0039913654327393, + -1.868977427482605 + ], + [ + -2.047943353652954, + -1.8163002729415894 + ], + [ + -2.080768346786499, + -1.7732667922973633 + ], + [ + -2.1188628673553467, + -1.7129542827606201 + ], + [ + -2.1526827812194824, + -1.6670058965682983 + ], + [ + -2.1762266159057617, + -1.6211575269699097 + ], + [ + -2.2120344638824463, + -1.5595113039016724 + ], + [ + -2.2398288249969482, + -1.5118365287780762 + ], + [ + -2.260369062423706, + -1.4670323133468628 + ], + [ + -2.2859272956848145, + -1.4121975898742676 + ], + [ + -2.3089702129364014, + -1.3657389879226685 + ], + [ + -2.321678400039673, + -1.319008708000183 + ], + [ + -2.34130859375, + -1.2638022899627686 + ], + [ + -2.358565330505371, + -1.2190756797790527 + ], + [ + -2.367945432662964, + -1.1691783666610718 + ], + [ + -2.3798136711120605, + -1.122207522392273 + ], + [ + -2.3943703174591064, + -1.072206974029541 + ], + [ + -2.400977611541748, + -1.0242115259170532 + ], + [ + -2.4109771251678467, + -0.9730558395385742 + ], + [ + -2.421635627746582, + -0.9196767807006836 + ], + [ + -2.4310638904571533, + -0.8683810234069824 + ], + [ + -2.4374585151672363, + -0.813830554485321 + ], + [ + -2.4480936527252197, + -0.7566489577293396 + ], + [ + -2.4574458599090576, + -0.6995614767074585 + ], + [ + -2.469574213027954, + -0.6409438252449036 + ], + [ + -2.4798359870910645, + -0.5829693675041199 + ], + [ + -2.4901702404022217, + -0.519244372844696 + ], + [ + -2.503509998321533, + -0.4582385718822479 + ], + [ + -2.5134944915771484, + -0.3993208408355713 + ], + [ + -2.525212526321411, + -0.33690086007118225 + ], + [ + -2.531342029571533, + -0.27798953652381897 + ], + [ + -2.5383381843566895, + -0.2205219268798828 + ], + [ + -2.5438132286071777, + -0.16239959001541138 + ], + [ + -2.530621290206909, + -0.10677018761634827 + ], + [ + -2.526913642883301, + -0.053873252123594284 + ], + [ + -2.5224623680114746, + 0.0016842411132529378 + ], + [ + -2.517287254333496, + 0.0572863332927227 + ], + [ + -2.5091207027435303, + 0.11101123690605164 + ], + [ + -2.501587152481079, + 0.16734004020690918 + ], + [ + -2.498530626296997, + 0.22565042972564697 + ], + [ + -2.4925310611724854, + 0.28695037961006165 + ], + [ + -2.4820055961608887, + 0.3394150137901306 + ], + [ + -2.4736030101776123, + 0.3964601457118988 + ], + [ + -2.464576244354248, + 0.4571801424026489 + ], + [ + -2.457829236984253, + 0.5174599289894104 + ], + [ + -2.446819543838501, + 0.5789187550544739 + ], + [ + -2.433417797088623, + 0.6292660236358643 + ], + [ + -2.4219560623168945, + 0.6928188800811768 + ], + [ + -2.4111437797546387, + 0.7525805830955505 + ], + [ + -2.404707431793213, + 0.8153723478317261 + ], + [ + -2.3971235752105713, + 0.8778687119483948 + ], + [ + -2.3757927417755127, + 0.9285744428634644 + ], + [ + -2.3689565658569336, + 0.9883994460105896 + ], + [ + -2.356597661972046, + 1.047275424003601 + ], + [ + -2.3498377799987793, + 1.105019211769104 + ], + [ + -2.3425841331481934, + 1.156809687614441 + ], + [ + -2.335012435913086, + 1.2025091648101807 + ], + [ + -2.310600757598877, + 1.2657932043075562 + ], + [ + -2.301192045211792, + 1.3172303438186646 + ], + [ + -2.2908334732055664, + 1.3577792644500732 + ], + [ + -2.27878737449646, + 1.3989558219909668 + ], + [ + -2.261579751968384, + 1.4277735948562622 + ], + [ + -2.238513231277466, + 1.4949188232421875 + ], + [ + -2.2176127433776855, + 1.5282776355743408 + ], + [ + -2.1968090534210205, + 1.5617926120758057 + ], + [ + -2.169755697250366, + 1.5892717838287354 + ], + [ + -2.13558292388916, + 1.625771164894104 + ], + [ + -2.109731435775757, + 1.67192542552948 + ], + [ + -2.075552225112915, + 1.7093220949172974 + ], + [ + -2.0314695835113525, + 1.7475249767303467 + ], + [ + -1.980591058731079, + 1.775829553604126 + ], + [ + -1.9266046285629272, + 1.8126258850097656 + ], + [ + -1.867958903312683, + 1.8584524393081665 + ], + [ + -1.8301701545715332, + 1.9078624248504639 + ], + [ + -1.7699631452560425, + 1.9495002031326294 + ], + [ + -1.7086732387542725, + 1.9993089437484741 + ], + [ + -1.6490353345870972, + 2.0524954795837402 + ], + [ + -1.581202507019043, + 2.1065025329589844 + ], + [ + -1.5355106592178345, + 2.1579995155334473 + ], + [ + -1.473389983177185, + 2.209970235824585 + ], + [ + -1.4070863723754883, + 2.272813081741333 + ], + [ + -1.342864990234375, + 2.337266445159912 + ], + [ + -1.2887318134307861, + 2.410109281539917 + ], + [ + -1.231166958808899, + 2.479233980178833 + ], + [ + -1.1784919500350952, + 2.5283203125 + ], + [ + -1.1275389194488525, + 2.586707592010498 + ], + [ + -1.0714021921157837, + 2.638383388519287 + ], + [ + -1.0138081312179565, + 2.7014384269714355 + ], + [ + -0.9613556861877441, + 2.767829179763794 + ], + [ + -0.9044824838638306, + 2.816967248916626 + ], + [ + -0.8406919836997986, + 2.859841823577881 + ], + [ + -0.7884116172790527, + 2.9085583686828613 + ], + [ + -0.7255499362945557, + 2.953869581222534 + ], + [ + -0.6576851606369019, + 2.998589277267456 + ], + [ + -0.6037365198135376, + 3.039970874786377 + ], + [ + -0.5375269651412964, + 3.081350564956665 + ], + [ + -0.44995808601379395, + 3.110718250274658 + ], + [ + -0.39340701699256897, + 3.1451056003570557 + ], + [ + -0.3168303072452545, + 3.183993339538574 + ], + [ + -0.23857304453849792, + 3.2116355895996094 + ], + [ + -0.16603463888168335, + 3.2358429431915283 + ], + [ + -0.0916532352566719, + 3.2647645473480225 + ], + [ + -0.0005811986047774553, + 3.2859268188476562 + ], + [ + 0.07298585772514343, + 3.3010852336883545 + ], + [ + 0.1580224484205246, + 3.319701671600342 + ], + [ + 0.23015999794006348, + 3.3372697830200195 + ], + [ + 0.30307266116142273, + 3.349024534225464 + ], + [ + 0.3876035511493683, + 3.3475186824798584 + ], + [ + 0.5878651738166809, + 3.2136189937591553 + ], + [ + 0.6779069304466248, + 3.219494581222534 + ], + [ + 0.7918234467506409, + 3.2124924659729004 + ], + [ + 0.8848069906234741, + 3.2114877700805664 + ], + [ + 0.9875006079673767, + 3.199876308441162 + ], + [ + 1.0822911262512207, + 3.192505359649658 + ], + [ + 1.1757166385650635, + 3.180107831954956 + ], + [ + 1.2767142057418823, + 3.164475679397583 + ], + [ + 1.379189372062683, + 3.1488306522369385 + ], + [ + 1.4690500497817993, + 3.1253068447113037 + ], + [ + 1.5520175695419312, + 3.1033992767333984 + ], + [ + 1.6493271589279175, + 3.0771281719207764 + ], + [ + 1.757622480392456, + 3.039611577987671 + ], + [ + 1.8461952209472656, + 3.0060765743255615 + ], + [ + 1.9201148748397827, + 2.956674575805664 + ], + [ + 2.001403570175171, + 2.910261392593384 + ], + [ + 2.076373815536499, + 2.870056629180908 + ], + [ + 2.1798932552337646, + 2.8098409175872803 + ], + [ + 2.250122308731079, + 2.744114398956299 + ], + [ + 2.3202872276306152, + 2.6732492446899414 + ], + [ + 2.3956542015075684, + 2.6075103282928467 + ], + [ + 2.4642441272735596, + 2.5216567516326904 + ], + [ + 2.5547165870666504, + 2.454493284225464 + ], + [ + 2.618576765060425, + 2.375303030014038 + ], + [ + 2.6805849075317383, + 2.284599542617798 + ], + [ + 2.749704599380493, + 2.186394691467285 + ], + [ + 2.813284397125244, + 2.094119071960449 + ], + [ + 2.880871057510376, + 1.9898854494094849 + ], + [ + 2.934469223022461, + 1.9067977666854858 + ], + [ + 2.991663932800293, + 1.8043824434280396 + ], + [ + 3.057093858718872, + 1.6970021724700928 + ], + [ + 3.1130027770996094, + 1.5867290496826172 + ], + [ + 3.171023368835449, + 1.4858604669570923 + ], + [ + 3.2148594856262207, + 1.3836365938186646 + ], + [ + 3.263996124267578, + 1.274282455444336 + ], + [ + 3.3087658882141113, + 1.1732949018478394 + ], + [ + 3.350975513458252, + 1.0699526071548462 + ], + [ + 3.390791893005371, + 0.9659026265144348 + ], + [ + 3.4243171215057373, + 0.8666683435440063 + ], + [ + 3.446524143218994, + 0.7704423069953918 + ], + [ + 3.472703456878662, + 0.675892174243927 + ], + [ + 3.4931538105010986, + 0.580154299736023 + ], + [ + 3.5077016353607178, + 0.4884197413921356 + ], + [ + 3.5124459266662598, + 0.3999975323677063 + ], + [ + 3.5147197246551514, + 0.30849725008010864 + ], + [ + 3.512087821960449, + 0.22403927147388458 + ], + [ + 3.504700183868408, + 0.13418523967266083 + ], + [ + 3.4935789108276367, + 0.045682694762945175 + ], + [ + 3.477421760559082, + -0.044898029416799545 + ], + [ + 3.456566572189331, + -0.13699372112751007 + ], + [ + 3.4338762760162354, + -0.23066364228725433 + ], + [ + 3.4055705070495605, + -0.327321857213974 + ], + [ + 3.378270149230957, + -0.4164586663246155 + ], + [ + 3.347321033477783, + -0.5155251622200012 + ], + [ + 3.322336435317993, + -0.6215901374816895 + ], + [ + 3.3006479740142822, + -0.7233368754386902 + ], + [ + 3.2822046279907227, + -0.8258315920829773 + ], + [ + 3.2668824195861816, + -0.9272357225418091 + ], + [ + 3.243856906890869, + -1.0230904817581177 + ], + [ + 3.244309186935425, + -1.116092324256897 + ], + [ + 3.234924077987671, + -1.1947085857391357 + ], + [ + 3.2223989963531494, + -1.2671915292739868 + ], + [ + 3.219113349914551, + -1.3285025358200073 + ], + [ + 3.207261323928833, + -1.3796749114990234 + ], + [ + 3.1931650638580322, + -1.415226697921753 + ], + [ + 3.1698687076568604, + -1.4688541889190674 + ], + [ + 3.1412322521209717, + -1.5014845132827759 + ], + [ + 3.1008613109588623, + -1.534751296043396 + ], + [ + 3.0634870529174805, + -1.5698833465576172 + ], + [ + 3.0127251148223877, + -1.588167667388916 + ], + [ + 2.9586687088012695, + -1.6208267211914062 + ], + [ + 2.8867380619049072, + -1.648159146308899 + ], + [ + 2.83349347114563, + -1.6734973192214966 + ], + [ + 2.766019105911255, + -1.6997148990631104 + ], + [ + 2.6952385902404785, + -1.7353109121322632 + ], + [ + 2.6424436569213867, + -1.7725975513458252 + ], + [ + 2.5772390365600586, + -1.807450771331787 + ], + [ + 2.497368812561035, + -1.8400312662124634 + ], + [ + 2.4342873096466064, + -1.8636877536773682 + ], + [ + 2.355811834335327, + -1.8967679738998413 + ], + [ + 2.2752785682678223, + -1.9312840700149536 + ], + [ + 2.1962032318115234, + -1.9753929376602173 + ], + [ + 2.121793746948242, + -2.019887924194336 + ], + [ + 2.0455734729766846, + -2.0668246746063232 + ], + [ + 1.9679526090621948, + -2.1126163005828857 + ], + [ + 1.9006325006484985, + -2.180799961090088 + ], + [ + 1.8309653997421265, + -2.2034127712249756 + ], + [ + 1.763604760169983, + -2.2559385299682617 + ], + [ + 1.697442889213562, + -2.307339906692505 + ], + [ + 1.6368964910507202, + -2.3589682579040527 + ], + [ + 1.5709640979766846, + -2.404280662536621 + ], + [ + 1.5167990922927856, + -2.4437079429626465 + ], + [ + 1.4635775089263916, + -2.4949469566345215 + ], + [ + 1.5027706623077393, + -2.411202907562256 + ], + [ + 1.453515887260437, + -2.456845283508301 + ], + [ + 1.3780262470245361, + -2.4823944568634033 + ], + [ + 1.3080123662948608, + -2.499399185180664 + ], + [ + 1.2225286960601807, + -2.535712242126465 + ], + [ + 1.1629917621612549, + -2.5621891021728516 + ], + [ + 1.1361860036849976, + -2.5766618251800537 + ], + [ + 1.063064455986023, + -2.587355852127075 + ], + [ + 0.9937528371810913, + -2.6161532402038574 + ], + [ + 0.9249582886695862, + -2.63638973236084 + ], + [ + 0.8631870746612549, + -2.6620867252349854 + ], + [ + 0.7993646264076233, + -2.6841962337493896 + ], + [ + 0.7536969780921936, + -2.673858642578125 + ], + [ + 0.694944441318512, + -2.6893975734710693 + ], + [ + 0.6465615034103394, + -2.7003469467163086 + ], + [ + 0.5747862458229065, + -2.727842330932617 + ], + [ + 0.5197077989578247, + -2.745699882507324 + ], + [ + 0.4731369912624359, + -2.75351619720459 + ], + [ + 0.40462714433670044, + -2.738023281097412 + ], + [ + 0.3501152992248535, + -2.738109588623047 + ], + [ + 0.2983783483505249, + -2.756690263748169 + ], + [ + 0.2515210509300232, + -2.7695090770721436 + ], + [ + 0.20125414431095123, + -2.7769975662231445 + ], + [ + 0.15428268909454346, + -2.775938034057617 + ], + [ + 0.0821581780910492, + -2.7765653133392334 + ], + [ + 0.04347499459981918, + -2.767928123474121 + ], + [ + -0.00789116881787777, + -2.7652084827423096 + ], + [ + -0.04599149525165558, + -2.7722885608673096 + ], + [ + -0.09060350060462952, + -2.763873338699341 + ], + [ + -0.12612250447273254, + -2.761052370071411 + ], + [ + -0.20212243497371674, + -2.75677490234375 + ], + [ + -0.24069586396217346, + -2.743093967437744 + ], + [ + -0.2836313843727112, + -2.7396843433380127 + ], + [ + -0.3282116949558258, + -2.7346386909484863 + ], + [ + -0.36533138155937195, + -2.7167201042175293 + ], + [ + -0.39979082345962524, + -2.7093350887298584 + ], + [ + -0.4458392858505249, + -2.6665122509002686 + ], + [ + -0.49984124302864075, + -2.6887519359588623 + ], + [ + -0.544296383857727, + -2.6687815189361572 + ], + [ + -0.5792315602302551, + -2.647686004638672 + ], + [ + -0.6127561926841736, + -2.6242294311523438 + ], + [ + -0.6479333639144897, + -2.6033527851104736 + ], + [ + -0.6897246837615967, + -2.5753986835479736 + ], + [ + -0.7329197525978088, + -2.567378282546997 + ], + [ + -0.780539870262146, + -2.5552568435668945 + ], + [ + -0.8120342493057251, + -2.526226282119751 + ], + [ + -0.8462810516357422, + -2.502086639404297 + ], + [ + -0.886154294013977, + -2.4731786251068115 + ], + [ + -0.9251731038093567, + -2.442185878753662 + ], + [ + -0.9638217687606812, + -2.400994300842285 + ], + [ + -1.00369131565094, + -2.4034459590911865 + ], + [ + -1.033838152885437, + -2.372750759124756 + ], + [ + -1.0716140270233154, + -2.3319952487945557 + ], + [ + -1.122118592262268, + -2.2918314933776855 + ], + [ + -1.1665476560592651, + -2.2538442611694336 + ], + [ + -1.2205716371536255, + -2.2237606048583984 + ], + [ + -1.273909568786621, + -2.18815279006958 + ], + [ + -1.2945715188980103, + -2.16145920753479 + ], + [ + -1.3416869640350342, + -2.1253881454467773 + ], + [ + -1.395548939704895, + -2.0892577171325684 + ], + [ + -1.445960521697998, + -2.055070161819458 + ], + [ + -1.5000419616699219, + -2.024179220199585 + ], + [ + -1.5625221729278564, + -1.9943028688430786 + ], + [ + -1.6127196550369263, + -1.9717718362808228 + ], + [ + -1.671931266784668, + -1.9514291286468506 + ], + [ + -1.6947245597839355, + -1.9129234552383423 + ], + [ + -1.7501715421676636, + -1.8841849565505981 + ], + [ + -1.8020837306976318, + -1.8659074306488037 + ], + [ + -1.8445435762405396, + -1.8498421907424927 + ], + [ + -1.887615442276001, + -1.8390449285507202 + ], + [ + -1.9261912107467651, + -1.8158771991729736 + ], + [ + -1.9600956439971924, + -1.8054693937301636 + ], + [ + -1.9973646402359009, + -1.7634742259979248 + ], + [ + -2.0321316719055176, + -1.7462167739868164 + ], + [ + -2.067336082458496, + -1.7277648448944092 + ], + [ + -2.0930607318878174, + -1.708570957183838 + ], + [ + -2.1171107292175293, + -1.6954368352890015 + ], + [ + -2.128897190093994, + -1.6695770025253296 + ], + [ + -2.147247076034546, + -1.650486707687378 + ], + [ + -2.168623924255371, + -1.6228190660476685 + ], + [ + -2.209636688232422, + -1.5790663957595825 + ], + [ + -2.229109525680542, + -1.5512958765029907 + ], + [ + -2.240053415298462, + -1.5164803266525269 + ], + [ + -2.252962350845337, + -1.4774736166000366 + ], + [ + -2.7837743759155273, + -1.919206976890564 + ], + [ + -2.8080172538757324, + -1.8697103261947632 + ], + [ + -2.853060245513916, + -1.8182430267333984 + ], + [ + -2.887516498565674, + -1.7683335542678833 + ], + [ + -2.9246363639831543, + -1.7109719514846802 + ], + [ + -2.9605214595794678, + -1.6502751111984253 + ], + [ + -2.991450786590576, + -1.590841293334961 + ], + [ + -3.0296034812927246, + -1.5322867631912231 + ], + [ + -3.0597405433654785, + -1.4669045209884644 + ], + [ + -3.0953335762023926, + -1.399247646331787 + ], + [ + -3.1277523040771484, + -1.3386845588684082 + ], + [ + -3.1657650470733643, + -1.2710931301116943 + ], + [ + -1.935664415359497, + -0.6883072257041931 + ], + [ + -1.95100998878479, + -0.6450150012969971 + ], + [ + -1.9696930646896362, + -0.6015149354934692 + ], + [ + -1.9844924211502075, + -0.5559136271476746 + ], + [ + -1.996744155883789, + -0.5113682746887207 + ], + [ + -2.008295774459839, + -0.4664038419723511 + ], + [ + -2.019610643386841, + -0.4187585711479187 + ], + [ + -2.030045986175537, + -0.37128278613090515 + ], + [ + -2.038402795791626, + -0.3244359791278839 + ], + [ + -2.0470566749572754, + -0.2772515118122101 + ], + [ + -2.0540878772735596, + -0.22947342693805695 + ], + [ + -2.0611395835876465, + -0.18174809217453003 + ], + [ + -2.066038131713867, + -0.133727565407753 + ], + [ + -2.0703699588775635, + -0.08456044644117355 + ], + [ + -2.074824094772339, + -0.03492160513997078 + ], + [ + -2.0768260955810547, + 0.013081388548016548 + ], + [ + -2.07806134223938, + 0.06199152022600174 + ], + [ + -2.079186201095581, + 0.11421190947294235 + ], + [ + -2.0783491134643555, + 0.1651063710451126 + ], + [ + -2.0766143798828125, + 0.2155379205942154 + ], + [ + -2.074216604232788, + 0.267122745513916 + ], + [ + -2.0705089569091797, + 0.32017746567726135 + ], + [ + -2.064100980758667, + 0.3715705871582031 + ], + [ + -2.0582058429718018, + 0.42422521114349365 + ], + [ + -2.0500378608703613, + 0.47659358382225037 + ], + [ + -2.0369718074798584, + 0.5266203284263611 + ], + [ + -2.028622627258301, + 0.5784882307052612 + ], + [ + -2.016465663909912, + 0.6334421634674072 + ], + [ + -2.0024194717407227, + 0.6820216178894043 + ], + [ + -1.985360026359558, + 0.7365118265151978 + ], + [ + -1.9684746265411377, + 0.7855709791183472 + ], + [ + -1.949262261390686, + 0.8370513319969177 + ], + [ + -1.927605152130127, + 0.8893451690673828 + ], + [ + -1.9071763753890991, + 0.9342036247253418 + ], + [ + -1.8821049928665161, + 0.9854799509048462 + ], + [ + -1.8544752597808838, + 1.0311120748519897 + ], + [ + -1.8296862840652466, + 1.0803190469741821 + ], + [ + -1.7978023290634155, + 1.1293190717697144 + ], + [ + -1.7671458721160889, + 1.1716810464859009 + ], + [ + -1.741865873336792, + 1.2175030708312988 + ], + [ + -1.7134449481964111, + 1.2704921960830688 + ], + [ + -1.6739500761032104, + 1.309050440788269 + ], + [ + -1.637024998664856, + 1.3500995635986328 + ], + [ + -1.6051915884017944, + 1.399223804473877 + ], + [ + -1.568987488746643, + 1.4360132217407227 + ], + [ + -1.5305047035217285, + 1.4814079999923706 + ], + [ + -1.490166187286377, + 1.518885612487793 + ], + [ + -1.4531137943267822, + 1.5561578273773193 + ], + [ + -1.4059789180755615, + 1.5879491567611694 + ], + [ + -1.3669108152389526, + 1.6364701986312866 + ], + [ + -1.3275558948516846, + 1.6582576036453247 + ], + [ + -1.2846368551254272, + 1.6983668804168701 + ], + [ + -1.241637110710144, + 1.7289179563522339 + ], + [ + -1.1996538639068604, + 1.757182002067566 + ], + [ + -1.148848533630371, + 1.7901995182037354 + ], + [ + -1.1093586683273315, + 1.8149954080581665 + ], + [ + -1.0608354806900024, + 1.8442833423614502 + ], + [ + -1.0009334087371826, + 1.862099051475525 + ], + [ + -0.9629958271980286, + 1.8989758491516113 + ], + [ + -0.919478714466095, + 1.9106411933898926 + ], + [ + -0.8724031448364258, + 1.9270148277282715 + ], + [ + -0.8270814418792725, + 1.953360676765442 + ], + [ + -0.7705026268959045, + 1.976083517074585 + ], + [ + -0.7327464818954468, + 1.9781056642532349 + ], + [ + -0.6781279444694519, + 1.997910737991333 + ], + [ + -0.635509192943573, + 2.018270969390869 + ], + [ + -0.5865940451622009, + 2.0264360904693604 + ], + [ + -0.5320722460746765, + 2.037405490875244 + ], + [ + -0.47908514738082886, + 2.0507781505584717 + ], + [ + -0.43149876594543457, + 2.053215980529785 + ], + [ + -0.38548192381858826, + 2.062180519104004 + ], + [ + -0.3325420320034027, + 2.063960313796997 + ], + [ + -0.2815983295440674, + 2.0593724250793457 + ], + [ + -0.20684583485126495, + 2.0576412677764893 + ], + [ + -0.16255079209804535, + 2.071381092071533 + ], + [ + -0.12181153148412704, + 2.0720713138580322 + ], + [ + -0.06642143428325653, + 2.0724048614501953 + ], + [ + -0.009489577263593674, + 2.0693399906158447 + ], + [ + 0.04472999647259712, + 2.066993236541748 + ], + [ + 0.09162499010562897, + 2.0643627643585205 + ], + [ + 0.14289888739585876, + 2.061814308166504 + ], + [ + 0.19132329523563385, + 2.0530941486358643 + ], + [ + 0.2475784420967102, + 2.0457935333251953 + ], + [ + 0.2924618422985077, + 2.029400110244751 + ], + [ + 0.34878143668174744, + 2.0216708183288574 + ], + [ + 0.38956591486930847, + 2.0064573287963867 + ], + [ + 0.43953731656074524, + 1.9903284311294556 + ], + [ + 0.4915914535522461, + 1.977489948272705 + ], + [ + 0.54994136095047, + 1.9571533203125 + ], + [ + 0.5936962366104126, + 1.9308748245239258 + ], + [ + 0.6432555913925171, + 1.9216440916061401 + ], + [ + 0.6953475475311279, + 1.898364782333374 + ], + [ + 0.7386367917060852, + 1.867858648300171 + ], + [ + 0.7911633849143982, + 1.8482643365859985 + ], + [ + 0.8304948806762695, + 1.8175406455993652 + ], + [ + 0.8832184672355652, + 1.7979975938796997 + ], + [ + 0.9245592355728149, + 1.769811987876892 + ], + [ + 0.9727722406387329, + 1.7323118448257446 + ], + [ + 1.0234758853912354, + 1.7048507928848267 + ], + [ + 1.0653328895568848, + 1.6785727739334106 + ], + [ + 1.1094121932983398, + 1.6469670534133911 + ], + [ + 1.1535905599594116, + 1.6131222248077393 + ], + [ + 1.2006678581237793, + 1.581589698791504 + ], + [ + 1.241642713546753, + 1.5472909212112427 + ], + [ + 1.2739598751068115, + 1.5033990144729614 + ], + [ + 1.327681303024292, + 1.4695595502853394 + ], + [ + 1.3650836944580078, + 1.4261245727539062 + ], + [ + 1.4111230373382568, + 1.3918198347091675 + ], + [ + 1.446264386177063, + 1.3551913499832153 + ], + [ + 1.480709195137024, + 1.311214566230774 + ], + [ + 1.515140414237976, + 1.2644424438476562 + ], + [ + 1.5527229309082031, + 1.2219665050506592 + ], + [ + 1.5906987190246582, + 1.177523136138916 + ], + [ + 1.6212247610092163, + 1.1303155422210693 + ], + [ + 1.6595853567123413, + 1.089963674545288 + ], + [ + 1.6904889345169067, + 1.033535361289978 + ], + [ + 1.7179726362228394, + 0.988362729549408 + ], + [ + 1.7513253688812256, + 0.9392821192741394 + ], + [ + 1.7762948274612427, + 0.890687882900238 + ], + [ + 1.8051608800888062, + 0.8408190608024597 + ], + [ + 1.8268612623214722, + 0.7908740639686584 + ], + [ + 1.852120041847229, + 0.7372981309890747 + ], + [ + 1.8749315738677979, + 0.6847925186157227 + ], + [ + 1.89579176902771, + 0.630113422870636 + ], + [ + 1.917185664176941, + 0.5766167044639587 + ], + [ + 1.9351413249969482, + 0.5243584513664246 + ], + [ + 1.9529199600219727, + 0.4701376259326935 + ], + [ + 1.969649076461792, + 0.4148019850254059 + ], + [ + 1.9852980375289917, + 0.36000943183898926 + ], + [ + 1.9972517490386963, + 0.30596867203712463 + ], + [ + 2.009254217147827, + 0.24899908900260925 + ], + [ + 2.0200159549713135, + 0.19426099956035614 + ], + [ + 2.028616189956665, + 0.14022786915302277 + ], + [ + 2.0368642807006836, + 0.0837329849600792 + ], + [ + 2.0446321964263916, + 0.027753230184316635 + ], + [ + 2.0468854904174805, + -0.027986951172351837 + ], + [ + 2.0531952381134033, + -0.08293461799621582 + ], + [ + 2.0552361011505127, + -0.13702012598514557 + ], + [ + 2.05584979057312, + -0.1936483234167099 + ], + [ + 2.052304744720459, + -0.24383021891117096 + ], + [ + 2.0526440143585205, + -0.29550325870513916 + ], + [ + 2.048532724380493, + -0.3591861128807068 + ], + [ + 2.0443758964538574, + -0.40666431188583374 + ], + [ + 2.0443642139434814, + -0.46980494260787964 + ], + [ + 2.0338969230651855, + -0.5193932056427002 + ], + [ + 2.0240724086761475, + -0.5742443799972534 + ], + [ + 2.0198025703430176, + -0.6330156922340393 + ], + [ + 2.0025546550750732, + -0.6862195730209351 + ], + [ + 1.9887348413467407, + -0.7390432357788086 + ], + [ + 1.9728606939315796, + -0.7888534069061279 + ], + [ + 1.9517942667007446, + -0.8563905358314514 + ], + [ + 1.9420608282089233, + -0.9004015326499939 + ], + [ + 1.9264236688613892, + -0.9444159865379333 + ], + [ + 1.909824013710022, + -0.9982982277870178 + ], + [ + 1.886473536491394, + -1.050907015800476 + ], + [ + 1.8674519062042236, + -1.094844102859497 + ], + [ + 1.8503884077072144, + -1.1460943222045898 + ], + [ + 1.8287944793701172, + -1.19496488571167 + ], + [ + 1.7960340976715088, + -1.2443928718566895 + ], + [ + 1.7666563987731934, + -1.2799354791641235 + ], + [ + 1.7382992506027222, + -1.3262783288955688 + ], + [ + 1.7129380702972412, + -1.3695182800292969 + ], + [ + 1.684373140335083, + -1.4202955961227417 + ], + [ + 1.6448442935943604, + -1.4575445652008057 + ], + [ + 1.624143362045288, + -1.4992337226867676 + ], + [ + 1.5851563215255737, + -1.5449323654174805 + ], + [ + 1.55446195602417, + -1.5835217237472534 + ], + [ + 1.5131127834320068, + -1.6291346549987793 + ], + [ + 1.4787636995315552, + -1.6570931673049927 + ], + [ + 1.4342319965362549, + -1.6829447746276855 + ], + [ + 1.384718894958496, + -1.7119535207748413 + ], + [ + 1.3472832441329956, + -1.738911747932434 + ], + [ + 1.3141601085662842, + -1.7887866497039795 + ], + [ + 1.2666597366333008, + -1.8041819334030151 + ], + [ + 1.22465980052948, + -1.8300002813339233 + ], + [ + 1.1822032928466797, + -1.8676955699920654 + ], + [ + 1.1421464681625366, + -1.8964000940322876 + ], + [ + 1.0968680381774902, + -1.9208683967590332 + ], + [ + 1.0547646284103394, + -1.9544309377670288 + ], + [ + 0.976579487323761, + -1.914185881614685 + ], + [ + 0.9392303228378296, + -1.9442344903945923 + ], + [ + 0.8792645931243896, + -1.9660634994506836 + ], + [ + 0.8503670692443848, + -1.9907130002975464 + ], + [ + 0.812386691570282, + -2.0461530685424805 + ], + [ + 0.7761523723602295, + -2.0736730098724365 + ], + [ + 0.7160670757293701, + -2.117474317550659 + ], + [ + 0.6659147143363953, + -2.1630029678344727 + ], + [ + 0.6172897815704346, + -2.1951303482055664 + ], + [ + 0.5469140410423279, + -2.2127740383148193 + ], + [ + 0.45462772250175476, + -2.1820499897003174 + ], + [ + 0.36450082063674927, + -2.183260679244995 + ], + [ + 0.25341686606407166, + -2.1558573246002197 + ], + [ + 0.11812781542539597, + -2.118143081665039 + ], + [ + -0.054833926260471344, + -2.017806053161621 + ], + [ + -0.22248850762844086, + -1.9006211757659912 + ], + [ + -0.3778339624404907, + -1.7416913509368896 + ], + [ + -0.47833186388015747, + -1.6339031457901 + ], + [ + -0.5277042984962463, + -1.5874066352844238 + ], + [ + -0.5500900149345398, + -1.573772668838501 + ], + [ + -0.5985336899757385, + -1.892890214920044 + ], + [ + -0.6200459599494934, + -1.9435665607452393 + ], + [ + -0.6419571042060852, + -1.9800007343292236 + ], + [ + -0.6618088483810425, + -1.9544645547866821 + ], + [ + -0.6725050210952759, + -1.910160779953003 + ], + [ + -0.667539119720459, + -1.8135590553283691 + ], + [ + -0.640052318572998, + -1.7172532081604004 + ], + [ + -0.629052460193634, + -1.6340324878692627 + ], + [ + -0.5882589221000671, + -1.5393677949905396 + ], + [ + -0.5432126522064209, + -1.4833647012710571 + ], + [ + -0.5077447891235352, + -1.445670247077942 + ], + [ + -0.46375808119773865, + -1.4242428541183472 + ], + [ + -0.5480551719665527, + -1.4715851545333862 + ], + [ + -0.5247310400009155, + -1.4488811492919922 + ], + [ + -0.4918777644634247, + -1.4331812858581543 + ], + [ + -0.4947419762611389, + -1.450975775718689 + ], + [ + -0.5342426896095276, + -1.5435386896133423 + ], + [ + -0.6388733983039856, + -1.7032588720321655 + ], + [ + -0.8014348745346069, + -1.8765698671340942 + ], + [ + -0.9571249485015869, + -2.0633420944213867 + ], + [ + -1.0846765041351318, + -2.1561086177825928 + ], + [ + -1.1955300569534302, + -2.180401086807251 + ], + [ + -1.2772194147109985, + -2.169501781463623 + ], + [ + -1.29525887966156, + -2.1280534267425537 + ], + [ + -1.3648170232772827, + -2.0986809730529785 + ], + [ + -1.4442802667617798, + -2.0715749263763428 + ], + [ + -1.5120972394943237, + -2.0225284099578857 + ], + [ + -1.5730106830596924, + -1.965773582458496 + ], + [ + -1.6367148160934448, + -1.8953351974487305 + ], + [ + -1.6879174709320068, + -1.8227035999298096 + ], + [ + -1.7132043838500977, + -1.7314528226852417 + ], + [ + -1.735830545425415, + -1.650993824005127 + ], + [ + -1.7569620609283447, + -1.5841424465179443 + ], + [ + -1.7611446380615234, + -1.5269325971603394 + ], + [ + -1.7931441068649292, + -1.497328758239746 + ], + [ + -1.8771740198135376, + -1.4869850873947144 + ], + [ + -1.9236654043197632, + -1.4803944826126099 + ], + [ + -1.9705396890640259, + -1.4703142642974854 + ], + [ + -2.044564962387085, + -1.480547547340393 + ], + [ + -2.1139039993286133, + -1.4970269203186035 + ], + [ + -2.194765567779541, + -1.5028825998306274 + ], + [ + -2.2751429080963135, + -1.4990124702453613 + ], + [ + -2.3369157314300537, + -1.467200517654419 + ], + [ + -2.4083096981048584, + -1.430380940437317 + ], + [ + -2.4738833904266357, + -1.3780300617218018 + ], + [ + -2.5244171619415283, + -1.3232356309890747 + ], + [ + -2.581082820892334, + -1.2635838985443115 + ], + [ + -2.625917434692383, + -1.196604609489441 + ], + [ + -2.682605743408203, + -1.1417529582977295 + ], + [ + -2.724843978881836, + -1.0747928619384766 + ], + [ + -2.763423204421997, + -1.0052158832550049 + ], + [ + -2.8057756423950195, + -0.9306648969650269 + ], + [ + -2.836543083190918, + -0.8596242070198059 + ], + [ + -2.858031749725342, + -0.7836382985115051 + ], + [ + -2.878641128540039, + -0.7108041644096375 + ], + [ + -2.895611524581909, + -0.634407639503479 + ], + [ + -2.9086661338806152, + -0.5609465837478638 + ], + [ + -2.9136550426483154, + -0.4889409840106964 + ], + [ + -2.9176650047302246, + -0.4121151566505432 + ], + [ + -2.920250177383423, + -0.33876174688339233 + ], + [ + -3.012542724609375, + -0.2511477768421173 + ], + [ + -3.027001142501831, + -0.17742539942264557 + ], + [ + -3.031571865081787, + -0.09994552284479141 + ], + [ + -3.0404305458068848, + -0.019353676587343216 + ], + [ + -3.0370371341705322, + 0.05985275283455849 + ], + [ + -3.0380406379699707, + 0.1337829828262329 + ], + [ + -3.027435064315796, + 0.20997832715511322 + ], + [ + -3.0283520221710205, + 0.2803376317024231 + ], + [ + -3.0140609741210938, + 0.35903212428092957 + ], + [ + -3.0063071250915527, + 0.43691587448120117 + ], + [ + -2.9903881549835205, + 0.5095707774162292 + ], + [ + -2.9810566902160645, + 0.5858488082885742 + ], + [ + -2.9618659019470215, + 0.6596417427062988 + ], + [ + -2.9772891998291016, + 0.7641208171844482 + ], + [ + -2.9629781246185303, + 0.84083491563797 + ], + [ + -2.9462153911590576, + 0.9086923599243164 + ], + [ + -2.9220540523529053, + 0.9702616930007935 + ], + [ + -2.9029810428619385, + 1.050229549407959 + ], + [ + -2.87648606300354, + 1.1280237436294556 + ], + [ + -2.85565185546875, + 1.1965140104293823 + ], + [ + -2.8345563411712646, + 1.2685397863388062 + ], + [ + -2.8009085655212402, + 1.3566017150878906 + ], + [ + -2.7621185779571533, + 1.4320367574691772 + ], + [ + -2.711992025375366, + 1.5123510360717773 + ], + [ + -2.651895523071289, + 1.5944353342056274 + ], + [ + -2.5953571796417236, + 1.6477941274642944 + ], + [ + -2.5262110233306885, + 1.699404239654541 + ], + [ + -2.482839584350586, + 1.7643747329711914 + ], + [ + -2.4126625061035156, + 1.7879997491836548 + ], + [ + -2.363837480545044, + 1.8217486143112183 + ], + [ + -2.317458391189575, + 1.8715041875839233 + ], + [ + -2.2701034545898438, + 1.9078409671783447 + ], + [ + -2.2377190589904785, + 1.945436954498291 + ], + [ + -2.177765130996704, + 1.9780257940292358 + ], + [ + -2.1320748329162598, + 2.0156772136688232 + ], + [ + -2.07867431640625, + 2.0727920532226562 + ], + [ + -2.030075788497925, + 2.1081161499023438 + ], + [ + -1.9569929838180542, + 2.1331570148468018 + ], + [ + -1.9040024280548096, + 2.1690497398376465 + ], + [ + -1.8473048210144043, + 2.198195457458496 + ], + [ + -1.790403962135315, + 2.2111968994140625 + ], + [ + -1.7382831573486328, + 2.2407805919647217 + ], + [ + -1.6828320026397705, + 2.276496648788452 + ], + [ + -1.6152105331420898, + 2.281519651412964 + ], + [ + -1.5538396835327148, + 2.3064870834350586 + ], + [ + -1.501750111579895, + 2.310166358947754 + ], + [ + -1.4373867511749268, + 2.329052448272705 + ], + [ + -1.3839010000228882, + 2.3393683433532715 + ], + [ + -1.3358155488967896, + 2.3524537086486816 + ], + [ + -1.292285680770874, + 2.344827175140381 + ], + [ + -1.2370109558105469, + 2.3486952781677246 + ], + [ + -1.2000646591186523, + 2.348179578781128 + ], + [ + -1.1455433368682861, + 2.350385904312134 + ], + [ + -1.101224422454834, + 2.3683669567108154 + ], + [ + -1.052161455154419, + 2.3695015907287598 + ], + [ + -1.0148978233337402, + 2.374345064163208 + ], + [ + -0.9671911001205444, + 2.3812332153320312 + ], + [ + -0.9316477179527283, + 2.3903934955596924 + ], + [ + -0.8905055522918701, + 2.3952643871307373 + ], + [ + -0.8540663719177246, + 2.3975415229797363 + ], + [ + -0.7962154746055603, + 2.4191648960113525 + ], + [ + -0.7757487297058105, + 2.435396671295166 + ], + [ + -0.7300823330879211, + 2.44856858253479 + ], + [ + -0.6863178610801697, + 2.4689321517944336 + ], + [ + -0.6393466591835022, + 2.463688611984253 + ], + [ + -0.5890231728553772, + 2.481721878051758 + ], + [ + -0.5453053116798401, + 2.490652561187744 + ], + [ + -0.50407874584198, + 2.4985015392303467 + ], + [ + -0.45502135157585144, + 2.503329038619995 + ], + [ + -0.4007115662097931, + 2.5152299404144287 + ], + [ + -0.3617822229862213, + 2.5356392860412598 + ], + [ + -0.28880366683006287, + 2.5387301445007324 + ], + [ + -0.23872920870780945, + 2.525373697280884 + ], + [ + -0.16778776049613953, + 2.5388519763946533 + ], + [ + -0.10583434253931046, + 2.5329205989837646 + ], + [ + -0.05415201932191849, + 2.547940492630005 + ], + [ + -0.0032007666304707527, + 2.5527305603027344 + ], + [ + 0.0419035479426384, + 2.5284228324890137 + ], + [ + 0.12796764075756073, + 2.5247223377227783 + ], + [ + 0.1797327697277069, + 2.5494322776794434 + ], + [ + 0.24520958960056305, + 2.5436084270477295 + ], + [ + 0.3022260069847107, + 2.542194366455078 + ], + [ + 0.35460618138313293, + 2.520174503326416 + ], + [ + 0.41946378350257874, + 2.5196592807769775 + ], + [ + 0.46872425079345703, + 2.5220162868499756 + ], + [ + 0.5266742706298828, + 2.504120349884033 + ], + [ + 0.6060177683830261, + 2.5000243186950684 + ], + [ + 0.6642038226127625, + 2.4721007347106934 + ], + [ + 0.7458529472351074, + 2.458055019378662 + ], + [ + 0.797263503074646, + 2.4908089637756348 + ], + [ + 0.8470003604888916, + 2.4221208095550537 + ], + [ + 0.9332271218299866, + 2.42008113861084 + ], + [ + 0.9862779974937439, + 2.3952484130859375 + ], + [ + 1.0538870096206665, + 2.3781652450561523 + ], + [ + 1.111477017402649, + 2.3285584449768066 + ], + [ + 1.1954751014709473, + 2.3137598037719727 + ], + [ + 1.2511414289474487, + 2.268101930618286 + ], + [ + 1.3104890584945679, + 2.246967315673828 + ], + [ + 1.3784379959106445, + 2.2122318744659424 + ], + [ + 1.4414472579956055, + 2.17385196685791 + ], + [ + 1.5019047260284424, + 2.1512889862060547 + ], + [ + 1.5576761960983276, + 2.105919599533081 + ], + [ + 1.6273058652877808, + 2.0529260635375977 + ], + [ + 1.6929495334625244, + 2.029416799545288 + ], + [ + 1.7603707313537598, + 1.9849306344985962 + ], + [ + 1.8037184476852417, + 1.9327088594436646 + ], + [ + 1.8640540838241577, + 1.8926706314086914 + ], + [ + 1.9293409585952759, + 1.8465800285339355 + ], + [ + 1.9726957082748413, + 1.796122670173645 + ], + [ + 2.03570294380188, + 1.7438268661499023 + ], + [ + 2.0876803398132324, + 1.6883608102798462 + ], + [ + 2.1440749168395996, + 1.6497546434402466 + ], + [ + 2.191690683364868, + 1.59380304813385 + ], + [ + 2.2472918033599854, + 1.5241057872772217 + ], + [ + 2.2852673530578613, + 1.4742635488510132 + ], + [ + 2.3335671424865723, + 1.4111393690109253 + ], + [ + 2.3914554119110107, + 1.3513866662979126 + ], + [ + 2.4380853176116943, + 1.297100305557251 + ], + [ + 2.474743604660034, + 1.2347817420959473 + ], + [ + 2.5217645168304443, + 1.1775881052017212 + ], + [ + 2.5668768882751465, + 1.1088923215866089 + ], + [ + 2.6099956035614014, + 1.0353500843048096 + ], + [ + 2.657444477081299, + 0.968788206577301 + ], + [ + 2.6951029300689697, + 0.8935712575912476 + ], + [ + 2.7195382118225098, + 0.8351325392723083 + ], + [ + 2.7655739784240723, + 0.7628029584884644 + ], + [ + 2.7955899238586426, + 0.6807453632354736 + ], + [ + 2.829982280731201, + 0.6168544888496399 + ], + [ + 2.8581137657165527, + 0.538804829120636 + ], + [ + 2.889735698699951, + 0.4630218744277954 + ], + [ + 2.9193005561828613, + 0.3800201416015625 + ], + [ + 2.948359727859497, + 0.29613617062568665 + ], + [ + 2.9684951305389404, + 0.20782488584518433 + ], + [ + 3.000218152999878, + 0.12198688089847565 + ], + [ + 3.0217325687408447, + 0.03142319619655609 + ], + [ + 3.045511245727539, + -0.06487647444009781 + ], + [ + 3.0460352897644043, + -0.14036421477794647 + ], + [ + 3.058229684829712, + -0.2300051897764206 + ], + [ + 3.079805850982666, + -0.3216644525527954 + ], + [ + 3.0902833938598633, + -0.42159315943717957 + ], + [ + 3.090718984603882, + -0.5077506899833679 + ], + [ + 3.0955865383148193, + -0.6067076325416565 + ], + [ + 3.097529172897339, + -0.7039830684661865 + ], + [ + 3.1028051376342773, + -0.8013229966163635 + ], + [ + 3.0955312252044678, + -0.9044585824012756 + ], + [ + 3.0934295654296875, + -1.0075933933258057 + ], + [ + 3.0832741260528564, + -1.1146950721740723 + ], + [ + 3.076805353164673, + -1.2261617183685303 + ], + [ + 3.0751819610595703, + -1.3362665176391602 + ], + [ + 3.0754971504211426, + -1.4560726881027222 + ], + [ + 3.014509677886963, + -1.5269591808319092 + ], + [ + 2.9847373962402344, + -1.6404539346694946 + ], + [ + 2.946702480316162, + -1.7503511905670166 + ], + [ + 2.900275707244873, + -1.8441591262817383 + ], + [ + 2.8524551391601562, + -1.9643250703811646 + ], + [ + 2.8231019973754883, + -2.072808265686035 + ], + [ + 2.7650814056396484, + -2.1800851821899414 + ], + [ + 2.7038183212280273, + -2.2937002182006836 + ], + [ + 2.645848512649536, + -2.404895544052124 + ], + [ + 2.561894416809082, + -2.5093536376953125 + ], + [ + 2.500335216522217, + -2.620445489883423 + ], + [ + 2.410123586654663, + -2.726806163787842 + ], + [ + 2.270482063293457, + -2.8333029747009277 + ], + [ + 2.201957941055298, + -2.8957021236419678 + ], + [ + 2.136942148208618, + -3.0040125846862793 + ], + [ + 2.024168014526367, + -3.1082284450531006 + ], + [ + 1.9148718118667603, + -3.1709301471710205 + ], + [ + 1.8106225728988647, + -3.2769107818603516 + ], + [ + 1.6913504600524902, + -3.3605289459228516 + ], + [ + 1.5654969215393066, + -3.430734872817993 + ], + [ + 1.4234001636505127, + -3.520102024078369 + ], + [ + 1.2560296058654785, + -3.582613706588745 + ], + [ + 1.0903170108795166, + -3.596350908279419 + ], + [ + 0.9169342517852783, + -3.5893301963806152 + ], + [ + 0.701367199420929, + -3.6350929737091064 + ], + [ + 0.5097681879997253, + -3.636725664138794 + ], + [ + 0.4784690737724304, + -3.6943578720092773 + ], + [ + 0.3449876010417938, + -3.7533657550811768 + ], + [ + 0.1965716928243637, + -3.8127543926239014 + ], + [ + 0.0830964744091034, + -3.9074316024780273 + ], + [ + -0.0814841017127037, + -3.9415621757507324 + ], + [ + -0.2178017646074295, + -3.969921588897705 + ], + [ + -0.38107481598854065, + -4.029063701629639 + ], + [ + -0.5660316348075867, + -4.000732421875 + ], + [ + -0.7196700572967529, + -3.976536273956299 + ], + [ + -0.9106118679046631, + -3.9504780769348145 + ], + [ + -1.0998752117156982, + -3.9075562953948975 + ], + [ + -1.2563295364379883, + -3.8200831413269043 + ], + [ + -1.4544214010238647, + -3.7071053981781006 + ], + [ + -3.0006213188171387, + -7.207033634185791 + ], + [ + -3.4433045387268066, + -7.032714366912842 + ], + [ + -3.43412184715271, + -7.545030117034912 + ], + [ + -3.825704574584961, + -7.590828895568848 + ], + [ + -4.113344669342041, + -7.517468452453613 + ], + [ + -4.368183135986328, + -7.506117820739746 + ], + [ + -4.8009867668151855, + -7.406807899475098 + ], + [ + -5.047353744506836, + -7.236881256103516 + ], + [ + -5.356578350067139, + -7.1335601806640625 + ], + [ + -5.647794246673584, + -6.922834873199463 + ], + [ + -5.931471824645996, + -6.773493766784668 + ], + [ + -6.162847518920898, + -6.5040178298950195 + ], + [ + -6.425640106201172, + -6.250199317932129 + ], + [ + -6.6294965744018555, + -5.955855846405029 + ], + [ + -6.857776641845703, + -5.586231708526611 + ], + [ + -7.068276405334473, + -5.20672607421875 + ], + [ + -7.437286853790283, + -5.641544818878174 + ], + [ + -7.696932315826416, + -5.457540035247803 + ], + [ + -7.9060587882995605, + -5.2242584228515625 + ], + [ + -8.066984176635742, + -4.946529388427734 + ], + [ + -8.336150169372559, + -4.7649970054626465 + ], + [ + -8.52597713470459, + -4.450690746307373 + ], + [ + -8.681577682495117, + -4.149618625640869 + ], + [ + -8.788962364196777, + -3.88460373878479 + ], + [ + -8.94499683380127, + -3.620978355407715 + ], + [ + -9.00985336303711, + -3.3398890495300293 + ], + [ + -9.162784576416016, + -3.038771152496338 + ], + [ + -9.188023567199707, + -2.7745771408081055 + ], + [ + -9.269676208496094, + -2.492663860321045 + ], + [ + -9.298174858093262, + -2.2071080207824707 + ], + [ + -9.301246643066406, + -1.9218449592590332 + ], + [ + -9.279318809509277, + -1.6178292036056519 + ], + [ + -9.617018699645996, + -1.3741966485977173 + ], + [ + -9.661920547485352, + -1.098971962928772 + ], + [ + -9.64769458770752, + -0.8025069832801819 + ], + [ + -9.675349235534668, + -0.549736499786377 + ], + [ + -9.680461883544922, + -0.32157254219055176 + ], + [ + -9.676546096801758, + -0.04465971514582634 + ], + [ + -9.685470581054688, + 0.24179793894290924 + ], + [ + -9.667086601257324, + 0.4546229839324951 + ], + [ + -9.610819816589355, + 0.6807534098625183 + ], + [ + -9.549544334411621, + 0.9478676319122314 + ], + [ + -9.535961151123047, + 1.2063448429107666 + ], + [ + -9.573528289794922, + 1.42529296875 + ], + [ + -9.505254745483398, + 1.6640177965164185 + ], + [ + -9.41240406036377, + 1.925183653831482 + ] + ], + "total_points": 1000 +} \ No newline at end of file diff --git a/vna_system/calibration/s11_start100_stop8800_points1000_bw1khz/яыф/short_metadata.json b/vna_system/calibration/s11_start100_stop8800_points1000_bw1khz/яыф/short_metadata.json new file mode 100644 index 0000000..7c0c589 --- /dev/null +++ b/vna_system/calibration/s11_start100_stop8800_points1000_bw1khz/яыф/short_metadata.json @@ -0,0 +1,16 @@ +{ + "preset": { + "filename": "s11_start100_stop8800_points1000_bw1khz.bin", + "mode": "s11", + "start_freq": 100000000.0, + "stop_freq": 8800000000.0, + "points": 1000, + "bandwidth": 1000.0 + }, + "calibration_name": "яыф", + "standard": "short", + "sweep_number": 13, + "sweep_timestamp": 1758896378.4093437, + "created_timestamp": "2025-09-26T17:20:00.022500", + "total_points": 1000 +} \ No newline at end of file diff --git a/vna_system/core/acquisition/data_acquisition.py b/vna_system/core/acquisition/data_acquisition.py index 6105fcd..cf440e2 100644 --- a/vna_system/core/acquisition/data_acquisition.py +++ b/vna_system/core/acquisition/data_acquisition.py @@ -1,36 +1,36 @@ -from __future__ import annotations - import io -import logging import os import struct import threading import time -from typing import BinaryIO, List, Tuple +from typing import BinaryIO import serial from vna_system.core import config as cfg +from vna_system.core.acquisition.port_manager import VNAPortLocator from vna_system.core.acquisition.sweep_buffer import SweepBuffer +from vna_system.core.logging.logger import get_component_logger - -logger = logging.getLogger(__name__) +logger = get_component_logger(__file__) class VNADataAcquisition: """Main data acquisition class with asynchronous sweep collection.""" def __init__(self) -> None: + # Configuration self.bin_log_path: str = cfg.BIN_INPUT_FILE_PATH - self.baud: int = cfg.DEFAULT_BAUD_RATE + # Dependencies + self.vna_port_locator = VNAPortLocator() self._sweep_buffer = SweepBuffer() # Control flags self._running: bool = False self._thread: threading.Thread | None = None - self._stop_event: threading.Event = threading.Event() + self._stop_event = threading.Event() self._paused: bool = False # Acquisition modes @@ -39,29 +39,30 @@ class VNADataAcquisition: # Sweep collection state self._collecting: bool = False - self._collected_rx_payloads: List[bytes] = [] + self._collected_rx_payloads: list[bytes] = [] self._meas_cmds_in_sweep: int = 0 + logger.debug("VNADataAcquisition initialized", baud=self.baud, bin_log_path=self.bin_log_path) + # --------------------------------------------------------------------- # # Lifecycle # --------------------------------------------------------------------- # - def start(self) -> None: """Start the data acquisition background thread.""" if self._running: - logger.debug("Acquisition already running; start() call ignored.") + logger.debug("start() ignored; acquisition already running") return self._running = True self._stop_event.clear() - self._thread = threading.Thread(target=self._acquisition_loop, daemon=True) + self._thread = threading.Thread(target=self._acquisition_loop, daemon=True, name="VNA-Acq") self._thread.start() - logger.info("Acquisition thread started.") + logger.info("Acquisition thread started") def stop(self) -> None: """Stop the data acquisition background thread.""" if not self._running: - logger.debug("Acquisition not running; stop() call ignored.") + logger.debug("stop() ignored; acquisition not running") return self._running = False @@ -69,8 +70,7 @@ class VNADataAcquisition: if self._thread and self._thread.is_alive(): self._thread.join(timeout=5.0) - logger.info("Acquisition thread joined.") - + logger.info("Acquisition thread joined") @property def is_running(self) -> bool: @@ -95,7 +95,7 @@ class VNADataAcquisition: def pause(self) -> None: """Pause the data acquisition.""" if not self._running: - logger.warning("Cannot pause: acquisition not running") + logger.warning("Cannot pause; acquisition not running") return self._paused = True @@ -105,24 +105,21 @@ class VNADataAcquisition: """Set continuous or single sweep mode. Also resumes if paused.""" self._continuous_mode = continuous - # Resume acquisition if setting to continuous mode and currently paused if continuous and self._paused: self._paused = False - logger.info("Data acquisition resumed (continuous mode)") + logger.info("Data acquisition resumed (continuous mode=True)") - mode_str = "continuous" if continuous else "single sweep" - logger.info(f"Acquisition mode set to: {mode_str}") + logger.info("Acquisition mode updated", continuous=continuous) def trigger_single_sweep(self) -> None: """Trigger a single sweep. Automatically switches to single sweep mode if needed.""" if not self._running: - logger.warning("Cannot trigger single sweep: acquisition not running") + logger.warning("Cannot trigger single sweep; acquisition not running") return - # Switch to single sweep mode if currently in continuous mode if self._continuous_mode: self.set_continuous_mode(False) - logger.info("Switched from continuous to single sweep mode") + logger.info("Switched from continuous to single-sweep mode") self._single_sweep_requested = True if self._paused: @@ -131,155 +128,158 @@ class VNADataAcquisition: logger.info("Single sweep triggered") # --------------------------------------------------------------------- # - # Serial management + # Serial helpers # --------------------------------------------------------------------- # - def _drain_serial_input(self, ser: serial.Serial) -> None: """Drain any pending bytes from the serial input buffer.""" if not ser: return - drained = 0 while True: - bytes_waiting = getattr(ser, "in_waiting", 0) - if bytes_waiting <= 0: + waiting = getattr(ser, "in_waiting", 0) + if waiting <= 0: break - drained += len(ser.read(bytes_waiting)) + drained += len(ser.read(waiting)) time.sleep(cfg.SERIAL_DRAIN_CHECK_DELAY) if drained: - logger.warning("Drained %d pending byte(s) from serial input.", drained) + logger.warning("Drained pending bytes from serial input", bytes=drained) # --------------------------------------------------------------------- # # Acquisition loop # --------------------------------------------------------------------- # - def _acquisition_loop(self) -> None: """Main acquisition loop executed by the background thread.""" while self._running and not self._stop_event.is_set(): try: - # Check if paused + # Honor pause if self._paused: time.sleep(0.1) continue - # Auto-detect port - self.port: str = cfg.get_vna_port() - logger.info(f"Using auto-detected port: {self.port}") + # Auto-detect and validate port + port = self.vna_port_locator.find_vna_port() + if port is None: + logger.warning("VNA port not found; retrying shortly") + time.sleep(0.5) + continue - with serial.Serial(self.port, self.baud) as ser: + logger.debug("Using port", device=port, baud=self.baud) + + # Open serial + process one sweep from the binary log + with serial.Serial(port, self.baud) as ser: self._drain_serial_input(ser) + + # Open the log file each iteration to read the next sweep from start with open(self.bin_log_path, "rb") as raw: buffered = io.BufferedReader(raw, buffer_size=cfg.SERIAL_BUFFER_SIZE) self._process_sweep_data(buffered, ser) - # Handle single sweep mode + # Handle single-sweep mode transitions if not self._continuous_mode: if self._single_sweep_requested: self._single_sweep_requested = False - logger.info("Single sweep completed, pausing acquisition") + logger.info("Single sweep completed; pausing acquisition") self.pause() else: - # In single sweep mode but no sweep requested, pause self.pause() except Exception as exc: # noqa: BLE001 - logger.error("Acquisition error: %s", exc) + logger.error("Acquisition loop error", error=repr(exc)) time.sleep(1.0) # --------------------------------------------------------------------- # # Log processing # --------------------------------------------------------------------- # - def _process_sweep_data(self, f: BinaryIO, ser: serial.Serial) -> None: - """Process the binary log file and collect sweep data one sweep at a time.""" + """Process the binary log file and collect sweep data for a single sweep.""" try: - # Start from beginning of file for each sweep - f.seek(0) - # Validate header header = self._read_exact(f, len(cfg.MAGIC)) if header != cfg.MAGIC: - raise ValueError("Invalid log format: MAGIC header mismatch.") + raise ValueError("Invalid log format: MAGIC header mismatch") self._reset_sweep_state() - # Process one complete sweep + # Read until exactly one sweep is completed sweep_completed = False while not sweep_completed and self._running and not self._stop_event.is_set(): - # Read record header - dir_byte = f.read(1) - if not dir_byte: - # EOF reached without completing sweep - wait and retry - logger.debug("EOF reached, waiting for more data...") + dir_b = f.read(1) + if not dir_b: + # EOF reached; wait for more data to arrive on disk + logger.debug("EOF reached; waiting for more data") time.sleep(0.1) break - direction = dir_byte[0] + direction = dir_b[0] (length,) = struct.unpack(">I", self._read_exact(f, 4)) if direction == cfg.DIR_TO_DEV: - # TX path: stream to device and inspect for sweep start + # TX path: forward to device and inspect for sweep start first = self._serial_write_from_file(f, length, ser) if not self._collecting and self._is_sweep_start_command(length, first): self._collecting = True - self._collected_rx_payloads = [] + self._collected_rx_payloads.clear() self._meas_cmds_in_sweep = 0 - logger.info("Starting sweep data collection from device") - + logger.info("Sweep collection started") elif direction == cfg.DIR_FROM_DEV: - # RX path: read exact number of bytes from device + # RX path: capture bytes from device; keep file pointer in sync rx_bytes = self._serial_read_exact(length, ser, capture=self._collecting) - self._skip_bytes(f, length) # Keep log file pointer in sync + self._skip_bytes(f, length) if self._collecting: self._collected_rx_payloads.append(rx_bytes) self._meas_cmds_in_sweep += 1 - # Check for sweep completion if self._meas_cmds_in_sweep >= cfg.MEAS_CMDS_PER_SWEEP: self._finalize_sweep() sweep_completed = True + else: + # Unknown record type: skip bytes to keep in sync + logger.warning("Unknown record direction; skipping", direction=direction, length=length) + self._skip_bytes(f, length) except Exception as exc: # noqa: BLE001 - logger.error("Processing error: %s", exc) + logger.error("Processing error", error=repr(exc)) time.sleep(1.0) def _finalize_sweep(self) -> None: """Parse collected payloads into points and push to the buffer.""" - all_points: List[Tuple[float, float]] = [] + all_points: list[tuple[float, float]] = [] for payload in self._collected_rx_payloads: - all_points.extend(self._parse_measurement_data(payload)) + if payload: + all_points.extend(self._parse_measurement_data(payload)) if all_points: sweep_number = self._sweep_buffer.add_sweep(all_points) - logger.info(f"Collected sweep #{sweep_number} with {len(all_points)} data points") + logger.info("Sweep collected", sweep_number=sweep_number, points=len(all_points)) if len(all_points) != cfg.EXPECTED_POINTS_PER_SWEEP: logger.warning( - "Expected %d points, got %d.", - cfg.EXPECTED_POINTS_PER_SWEEP, - len(all_points), + "Unexpected number of points", + expected=cfg.EXPECTED_POINTS_PER_SWEEP, + actual=len(all_points), ) + else: + logger.warning("No points parsed for sweep") self._reset_sweep_state() def _reset_sweep_state(self) -> None: """Reset internal state for the next sweep collection.""" self._collecting = False - self._collected_rx_payloads = [] + self._collected_rx_payloads.clear() self._meas_cmds_in_sweep = 0 # --------------------------------------------------------------------- # # I/O helpers # --------------------------------------------------------------------- # - def _read_exact(self, f: BinaryIO, n: int) -> bytes: """Read exactly *n* bytes from a file-like object or raise EOFError.""" buf = bytearray() while len(buf) < n: chunk = f.read(n - len(buf)) if not chunk: - raise EOFError(f"Unexpected EOF while reading {n} bytes.") + raise EOFError(f"Unexpected EOF while reading {n} bytes") buf += chunk return bytes(buf) @@ -290,14 +290,13 @@ class VNADataAcquisition: f.seek(n, os.SEEK_CUR) return except (OSError, io.UnsupportedOperation): - # Fall back to manual skipping below. pass remaining = n while remaining > 0: chunk = f.read(min(cfg.FILE_CHUNK_SIZE, remaining)) if not chunk: - raise EOFError(f"Unexpected EOF while skipping {n} bytes.") + raise EOFError(f"Unexpected EOF while skipping {n} bytes") remaining -= len(chunk) def _serial_write_from_file(self, f: BinaryIO, nbytes: int, ser: serial.Serial) -> bytes: @@ -313,12 +312,12 @@ class VNADataAcquisition: to_read = min(cfg.TX_CHUNK_SIZE, remaining) chunk = f.read(to_read) if not chunk: - raise EOFError("Log truncated while sending.") + raise EOFError("Log truncated while sending") # Capture a peek for command inspection - needed = max(0, cfg.SERIAL_PEEK_SIZE - len(first)) - if needed: - first.extend(chunk[:needed]) + need = max(0, cfg.SERIAL_PEEK_SIZE - len(first)) + if need: + first.extend(chunk[:need]) # Write to serial written = 0 @@ -334,17 +333,16 @@ class VNADataAcquisition: def _serial_read_exact(self, nbytes: int, ser: serial.Serial, capture: bool = False) -> bytes: """Read exactly *nbytes* from the serial port; optionally capture and return them.""" - deadline = time.monotonic() + cfg.RX_TIMEOUT total = 0 out = bytearray() if capture else None + old_timeout = ser.timeout ser.timeout = min(cfg.SERIAL_IDLE_TIMEOUT, cfg.RX_TIMEOUT) - try: while total < nbytes: if time.monotonic() >= deadline: - raise TimeoutError(f"Timeout while waiting for {nbytes} bytes.") + raise TimeoutError(f"Timeout while waiting for {nbytes} bytes") chunk = ser.read(nbytes - total) if chunk: total += len(chunk) @@ -357,25 +355,18 @@ class VNADataAcquisition: # --------------------------------------------------------------------- # # Parsing & detection # --------------------------------------------------------------------- # - - def _parse_measurement_data(self, payload: bytes) -> List[Tuple[float, float]]: + def _parse_measurement_data(self, payload: bytes) -> list[tuple[float, float]]: """Parse complex measurement samples (float32 pairs) from a payload.""" if len(payload) <= cfg.MEAS_HEADER_LEN: return [] data = memoryview(payload)[cfg.MEAS_HEADER_LEN:] - out: List[Tuple[float, float]] = [] - n_pairs = len(data) // 8 # 2 × float32 per point - - for i in range(n_pairs): - off = i * 8 - real = struct.unpack_from(" bool: """Return True if a TX command indicates the start of a sweep.""" return tx_len == cfg.SWEEP_CMD_LEN and first_bytes.startswith(cfg.SWEEP_CMD_PREFIX) - diff --git a/vna_system/core/acquisition/port_manager.py b/vna_system/core/acquisition/port_manager.py new file mode 100644 index 0000000..1bab8f2 --- /dev/null +++ b/vna_system/core/acquisition/port_manager.py @@ -0,0 +1,136 @@ +import glob + +import serial.tools.list_ports + +from vna_system.core.logging.logger import get_component_logger +from vna_system.core.config import VNA_PID, VNA_VID + +logger = get_component_logger(__file__) + + +class VNAPortLocator: + """ + Robust VNA serial port locator with in-memory cache. + + Strategy + -------- + 1) Prefer the cached port if it exists *and* matches expected VID/PID. + 2) Scan all ports and pick an exact VID/PID match. + 3) As a last resort, pick the first /dev/ttyACM* (unverified). + """ + + __slots__ = ("_cached_port") + + def __init__(self) -> None: + self._cached_port: str | None = None + logger.debug("VNAPortLocator initialized") + + + # --------------------------------------------------------------------- + # Helpers + # --------------------------------------------------------------------- + def _enumerate_ports(self) -> list: + """Return a list of pyserial ListPortInfo entries.""" + try: + ports = list(serial.tools.list_ports.comports()) + logger.debug("Serial ports enumerated", count=len(ports)) + return ports + except Exception as exc: + logger.warning("Failed to enumerate serial ports", error=repr(exc)) + return [] + + def _get_port_info(self, device: str): + """Return pyserial ListPortInfo for a device path, or None if absent.""" + for p in self._enumerate_ports(): + if p.device == device: + return p + return None + + @staticmethod + def _is_exact_vna_port(p) -> bool: + """True if VID/PID match exactly the expected VNA device.""" + return getattr(p, "vid", None) == VNA_VID and getattr(p, "pid", None) == VNA_PID + + def verify_port_identity(self, port: str) -> bool: + """ + Verify that a device path belongs to *our* VNA by VID/PID. + + Returns True only if the device exists and matches VID/PID exactly. + """ + info = self._get_port_info(port) + if not info: + logger.debug("Port not present", device=port) + return False + if self._is_exact_vna_port(info): + logger.debug("Port verified by VID/PID", device=port, vid=info.vid, pid=info.pid) + return True + + logger.warning( + "Port belongs to a different device", + device=port, + vid=getattr(info, "vid", None), + pid=getattr(info, "pid", None), + expected_vid=VNA_VID, + expected_pid=VNA_PID, + ) + return False + + # --------------------------------------------------------------------- + # Discovery + # --------------------------------------------------------------------- + def find_vna_port(self) -> str | None: + """ + Locate the VNA serial port following the strategy described in the class docstring. + + Returns + ------- + str | None + Device path if found; otherwise None. + """ + cached = self._cached_port + + # 1) Try the cached port (must be present and VID/PID-correct) + if cached and self.verify_port_identity(cached): + logger.info("Using cached VNA port", device=cached) + return cached + elif cached: + logger.debug("Ignoring cached port due to VID/PID mismatch", device=cached) + + # 2) Enumerate ports and pick exact VID/PID match (prefer stable identity) + exact_candidates: list[str] = [] + for p in self._enumerate_ports(): + logger.debug( + "Inspecting port", + device=p.device, + vid=getattr(p, "vid", None), + pid=getattr(p, "pid", None), + manufacturer=getattr(p, "manufacturer", None), + description=getattr(p, "description", None), + ) + if self._is_exact_vna_port(p): + exact_candidates.append(p.device) + + logger.debug("Exact candidates collected", count=len(exact_candidates), candidates=exact_candidates) + + if exact_candidates: + # If the cached path is among exact matches, keep its priority + selected = cached if cached in exact_candidates else exact_candidates[0] + logger.info("VNA device found by VID/PID", device=selected) + + self._cached_port = selected + logger.debug("Cached port updated", device=selected) + return selected + + # 3) Last resort: first ACM device (best-effort on Linux; not cached) + try: + acm_ports = sorted(glob.glob("/dev/ttyACM*")) + logger.debug("ACM ports scanned", ports=acm_ports) + if acm_ports: + selected = acm_ports[0] + logger.info("Using first available ACM port (unverified)", device=selected) + return selected + except Exception as exc: + logger.warning("Error during ACM port detection", error=repr(exc)) + + logger.warning("VNA device not found by auto-detection") + return None diff --git a/vna_system/core/acquisition/sweep_buffer.py b/vna_system/core/acquisition/sweep_buffer.py index 0007650..ff5f712 100644 --- a/vna_system/core/acquisition/sweep_buffer.py +++ b/vna_system/core/acquisition/sweep_buffer.py @@ -1,54 +1,108 @@ -import math -import threading -import time from collections import deque from dataclasses import dataclass -from typing import List, Tuple +import threading +import time from vna_system.core.config import SWEEP_BUFFER_MAX_SIZE +from vna_system.core.logging.logger import get_component_logger + +logger = get_component_logger(__file__) + +Point = tuple[float, float] # (real, imag) -@dataclass +@dataclass(slots=True, frozen=True) class SweepData: - """Container for a single sweep with metadata""" + """ + Immutable container for a single sweep with metadata. + + Attributes + ---------- + sweep_number: + Monotonically increasing identifier for the sweep. + timestamp: + UNIX timestamp (seconds since epoch) when the sweep was stored. + points: + Sequence of complex-valued points represented as (real, imag) tuples. + total_points: + Cached number of points in `points` for quick access. + """ sweep_number: int timestamp: float - points: List[Tuple[float, float]] # Complex pairs (real, imag) + points: list[Point] total_points: int - @property - def magnitude_phase_data(self) -> List[Tuple[float, float, float, float]]: - """Convert to magnitude/phase representation""" - result = [] - for real, imag in self.points: - magnitude = (real * real + imag * imag) ** 0.5 - phase = math.atan2(imag, real) if (real != 0.0 or imag != 0.0) else 0.0 - result.append((real, imag, magnitude, phase)) - return result - class SweepBuffer: - """Thread-safe circular buffer for sweep data""" + """ + Thread-safe circular buffer for sweep data. - def __init__(self, max_size: int = SWEEP_BUFFER_MAX_SIZE, initial_sweep_number: int = 0): - self._buffer = deque(maxlen=max_size) + Parameters + ---------- + max_size: + Maximum number of sweeps to retain. Old entries are discarded when the + buffer exceeds this size. + initial_sweep_number: + Starting value for the internal sweep counter. + """ + + def __init__(self, max_size: int = SWEEP_BUFFER_MAX_SIZE, initial_sweep_number: int = 0) -> None: + self._buffer: deque[SweepData] = deque(maxlen=max_size) self._lock = threading.RLock() self._sweep_counter = initial_sweep_number + logger.debug("SweepBuffer initialized", max_size=max_size, initial_sweep_number=initial_sweep_number) - def add_sweep(self, points: List[Tuple[float, float]]) -> int: - """Add a new sweep to the buffer and return its number""" + # ------------------------------ + # Introspection utilities + # ------------------------------ + @property + def current_sweep_number(self) -> int: + """Return the last assigned sweep number (0 if none were added yet).""" + with self._lock: + logger.debug("Current sweep number retrieved", sweep_number=self._sweep_counter) + return self._sweep_counter + + # ------------------------------ + # Core API + # ------------------------------ + def add_sweep(self, points: list[Point]) -> int: + """ + Add a new sweep to the buffer. + + Parameters + ---------- + points: + Sequence of (real, imag) tuples representing a sweep. + + Returns + ------- + int + The assigned sweep number for the newly added sweep. + """ + timestamp = time.time() with self._lock: self._sweep_counter += 1 sweep = SweepData( sweep_number=self._sweep_counter, - timestamp=time.time(), - points=points, - total_points=len(points) + timestamp=timestamp, + points=list(points), # ensure we store our own list + total_points=len(points), ) self._buffer.append(sweep) + logger.debug( + "New sweep added", + sweep_number=sweep.sweep_number, + total_points=sweep.total_points, + buffer_size=len(self._buffer), + ) return self._sweep_counter def get_latest_sweep(self) -> SweepData | None: - """Get the most recent sweep""" + """Return the most recent sweep, or None if the buffer is empty.""" with self._lock: - return self._buffer[-1] if self._buffer else None + sweep = self._buffer[-1] if self._buffer else None + # if sweep: # TOO NOISY + # logger.debug("Latest sweep retrieved", sweep_number=sweep.sweep_number) + # else: + # logger.debug("Latest sweep requested but buffer is empty") + return sweep diff --git a/vna_system/core/config.py b/vna_system/core/config.py index fde6b5b..bac4961 100644 --- a/vna_system/core/config.py +++ b/vna_system/core/config.py @@ -1,124 +1,76 @@ -#!/usr/bin/env python3 -""" -Configuration file for VNA data acquisition system -""" - -import glob -import logging from pathlib import Path -import serial.tools.list_ports -# Base directory for VNA system +# ----------------------------------------------------------------------------- +# Project paths +# ----------------------------------------------------------------------------- BASE_DIR = Path(__file__).parent.parent -# Serial communication settings -DEFAULT_BAUD_RATE = 115200 -DEFAULT_PORT = "/dev/ttyACM0" +# ----------------------------------------------------------------------------- +# API / Server settings +# ----------------------------------------------------------------------------- +API_HOST = "0.0.0.0" +API_PORT = 8000 -# VNA device identification -VNA_VID = 0x0483 # STMicroelectronics -VNA_PID = 0x5740 # STM32 Virtual ComPort -VNA_MANUFACTURER = "STMicroelectronics" -VNA_PRODUCT = "STM32 Virtual ComPort" +# ----------------------------------------------------------------------------- +# Logging settings (используются из main) +# ----------------------------------------------------------------------------- +LOG_LEVEL = "INFO" # {"DEBUG","INFO","WARNING","ERROR","CRITICAL"} +LOG_DIR = BASE_DIR / "logs" # Directory for application logs +LOG_APP_FILE = LOG_DIR / "vna_system.log" # Main application log file + + +# ----------------------------------------------------------------------------- +# Serial communication settings +# ----------------------------------------------------------------------------- +DEFAULT_BAUD_RATE = 115200 RX_TIMEOUT = 5.0 TX_CHUNK_SIZE = 64 * 1024 +# ----------------------------------------------------------------------------- +# VNA device identification +# ----------------------------------------------------------------------------- +VNA_VID = 0x0483 # STMicroelectronics +VNA_PID = 0x5740 # STM32 Virtual ComPort + +# ----------------------------------------------------------------------------- # Sweep detection and parsing constants +# ----------------------------------------------------------------------------- SWEEP_CMD_LEN = 515 SWEEP_CMD_PREFIX = bytes([0xAA, 0x00, 0xDA]) MEAS_HEADER_LEN = 21 MEAS_CMDS_PER_SWEEP = 17 EXPECTED_POINTS_PER_SWEEP = 1000 +# ----------------------------------------------------------------------------- # Buffer settings +# ----------------------------------------------------------------------------- SWEEP_BUFFER_MAX_SIZE = 100 # Maximum number of sweeps to store in circular buffer SERIAL_BUFFER_SIZE = 512 * 1024 -# Log file settings -BIN_INPUT_FILE_PATH = "./vna_system/binary_input/current_input.bin" # Symbolic link to the current log file +# ----------------------------------------------------------------------------- +# Log file settings (binary input path, not to be confused with text logs) +# ----------------------------------------------------------------------------- +BIN_INPUT_FILE_PATH = "./vna_system/binary_input/current_input.bin" # Symlink to current binary input +# ----------------------------------------------------------------------------- # Binary log format constants +# ----------------------------------------------------------------------------- MAGIC = b"VNALOG1\n" DIR_TO_DEV = 0x01 # '>' DIR_FROM_DEV = 0x00 # '<' +# ----------------------------------------------------------------------------- # File I/O settings +# ----------------------------------------------------------------------------- FILE_CHUNK_SIZE = 256 * 1024 SERIAL_PEEK_SIZE = 32 +# ----------------------------------------------------------------------------- # Timeout settings +# ----------------------------------------------------------------------------- SERIAL_IDLE_TIMEOUT = 0.5 SERIAL_DRAIN_DELAY = 0.05 SERIAL_DRAIN_CHECK_DELAY = 0.01 SERIAL_CONNECT_DELAY = 0.01 - -def find_vna_port(): - """ - Automatically find VNA device port. - - Returns: - str: Port path (e.g., '/dev/ttyACM1') or None if not found - """ - logger = logging.getLogger(__name__) - - # Method 1: Use pyserial port detection by VID/PID - try: - ports = list(serial.tools.list_ports.comports()) - - logger.debug(f"Found {len(ports)} serial ports") - - for port in ports: - logger.debug(f"Checking port {port.device}") - - # Check by VID/PID - if port.vid == VNA_VID and port.pid == VNA_PID: - logger.debug(f"Found VNA device by VID/PID at {port.device}") - return port.device - - # Fallback: Check by manufacturer/product strings - if (port.manufacturer and VNA_MANUFACTURER.lower() in port.manufacturer.lower() and - port.description and VNA_PRODUCT.lower() in port.description.lower()): - logger.debug(f"Found VNA device by description at {port.device}") - return port.device - - except Exception as e: - logger.warning(f"Error during VID/PID port detection: {e}") - - # Method 2: Search ttyACM devices (Linux-specific) - try: - acm_ports = glob.glob('/dev/ttyACM*') - logger.debug(f"Found ACM ports: {acm_ports}") - - if acm_ports: - # Sort to get consistent ordering (ttyACM0, ttyACM1, etc.) - acm_ports.sort() - logger.info(f"Using first available ACM port: {acm_ports[0]}") - return acm_ports[0] - - except Exception as e: - logger.warning(f"Error during ACM port detection: {e}") - - # Method 3: Fallback to default - logger.warning(f"VNA device not found, using default port: {DEFAULT_PORT}") - return DEFAULT_PORT - - -def get_vna_port(): - """ - Get VNA port, trying auto-detection first, then falling back to default. - - Returns: - str: Port path to use for VNA connection - """ - logger = logging.getLogger(__name__) - - try: - port = find_vna_port() - if port and port != DEFAULT_PORT: - logger.info(f"Auto-detected VNA port: {port}") - return port - except Exception as e: - logger.error(f"Port detection failed: {e}") - logger.info(f"Using default port: {DEFAULT_PORT}") - return DEFAULT_PORT \ No newline at end of file +PROCESSORS_CONFIG_DIR_PATH = "vna_system/core/processors/configs" \ No newline at end of file diff --git a/vna_system/core/logging/__init__.py b/vna_system/core/logging/__init__.py new file mode 100644 index 0000000..59ebdb9 --- /dev/null +++ b/vna_system/core/logging/__init__.py @@ -0,0 +1,9 @@ +""" +VNA System Logging Module + +Provides centralized, consistent logging across all system components. +""" + +from .logger import get_logger, get_component_logger, setup_logging, VNALogger + +__all__ = ['get_logger', 'get_component_logger', 'setup_logging', 'VNALogger'] \ No newline at end of file diff --git a/vna_system/core/logging/logger.py b/vna_system/core/logging/logger.py new file mode 100644 index 0000000..b40f642 --- /dev/null +++ b/vna_system/core/logging/logger.py @@ -0,0 +1,257 @@ +import logging +import sys +from enum import StrEnum +from pathlib import Path +from datetime import datetime +from typing import Any + + +class LogLevel(StrEnum): + """Log level enumeration with associated prefixes and ANSI colors.""" + DEBUG = "DEBUG" + INFO = "INFO" + WARNING = "WARNING" + ERROR = "ERROR" + CRITICAL = "CRITICAL" + + @property + def prefix(self) -> str: + return { + LogLevel.DEBUG: "DEBUG", + LogLevel.INFO: "INFO", + LogLevel.WARNING: "WARN", + LogLevel.ERROR: "ERROR", + LogLevel.CRITICAL: "FATAL", + }[self] + + @property + def color(self) -> str: + # ANSI colors; disabled if stdout is not a TTY + if not sys.stdout.isatty(): + return "" + return { + LogLevel.DEBUG: "\033[36m", # Cyan + LogLevel.INFO: "\033[32m", # Green + LogLevel.WARNING: "\033[33m", # Yellow + LogLevel.ERROR: "\033[31m", # Red + LogLevel.CRITICAL: "\033[35m", # Magenta + }[self] + + @staticmethod + def reset_color() -> str: + return "" if not sys.stdout.isatty() else "\033[0m" + + +class VNALogger: + """ + Enhanced logger for VNA system with consistent formatting and optional colors. + + Features + -------- + - Consistent color coding across all modules (TTY-aware). + - Component name namespacing (logger name: `vna.`). + - Optional file logging per component. + - Lightweight performance timers. + - Structured metadata via keyword arguments. + """ + + __slots__ = ("component_name", "log_file", "_logger", "_timers") + _loggers: dict[str, "VNALogger"] = {} + _base_config_set = False + + def __init__(self, component_name: str, log_file: Path | None = None) -> None: + self.component_name = component_name + self.log_file = log_file + self._logger = logging.getLogger(f"vna.{component_name}") + self._logger.setLevel(logging.DEBUG) + self._logger.propagate = True # use root handlers configured once + self._timers: dict[str, float] = {} + + if not VNALogger._base_config_set: + self._configure_base_logging() + VNALogger._base_config_set = True + + if self.log_file: + self._add_file_handler(self.log_file) + + # --------------------------------------------------------------------- + # Base configuration (root logger + console format) + # --------------------------------------------------------------------- + def _configure_base_logging(self) -> None: + root = logging.getLogger() + root.setLevel(logging.DEBUG) + + # Remove existing handlers to avoid duplicates on reloads + for h in root.handlers[:]: + root.removeHandler(h) + + console_handler = logging.StreamHandler(sys.stdout) + console_handler.setLevel(logging.DEBUG) + console_handler.setFormatter(self._create_console_formatter()) + root.addHandler(console_handler) + + def _create_console_formatter(self) -> logging.Formatter: + class ColoredFormatter(logging.Formatter): + def format(self, record: logging.LogRecord) -> str: + level = LogLevel(record.levelname) if record.levelname in LogLevel.__members__ else LogLevel.INFO + timestamp = datetime.fromtimestamp(record.created).strftime("%H:%M:%S.%f")[:-3] + component = f"[{record.name.replace('vna.', '')}]" + color = level.color + reset = LogLevel.reset_color() + # Use record.getMessage() to apply %-formatting already handled by logging + return f"{color}{level.prefix} {timestamp} {component:<20} {record.getMessage()}{reset}" + + return ColoredFormatter() + + # --------------------------------------------------------------------- + # File handler + # --------------------------------------------------------------------- + def _add_file_handler(self, path: Path) -> None: + path.parent.mkdir(parents=True, exist_ok=True) + + # Avoid adding duplicate file handlers for the same path + for h in self._logger.handlers: + if isinstance(h, logging.FileHandler) and Path(h.baseFilename) == path: + return + + file_handler = logging.FileHandler(path, encoding="utf-8") + file_handler.setLevel(logging.DEBUG) + file_handler.setFormatter(logging.Formatter("%(asctime)s - %(name)s - %(levelname)s - %(message)s")) + self._logger.addHandler(file_handler) + + # --------------------------------------------------------------------- + # Public logging API + # --------------------------------------------------------------------- + def debug(self, message: str, /, **metadata: Any) -> None: + self._log_with_metadata(logging.DEBUG, message, metadata) + + def info(self, message: str, /, **metadata: Any) -> None: + self._log_with_metadata(logging.INFO, message, metadata) + + def warning(self, message: str, /, **metadata: Any) -> None: + self._log_with_metadata(logging.WARNING, message, metadata) + + def error(self, message: str, /, **metadata: Any) -> None: + self._log_with_metadata(logging.ERROR, message, metadata) + + def critical(self, message: str, /, **metadata: Any) -> None: + self._log_with_metadata(logging.CRITICAL, message, metadata) + + def _log_with_metadata(self, level: int, message: str, metadata: dict[str, Any]) -> None: + if metadata: + # Render key=value; repr() helps keep types unambiguous in logs + meta_str = " ".join(f"{k}={repr(v)}" for k, v in metadata.items()) + self._logger.log(level, f"{message} | {meta_str}") + else: + self._logger.log(level, message) + + # --------------------------------------------------------------------- + # Timers + # --------------------------------------------------------------------- + def timer_start(self, operation: str) -> str: + """ + Start a high-resolution timer for performance measurement. + + Returns + ------- + str + Timer identifier to be passed to `timer_end`. + """ + # perf_counter() is monotonic & high-resolution + timer_id = f"{self.component_name}:{operation}:{datetime.now().timestamp()}" + self._timers[timer_id] = datetime.now().timestamp() + self.debug("Timer started", operation=operation, timer_id=timer_id) + return timer_id + + def timer_end(self, timer_id: str, operation: str | None = None) -> float: + """ + End a timer and log the elapsed time. + + Returns + ------- + float + Elapsed time in milliseconds. Returns 0.0 if timer_id is unknown. + """ + started = self._timers.pop(timer_id, None) + if started is None: + self.warning("Timer not found", timer_id=timer_id) + return 0.0 + + elapsed_ms = (datetime.now().timestamp() - started) * 1000.0 + self.info("Timer completed", operation=operation or "operation", timer_id=timer_id, elapsed_ms=round(elapsed_ms, 2)) + return elapsed_ms + + +def get_logger(component_name: str, log_file: Path | None = None) -> VNALogger: + """ + Get or create a logger instance for a component. + + Examples + -------- + >>> logger = get_logger("magnitude_processor") + >>> logger.info("Processor initialized") + """ + cache_key = f"{component_name}|{log_file}" + logger = VNALogger._loggers.get(cache_key) + if logger is None: + logger = VNALogger(component_name, log_file) + VNALogger._loggers[cache_key] = logger + return logger + + +def get_component_logger(component_path: str) -> VNALogger: + """ + Create a logger with a component name derived from a file path. + + The base name of the file (without extension) is used, with a few + opinionated adjustments for readability. + """ + path = Path(component_path) + component = path.stem + + if "processor" in component and not component.endswith("_processor"): + component = f"{component}_processor" + elif path.parent.name in {"websocket", "acquisition", "settings"}: + component = f"{path.parent.name}_{component}" + + return get_logger(component) + + +def setup_logging(log_level: str = "INFO", log_dir: Path | None = None) -> None: + """ + Configure application-wide logging defaults. + + Parameters + ---------- + log_level: + One of {"DEBUG","INFO","WARNING","ERROR","CRITICAL"} (case-insensitive). + log_dir: + If provided, creates a rotating file per component on demand. + """ + level_name = log_level.upper() + numeric_level = getattr(logging, level_name, None) + if not isinstance(numeric_level, int): + raise ValueError(f"Invalid log level: {log_level}") + + logging.getLogger("vna").setLevel(numeric_level) + + # Add global file handler for all logs if log_dir provided + if log_dir: + log_dir.mkdir(parents=True, exist_ok=True) + global_log_file = log_dir / "vna_all.log" + + root = logging.getLogger() + # Check if file handler already exists + has_file_handler = any(isinstance(h, logging.FileHandler) for h in root.handlers) + if not has_file_handler: + file_handler = logging.FileHandler(global_log_file, encoding="utf-8") + file_handler.setLevel(numeric_level) + file_handler.setFormatter(logging.Formatter( + "%(asctime)s - %(name)s - %(levelname)s - %(message)s" + )) + root.addHandler(file_handler) + + # Touch the app logger (and its file) early to confirm configuration. + log_path = (log_dir / "vna_system.log") if log_dir else None + app_logger = get_logger("vna_system", log_path) + app_logger.info("VNA System logging initialized", log_level=level_name, log_dir=str(log_dir) if log_dir else None) diff --git a/vna_system/core/processors/base_processor.py b/vna_system/core/processors/base_processor.py index b57265b..7a2e9a6 100644 --- a/vna_system/core/processors/base_processor.py +++ b/vna_system/core/processors/base_processor.py @@ -1,190 +1,562 @@ -from abc import ABC, abstractmethod -from typing import Dict, Any, List, Optional -from dataclasses import dataclass -from pathlib import Path -import json -import threading +from dataclasses import dataclass, asdict from datetime import datetime +from pathlib import Path +from typing import Any +import json +import math +import threading + +from vna_system.core.logging.logger import get_component_logger from vna_system.core.settings.preset_manager import ConfigPreset +logger = get_component_logger(__file__) -@dataclass + +# ============================================================================= +# Data models +# ============================================================================= +@dataclass(slots=True) class UIParameter: + """ + Descriptor of a single UI control that also serves as a *schema* for config validation. + + Fields + ------ + name: + Stable key used in configs and payloads. + label: + Human-readable label for the UI. + type: + One of: "slider", "toggle", "select", "input", "button". + value: + Default value (also used to seed a missing config key). + options: + Extra, type-specific metadata used for validation and UI behavior. + + Supported `options` by type + --------------------------- + slider: + {"min": , "max": , "step": , "dtype": "int"|"float"} + Notes: + - dtype defaults to "float". + - step alignment is checked from `min` when provided, otherwise from 0/0.0. + toggle: + {} + select: + {"choices": [, ...]} + Notes: + - `choices` MUST be present and must be a list. + input: + {"type": "int"|"float", "min": , "max": } + Notes: + - Strings are NOT allowed; only numeric input is accepted. + - `type` is required and controls casting/validation. + button: + {"action": ""} + Notes: + - The button value is ignored by validation (buttons are commands, not state). + """ name: str label: str - type: str # 'slider', 'toggle', 'select', 'input', 'button' + type: str value: Any - options: Optional[Dict[str, Any]] = None # min/max for slider, choices for select, etc. + options: dict[str, Any] | None = None -@dataclass +@dataclass(slots=True) class ProcessedResult: + """ + Result payload emitted by processors. + + Fields + ------ + processor_id: + Logical processor identifier. + timestamp: + UNIX timestamp (float) when the result was produced. + data: + Arbitrary computed data (domain-specific). + plotly_config: + Prebuilt Plotly figure/config to render on the client. + ui_parameters: + The UI schema (possibly dynamic) that the client can render. + metadata: + Additional context useful to the UI or debugging (e.g., config snapshot). + """ processor_id: str timestamp: float - data: Dict[str, Any] - plotly_config: Dict[str, Any] - ui_parameters: List[UIParameter] - metadata: Dict[str, Any] + data: dict[str, Any] + plotly_config: dict[str, Any] + ui_parameters: list[UIParameter] + metadata: dict[str, Any] -class BaseProcessor(ABC): - def __init__(self, processor_id: str, config_dir: Path): +# ============================================================================= +# Base processor +# ============================================================================= +class BaseProcessor: + """ + Base class for sweep processors. + + Responsibilities + ---------------- + • Manage a JSON config file (load → validate → save). + • Keep a bounded, thread-safe history of recent sweeps. + • Provide a uniform API for (re)calculation and result packaging. + • Validate config against the UI schema provided by `get_ui_parameters()`. + + Integration contract (to be implemented by subclasses) + ------------------------------------------------------ + - `process_sweep(sweep_data, calibrated_data, vna_config) -> dict[str, Any]` + Perform the actual computation and return a pure-data dict. + - `generate_plotly_config(processed_data, vna_config) -> dict[str, Any]` + Convert computed data to a Plotly config the client can render. + - `get_ui_parameters() -> list[UIParameter]` + Provide the UI schema (and validation rules via `options`) for this processor. + - `_get_default_config() -> dict[str, Any]` + Provide defaults for config keys. Keys should match UIParameter names. + """ + + # --------------------------------------------------------------------- # + # Lifecycle + # --------------------------------------------------------------------- # + def __init__(self, processor_id: str, config_dir: Path) -> None: self.processor_id = processor_id self.config_dir = config_dir self.config_file = config_dir / f"{processor_id}_config.json" - self._lock = threading.RLock() - self._sweep_history: List[Any] = [] - self._max_history = 1 - self._config = {} - self._load_config() + # Concurrency: all shared state guarded by this lock + self._lock = threading.RLock() + + # Bounded history of recent inputs/results (data-only dicts) + self._sweep_history: list[dict[str, Any]] = [] + self._max_history = 1 + + # Current configuration snapshot + self._config: dict[str, Any] = {} + + self._load_config() + logger.debug( + "Processor initialized", + processor_id=self.processor_id, + config_file=str(self.config_file), + ) + + # --------------------------------------------------------------------- # + # History management + # --------------------------------------------------------------------- # @property def max_history(self) -> int: + """Maximum number of history entries retained in memory.""" return self._max_history @max_history.setter - def max_history(self, value: int): + def max_history(self, value: int) -> None: + """Change max history size (min 1) and trim existing history if needed.""" with self._lock: - self._max_history = max(1, value) - self._trim_history() + new_size = max(1, int(value)) + if new_size != self._max_history: + self._max_history = new_size + self._trim_history() + logger.debug( + "Max history updated", + max_history=new_size, + current=len(self._sweep_history), + ) - def _trim_history(self): + def clear_history(self) -> None: + """Drop all stored history entries.""" + with self._lock: + self._sweep_history.clear() + logger.debug("History cleared") + + def _trim_history(self) -> None: + """Internal: keep only the newest `_max_history` items.""" if len(self._sweep_history) > self._max_history: + dropped = len(self._sweep_history) - self._max_history self._sweep_history = self._sweep_history[-self._max_history:] + logger.debug("History trimmed", dropped=dropped, kept=self._max_history) - def _load_config(self): + # --------------------------------------------------------------------- # + # Config I/O and updates + # --------------------------------------------------------------------- # + def _load_config(self) -> None: + """ + Load the JSON config from disk; on failure or first run, use defaults. + + Strategy + -------- + - Read file if present; ensure the root is a dict. + - Shallow-merge with defaults (unknown keys are preserved). + - Validate using UI schema (`_validate_config`). + - On any error, fall back to defaults and save them. + """ + defaults = self._get_default_config() if self.config_file.exists(): try: - with open(self.config_file, 'r') as f: - self._config = json.load(f) + cfg = json.loads(self.config_file.read_text(encoding="utf-8")) + if not isinstance(cfg, dict): + raise ValueError("Config root must be an object") + merged = {**defaults, **cfg} + self._config = merged self._validate_config() - except (json.JSONDecodeError, FileNotFoundError): - self._config = self._get_default_config() - self.save_config() - else: - self._config = self._get_default_config() - self.save_config() + logger.debug("Config loaded", file=str(self.config_file)) + return + except Exception as exc: # noqa: BLE001 + logger.warning( + "Config load failed; using defaults", + error=repr(exc), + file=str(self.config_file), + ) - def save_config(self): + self._config = defaults + self.save_config() + + def save_config(self) -> None: + """ + Save current config to disk atomically. + + Implementation detail + --------------------- + Write to a temporary sidecar file and then replace the target to avoid + partial writes in case of crashes. + """ self.config_dir.mkdir(parents=True, exist_ok=True) - with open(self.config_file, 'w') as f: - json.dump(self._config, f, indent=2) + tmp = self.config_file.with_suffix(".json.tmp") + payload = json.dumps(self._config, indent=2, ensure_ascii=False) + tmp.write_text(payload, encoding="utf-8") + tmp.replace(self.config_file) + logger.debug("Config saved", file=str(self.config_file)) - def update_config(self, updates: Dict[str, Any]): + def update_config(self, updates: dict[str, Any]) -> None: + """ + Update config with user-provided values. + + - Performs type conversion based on current schema (`_convert_config_types`). + - Validates against UI schema; on failure rolls back to the previous state. + - Saves the resulting config when validation passes. + """ with self._lock: - old_config = self._config.copy() - # Convert types based on existing config values - converted_updates = self._convert_config_types(updates) - self._config.update(converted_updates) + before = self._config.copy() + converted = self._convert_config_types(updates) + self._config.update(converted) try: self._validate_config() self.save_config() - except Exception as e: - self._config = old_config - raise ValueError(f"Invalid configuration: {e}") + logger.info("Config updated", updates=converted) + except Exception as exc: # noqa: BLE001 + self._config = before + logger.error("Invalid configuration update; rolled back", error=repr(exc)) + raise ValueError(f"Invalid configuration: {exc}") from exc - def _convert_config_types(self, updates: Dict[str, Any]) -> Dict[str, Any]: - """Convert string values to appropriate types based on existing config""" - converted = {} - - for key, value in updates.items(): - # If the key is not in the current config, keep the value as-is - if key not in self._config: - converted[key] = value - continue - - existing_value = self._config[key] - - # Convert booleans from string - if isinstance(existing_value, bool) and isinstance(value, str): - converted[key] = value.lower() in ('true', '1', 'on', 'yes') - continue - - # Convert numbers from string - if isinstance(existing_value, (int, float)) and isinstance(value, str): - try: - if isinstance(existing_value, int): - # Handle cases like "50.0" → 50 - converted[key] = int(float(value)) - else: - converted[key] = float(value) - except ValueError: - # Keep the original string if conversion fails - converted[key] = value - continue - - # For all other cases, keep the value as-is - converted[key] = value - - return converted - - - def get_config(self) -> Dict[str, Any]: - return self._config.copy() - - def add_sweep_data(self, sweep_data: Any, calibrated_data: Any, vna_config: ConfigPreset | None): + def get_config(self) -> dict[str, Any]: + """Return a shallow copy of the current config snapshot.""" with self._lock: - self._sweep_history.append({ - 'sweep_data': sweep_data, - 'calibrated_data': calibrated_data, - 'vna_config': vna_config.__dict__ if vna_config is not None else {}, - 'timestamp': datetime.now().timestamp() - }) + return self._config.copy() + + def _convert_config_types(self, updates: dict[str, Any]) -> dict[str, Any]: + """ + Convert string inputs into the target types inferred from the current config. + + Rules + ----- + • Booleans: accept case-insensitive {"true","1","on","yes"}. + • Int/float: accept numeric strings; for ints, tolerate "50.0" → 50. + • Unknown keys: kept as-is (subclass validators may use them). + """ + out: dict[str, Any] = {} + for key, value in updates.items(): + if key not in self._config: + out[key] = value + continue + + current = self._config[key] + + # bool + if isinstance(current, bool) and isinstance(value, str): + out[key] = value.strip().lower() in {"true", "1", "on", "yes"} + continue + + # numbers + if isinstance(current, int) and isinstance(value, str): + try: + out[key] = int(float(value)) + continue + except ValueError: + pass + if isinstance(current, float) and isinstance(value, str): + try: + out[key] = float(value) + continue + except ValueError: + pass + + # fallback: unchanged + out[key] = value + return out + + # --------------------------------------------------------------------- # + # Data path: accept new sweep, recompute, produce result + # --------------------------------------------------------------------- # + def add_sweep_data(self, sweep_data: Any, calibrated_data: Any, vna_config: ConfigPreset | None): + """ + Add the latest sweep to the in-memory history and trigger recalculation. + + Parameters + ---------- + sweep_data: + Raw/parsed sweep data as produced by acquisition. + calibrated_data: + Data post-calibration (structure is processor-specific). + vna_config: + Snapshot of VNA settings (dataclass or pydantic model supported). + + Returns + ------- + ProcessedResult | None + The newly computed result or None when history is empty. + """ + with self._lock: + self._sweep_history.append( + { + "sweep_data": sweep_data, + "calibrated_data": calibrated_data, + "vna_config": asdict(vna_config) if vna_config is not None else {}, + "timestamp": datetime.now().timestamp(), + } + ) self._trim_history() return self.recalculate() - def recalculate(self) -> Optional[ProcessedResult]: + def recalculate(self) -> ProcessedResult | None: + """ + Recompute the processor output using the most recent history entry. + + Notes + ----- + Subclasses must ensure `process_sweep` and `generate_plotly_config` + are pure (no global side effects) and thread-safe w.r.t. the provided inputs. + """ with self._lock: if not self._sweep_history: + logger.debug("Recalculate skipped; history empty") return None latest = self._sweep_history[-1] return self._process_data( - latest['sweep_data'], - latest['calibrated_data'], - latest['vna_config'] + latest["sweep_data"], + latest["calibrated_data"], + latest["vna_config"], ) - def _process_data(self, sweep_data: Any, calibrated_data: Any, vna_config: Dict[str, Any]) -> ProcessedResult: - processed_data = self.process_sweep(sweep_data, calibrated_data, vna_config) - plotly_config = self.generate_plotly_config(processed_data, vna_config) - ui_parameters = self.get_ui_parameters() + def _process_data(self, sweep_data: Any, calibrated_data: Any, vna_config: dict[str, Any]) -> ProcessedResult: + """ + Internal: compute processed data, build a Plotly config, and wrap into `ProcessedResult`. + """ + processed = self.process_sweep(sweep_data, calibrated_data, vna_config) + plotly_conf = self.generate_plotly_config(processed, vna_config) + ui_params = self.get_ui_parameters() - return ProcessedResult( + result = ProcessedResult( processor_id=self.processor_id, timestamp=datetime.now().timestamp(), - data=processed_data, - plotly_config=plotly_config, - ui_parameters=ui_parameters, - metadata=self._get_metadata() + data=processed, + plotly_config=plotly_conf, + ui_parameters=ui_params, + metadata=self._get_metadata(), ) + logger.debug("Processed result produced", processor_id=self.processor_id) + return result - @abstractmethod - def process_sweep(self, sweep_data: Any, calibrated_data: Any, vna_config: Dict[str, Any]) -> Dict[str, Any]: - pass + # --------------------------------------------------------------------- # + # Abstracts to implement in concrete processors + # --------------------------------------------------------------------- # + def process_sweep(self, sweep_data: Any, calibrated_data: Any, vna_config: dict[str, Any]) -> dict[str, Any]: + """Compute the processor’s domain result from input sweep data.""" + raise NotImplementedError - @abstractmethod - def generate_plotly_config(self, processed_data: Dict[str, Any], vna_config: Dict[str, Any]) -> Dict[str, Any]: - pass + def generate_plotly_config(self, processed_data: dict[str, Any], vna_config: dict[str, Any]) -> dict[str, Any]: + """Create a ready-to-render Plotly configuration from processed data.""" + raise NotImplementedError - @abstractmethod - def get_ui_parameters(self) -> List[UIParameter]: - pass + def get_ui_parameters(self) -> list[UIParameter]: + """Return the UI schema (used both for UI rendering and config validation).""" + raise NotImplementedError - @abstractmethod - def _get_default_config(self) -> Dict[str, Any]: - pass + def _get_default_config(self) -> dict[str, Any]: + """Provide default config values; keys should match `UIParameter.name`.""" + raise NotImplementedError - @abstractmethod - def _validate_config(self): - pass + # --------------------------------------------------------------------- # + # Validation using UI schema + # --------------------------------------------------------------------- # + def _validate_config(self) -> None: + """ + Validate `self._config` using the schema in `get_ui_parameters()`. - def _get_metadata(self) -> Dict[str, Any]: - return { - 'processor_id': self.processor_id, - 'config': self._config, - 'history_count': len(self._sweep_history), - 'max_history': self._max_history - } \ No newline at end of file + Validation rules + ---------------- + slider: + - dtype: "int"|"float" (default "float") + - min/max: inclusive numeric bounds + - step: if present, enforce alignment from `min` (or 0/0.0) + toggle: + - must be bool + select: + - options must be {"choices": [ ... ]} + - value must be one of `choices` + input: + - options must be {"type": "int"|"float", "min"?, "max"?} + - value must be numeric (no strings) + button: + - options must be {"action": ""} + - value is ignored by validation + + Unknown control types emit a warning but do not block execution. + """ + params = {p.name: p for p in self.get_ui_parameters()} + for name, schema in params.items(): + if name not in self._config: + # Seed missing keys from the UI default to maintain a consistent shape. + self._config[name] = schema.value + logger.debug("Config key missing; seeded from UI default", key=name, value=schema.value) + + value = self._config[name] + ptype = (schema.type or "").lower() + opts = schema.options or {} + + try: + if ptype == "slider": + self._validate_slider(name, value, opts) + elif ptype == "toggle": + self._validate_toggle(name, value) + elif ptype == "select": + self._validate_select_strict(name, value, opts) + elif ptype == "input": + self._validate_input_numeric(name, value, opts) + elif ptype == "button": + self._validate_button_opts(name, opts) + else: + logger.warning("Unknown UI control type; skipping validation", key=name, type=ptype) + except ValueError as exc: + # Prefix the processor id for easier debugging in multi-processor UIs. + raise ValueError(f"[{self.processor_id}] Invalid `{name}`: {exc}") from exc + + # ---- Validators (per control type) ----------------------------------- # + def _validate_slider(self, key: str, value: Any, opts: dict[str, Any]) -> None: + """ + Validate a slider value; normalize to int/float based on `dtype`. + """ + dtype = str(opts.get("dtype", "float")).lower() + min_v = opts.get("min") + max_v = opts.get("max") + step = opts.get("step") + + # Type / casting + if dtype == "int": + if not isinstance(value, int): + if isinstance(value, float) and value.is_integer(): + value = int(value) + else: + raise ValueError(f"expected int, got {type(value).__name__}") + else: + if not isinstance(value, (int, float)): + raise ValueError(f"expected number, got {type(value).__name__}") + value = float(value) + + # Bounds + if min_v is not None and value < min_v: + raise ValueError(f"{value} < min {min_v}") + if max_v is not None and value > max_v: + raise ValueError(f"{value} > max {max_v}") + + # Step alignment + if step is not None: + base = min_v if min_v is not None else (0 if dtype == "int" else 0.0) + if dtype == "int": + if (value - int(base)) % int(step) != 0: + raise ValueError(f"value {value} not aligned to step {step} from base {base}") + else: + steps = (value - float(base)) / float(step) + if not math.isclose(steps, round(steps), rel_tol=1e-9, abs_tol=1e-9): + raise ValueError(f"value {value} not aligned to step {step} from base {base}") + + # Normalize the stored value + self._config[key] = int(value) if dtype == "int" else float(value) + + def _validate_toggle(self, key: str, value: Any) -> None: + """Validate a boolean toggle.""" + if not isinstance(value, bool): + raise ValueError(f"expected bool, got {type(value).__name__}") + + def _validate_select_strict(self, key: str, value: Any, opts: dict[str, Any]) -> None: + """ + Validate a 'select' value against a required list of choices. + """ + if not isinstance(opts, dict) or "choices" not in opts or not isinstance(opts["choices"], list): + raise ValueError("select.options must be a dict with key 'choices' as a list") + choices = opts["choices"] + if value not in choices: + raise ValueError(f"value {value!r} not in choices {choices!r}") + + def _validate_input_numeric(self, key: str, value: Any, opts: dict[str, Any]) -> None: + """ + Validate a numeric input. + + options: + - type: "int" | "float" (required) + - min/max: optional numeric bounds + """ + t = str(opts.get("type", "")).lower() + if t not in {"int", "float"}: + raise ValueError("input.options.type must be 'int' or 'float'") + + if t == "int": + # bool is a subclass of int in Python; explicitly reject it + if isinstance(value, bool) or not isinstance(value, (int, float)): + raise ValueError(f"expected int, got {type(value).__name__}") + if isinstance(value, float) and not value.is_integer(): + raise ValueError(f"expected int, got non-integer float {value}") + iv = int(value) + self._numeric_bounds_check(key, iv, opts) + self._config[key] = iv + else: + if isinstance(value, bool) or not isinstance(value, (int, float)): + raise ValueError(f"expected float, got {type(value).__name__}") + fv = float(value) + self._numeric_bounds_check(key, fv, opts) + self._config[key] = fv + + def _validate_button_opts(self, key: str, opts: dict[str, Any]) -> None: + """ + Validate a button descriptor; buttons are imperative actions, not state. + """ + if not isinstance(opts, dict) or "action" not in opts or not isinstance(opts["action"], str): + raise ValueError("button.options must be a dict with key 'action' (str)") + + @staticmethod + def _numeric_bounds_check(key: str, value: float, opts: dict[str, Any]) -> None: + """Shared numeric bounds check for input/slider.""" + min_v = opts.get("min") + max_v = opts.get("max") + if min_v is not None and value < min_v: + raise ValueError(f"{key} {value} < min {min_v}") + if max_v is not None and value > max_v: + raise ValueError(f"{key} {value} > max {max_v}") + + # --------------------------------------------------------------------- # + # Utilities + # --------------------------------------------------------------------- # + def _get_metadata(self) -> dict[str, Any]: + """ + Return diagnostic metadata bundled with each `ProcessedResult`. + """ + with self._lock: + return { + "processor_id": self.processor_id, + "config": self._config.copy(), + "history_count": len(self._sweep_history), + "max_history": self._max_history, + } \ No newline at end of file diff --git a/vna_system/core/processors/calibration_processor.py b/vna_system/core/processors/calibration_processor.py index 92844a2..999aaf3 100644 --- a/vna_system/core/processors/calibration_processor.py +++ b/vna_system/core/processors/calibration_processor.py @@ -1,134 +1,136 @@ -""" -Calibration Processor Module - -Applies VNA calibrations to sweep data using stored calibration standards. -Supports both S11 and S21 measurement modes with appropriate correction algorithms. -""" - import numpy as np -from typing import List, Tuple -from ..acquisition.sweep_buffer import SweepData -from ..settings.preset_manager import VNAMode -from ..settings.calibration_manager import CalibrationSet, CalibrationStandard +from vna_system.core.logging.logger import get_component_logger +from vna_system.core.acquisition.sweep_buffer import SweepData +from vna_system.core.settings.preset_manager import VNAMode +from vna_system.core.settings.calibration_manager import CalibrationSet, CalibrationStandard + +logger = get_component_logger(__file__) class CalibrationProcessor: """ - Processes sweep data by applying VNA calibrations. + Apply VNA calibration to raw sweeps. - For S11 mode: Uses OSL (Open-Short-Load) calibration - For S21 mode: Uses Through calibration + Supports: + - S11 (reflection) using OSL (Open–Short–Load) error model + - S21 (transmission) using THRU reference + + All operations are vectorized with NumPy and return data as a list of (real, imag) tuples. """ - def __init__(self): - pass - - def apply_calibration(self, sweep_data: SweepData, calibration_set: CalibrationSet) -> List[Tuple[float, float]]: + def apply_calibration(self, sweep_data: SweepData, calibration_set: CalibrationSet) -> list[tuple[float, float]]: """ - Apply calibration to sweep data and return corrected complex data as list of (real, imag) tuples. + Calibrate a sweep and return corrected complex points. - Args: - sweep_data: Raw sweep data from VNA - calibration_set: Calibration standards data + Parameters + ---------- + sweep_data + Raw sweep as (real, imag) tuples with metadata. + calibration_set + A complete set of standards for the current VNA mode. - Returns: - List of (real, imag) tuples with calibration applied + Returns + ------- + list[tuple[float, float]] + Calibrated complex points as (real, imag) pairs. - Raises: - ValueError: If calibration is incomplete or mode not supported + Raises + ------ + ValueError + If the calibration set is incomplete or the VNA mode is unsupported. """ if not calibration_set.is_complete(): raise ValueError("Calibration set is incomplete") - # Convert sweep data to complex array - raw_signal = self._sweep_to_complex_array(sweep_data) + raw = self._to_complex_array(sweep_data) - # Apply calibration based on measurement mode if calibration_set.preset.mode == VNAMode.S21: - calibrated_array = self._apply_s21_calibration(raw_signal, calibration_set) + logger.debug("Applying S21 calibration", sweep_number=sweep_data.sweep_number, points=sweep_data.total_points) + calibrated = self._apply_s21(raw, calibration_set) elif calibration_set.preset.mode == VNAMode.S11: - calibrated_array = self._apply_s11_calibration(raw_signal, calibration_set) + logger.debug("Applying S11 calibration (OSL)", sweep_number=sweep_data.sweep_number, points=sweep_data.total_points) + calibrated = self._apply_s11_osl(raw, calibration_set) else: raise ValueError(f"Unsupported measurement mode: {calibration_set.preset.mode}") - # Convert back to list of (real, imag) tuples - return [(complex_val.real, complex_val.imag) for complex_val in calibrated_array] + return [(z.real, z.imag) for z in calibrated] - def _sweep_to_complex_array(self, sweep_data: SweepData) -> np.ndarray: - """Convert SweepData to complex numpy array.""" - complex_data = [] - for real, imag in sweep_data.points: - complex_data.append(complex(real, imag)) - return np.array(complex_data) + # --------------------------------------------------------------------- # + # Helpers + # --------------------------------------------------------------------- # + @staticmethod + def _to_complex_array(sweep: SweepData) -> np.ndarray: + """Convert `SweepData.points` to a 1-D complex NumPy array.""" + # Using vectorized construction for speed and clarity + if not sweep.points: + return np.empty(0, dtype=np.complex64) + arr = np.asarray(sweep.points, dtype=np.float32) + return arr[:, 0].astype(np.float32) + 1j * arr[:, 1].astype(np.float32) - def _apply_s21_calibration(self, raw_signal: np.ndarray, calibration_set: CalibrationSet) -> np.ndarray: + @staticmethod + def _safe_divide(num: np.ndarray, den: np.ndarray, eps: float = 1e-12) -> np.ndarray: """ - Apply S21 (transmission) calibration using through standard. + Elementwise complex-safe division with small epsilon guard. - Calibrated_S21 = Raw_Signal / Through_Reference + Avoids division by zero by clamping |den| np.ndarray: + # --------------------------------------------------------------------- # + # S21 calibration (THRU) + # --------------------------------------------------------------------- # + def _apply_s21(self, raw: np.ndarray, calib: CalibrationSet) -> np.ndarray: """ - Apply S11 (reflection) calibration using OSL (Open-Short-Load) method. + S21: normalize the DUT response by the THRU reference. - This implements the standard OSL error correction: - - Ed (Directivity): Load standard - - Es (Source Match): Calculated from Open, Short, Load - - Er (Reflection Tracking): Calculated from Open, Short, Load - - Final correction: S11 = (Raw - Ed) / (Er + Es * (Raw - Ed)) + Calibrated = Raw / Through """ + through = self._to_complex_array(calib.standards[CalibrationStandard.THROUGH]) + if raw.size != through.size: + raise ValueError("Signal and THRU reference have different lengths") + return self._safe_divide(raw, through) - # Get calibration standards - open_sweep = calibration_set.standards[CalibrationStandard.OPEN] - short_sweep = calibration_set.standards[CalibrationStandard.SHORT] - load_sweep = calibration_set.standards[CalibrationStandard.LOAD] + # --------------------------------------------------------------------- # + # S11 calibration (OSL) + # --------------------------------------------------------------------- # + def _apply_s11_osl(self, raw: np.ndarray, calib: CalibrationSet) -> np.ndarray: + """ + S11 OSL correction using a 3-term error model. - # Convert to complex arrays - open_cal = self._sweep_to_complex_array(open_sweep) - short_cal = self._sweep_to_complex_array(short_sweep) - load_cal = self._sweep_to_complex_array(load_sweep) + Error terms + ----------- + Ed (directivity) := Load + Es (source match) := (Open + Short - 2*Load) / (Open - Short) + Er (reflection tracking) := -2*(Open - Load)*(Short - Load) / (Open - Short) - # Validate array sizes - if not (len(raw_signal) == len(open_cal) == len(short_cal) == len(load_cal)): - raise ValueError("Signal and calibration data have different lengths") + Final correction + ---------------- + S11 = (Raw - Ed) / (Er + Es * (Raw - Ed)) + """ + open_ref = self._to_complex_array(calib.standards[CalibrationStandard.OPEN]) + short_ref = self._to_complex_array(calib.standards[CalibrationStandard.SHORT]) + load_ref = self._to_complex_array(calib.standards[CalibrationStandard.LOAD]) - # Calculate error terms - directivity = load_cal.copy() # Ed = Load + n = raw.size + if not (open_ref.size == short_ref.size == load_ref.size == n): + raise ValueError("Signal and OSL standards have different lengths") - # Source match: Es = (Open + Short - 2*Load) / (Open - Short) - denominator = open_cal - short_cal - denominator = np.where(np.abs(denominator) < 1e-12, 1e-12, denominator) - source_match = (open_cal + short_cal - 2 * load_cal) / denominator + # Ed + ed = load_ref - # Reflection tracking: Er = -2 * (Open - Load) * (Short - Load) / (Open - Short) - reflection_tracking = -2 * (open_cal - load_cal) * (short_cal - load_cal) / denominator + # Es, Er with guarded denominators + denom = open_ref - short_ref + denom = np.where(np.abs(denom) < 1e-12, 1e-12 * np.exp(1j * np.angle(denom)), denom) - # Apply OSL correction - corrected_numerator = raw_signal - directivity - corrected_denominator = reflection_tracking + source_match * corrected_numerator + es = (open_ref + short_ref - 2.0 * load_ref) / denom + er = -2.0 * (open_ref - load_ref) * (short_ref - load_ref) / denom - # Avoid division by zero - corrected_denominator = np.where(np.abs(corrected_denominator) < 1e-12, 1e-12, corrected_denominator) - - calibrated_signal = corrected_numerator / corrected_denominator - - return calibrated_signal \ No newline at end of file + num = raw - ed + den = er + es * num + return self._safe_divide(num, den) diff --git a/vna_system/core/processors/configs/magnitude_config.json b/vna_system/core/processors/configs/magnitude_config.json index 2abb7ef..e8723a6 100644 --- a/vna_system/core/processors/configs/magnitude_config.json +++ b/vna_system/core/processors/configs/magnitude_config.json @@ -1,9 +1,10 @@ { - "y_min": -80, - "y_max": 15, + "y_min": -60, + "y_max": 20, "smoothing_enabled": false, "smoothing_window": 5, - "marker_enabled": true, - "marker_frequency": 100000009, - "grid_enabled": true + "marker_enabled": false, + "marker_frequency": 100000009.0, + "grid_enabled": false, + "reset_smoothing": false } \ No newline at end of file diff --git a/vna_system/core/processors/configs/phase_config.json b/vna_system/core/processors/configs/phase_config.json index 8dc6f71..a694a77 100644 --- a/vna_system/core/processors/configs/phase_config.json +++ b/vna_system/core/processors/configs/phase_config.json @@ -1,12 +1,12 @@ { - "y_min": -210, + "y_min": -360, "y_max": 360, "unwrap_phase": false, "phase_offset": 0, - "smoothing_enabled": true, + "smoothing_enabled": false, "smoothing_window": 5, - "marker_enabled": false, - "marker_frequency": "asdasd", + "marker_enabled": true, + "marker_frequency": 8000000000.0, "reference_line_enabled": false, "reference_phase": 0, "grid_enabled": true diff --git a/vna_system/core/processors/implementations/magnitude_processor.py b/vna_system/core/processors/implementations/magnitude_processor.py index 2078c39..52077f0 100644 --- a/vna_system/core/processors/implementations/magnitude_processor.py +++ b/vna_system/core/processors/implementations/magnitude_processor.py @@ -1,221 +1,293 @@ import numpy as np -from typing import Dict, Any, List from pathlib import Path +from typing import Any -from ..base_processor import BaseProcessor, UIParameter +from vna_system.core.logging.logger import get_component_logger +from vna_system.core.processors.base_processor import BaseProcessor, UIParameter + +logger = get_component_logger(__file__) class MagnitudeProcessor(BaseProcessor): - def __init__(self, config_dir: Path): + """ + Compute and visualize magnitude (in dB) over frequency from calibrated sweep data. + + Pipeline + -------- + 1) Derive frequency axis from VNA config (start/stop, N points). + 2) Compute |S| in dB per point (20*log10(|complex|), clamped for |complex|==0). + 3) Optionally smooth using moving-average (odd window). + 4) Provide Plotly configuration including an optional marker. + + Notes + ----- + - `calibrated_data` is expected to be a `SweepData` with `.points: list[tuple[float,float]]`. + - Marker frequency is validated by BaseProcessor via `UIParameter(options=...)`. + """ + + def __init__(self, config_dir: Path) -> None: super().__init__("magnitude", config_dir) - # State for smoothing that can be reset by button - self._smoothing_history = [] + # Internal state that can be reset via a UI "button" + self._smoothing_history: list[float] = [] - def process_sweep(self, sweep_data: Any, calibrated_data: Any, vna_config: Dict[str, Any]) -> Dict[str, Any]: - if not calibrated_data or not hasattr(calibrated_data, 'points'): - return {'error': 'No calibrated data available'} + # ------------------------------------------------------------------ # + # Core processing + # ------------------------------------------------------------------ # + def process_sweep(self, sweep_data: Any, calibrated_data: Any, vna_config: dict[str, Any]) -> dict[str, Any]: + """ + Produce magnitude trace (dB) and ancillary info from a calibrated sweep. - frequencies = [] - magnitudes_db = [] - - for i, (real, imag) in enumerate(calibrated_data.points): - complex_val = complex(real, imag) - magnitude_db = 20 * np.log10(abs(complex_val)) if abs(complex_val) > 0 else -120 - - # Calculate frequency based on VNA config - start_freq = vna_config.get('start_frequency', 100e6) - stop_freq = vna_config.get('stop_frequency', 8.8e9) - total_points = len(calibrated_data.points) - frequency = start_freq + (stop_freq - start_freq) * i / (total_points - 1) - - frequencies.append(frequency) - magnitudes_db.append(magnitude_db) - - # Apply smoothing if enabled - if self._config.get('smoothing_enabled', False): - window_size = self._config.get('smoothing_window', 5) - magnitudes_db = self._apply_moving_average(magnitudes_db, window_size) - - return { - 'frequencies': frequencies, - 'magnitudes_db': magnitudes_db, - 'y_min': self._config.get('y_min', -80), - 'y_max': self._config.get('y_max', 10), - 'marker_enabled': self._config.get('marker_enabled', True), - 'marker_frequency': self._config.get('marker_frequency', frequencies[len(frequencies)//2] if frequencies else 1e9), - 'grid_enabled': self._config.get('grid_enabled', True) - } - - def generate_plotly_config(self, processed_data: Dict[str, Any], vna_config: Dict[str, Any]) -> Dict[str, Any]: - if 'error' in processed_data: - return {'error': processed_data['error']} - - frequencies = processed_data['frequencies'] - magnitudes_db = processed_data['magnitudes_db'] - - # Find marker point - marker_freq = processed_data['marker_frequency'] - marker_idx = min(range(len(frequencies)), key=lambda i: abs(frequencies[i] - marker_freq)) - marker_mag = magnitudes_db[marker_idx] - - traces = [{ - 'x': [f / 1e9 for f in frequencies], # Convert to GHz - 'y': magnitudes_db, - 'type': 'scatter', - 'mode': 'lines', - 'name': 'S11 Magnitude', - 'line': {'color': 'blue', 'width': 2} - }] - - # Add marker if enabled - if processed_data['marker_enabled']: - traces.append({ - 'x': [frequencies[marker_idx] / 1e9], - 'y': [marker_mag], - 'type': 'scatter', - 'mode': 'markers', - 'name': f'Marker: {frequencies[marker_idx]/1e9:.3f} GHz, {marker_mag:.2f} dB', - 'marker': {'color': 'red', 'size': 8, 'symbol': 'circle'} - }) - - return { - 'data': traces, - 'layout': { - 'title': 'S11 Magnitude Response', - 'xaxis': { - 'title': 'Frequency (GHz)', - 'showgrid': processed_data['grid_enabled'] - }, - 'yaxis': { - 'title': 'Magnitude (dB)', - 'range': [processed_data['y_min'], processed_data['y_max']], - 'showgrid': processed_data['grid_enabled'] - }, - 'hovermode': 'x unified', - 'showlegend': True + Returns + ------- + dict[str, Any] + { + 'frequencies': list[float], + 'magnitudes_db': list[float], + 'y_min': float, + 'y_max': float, + 'marker_enabled': bool, + 'marker_frequency': float, + 'grid_enabled': bool } - } + """ + if not calibrated_data or not hasattr(calibrated_data, "points"): + logger.warning("No calibrated data available for magnitude processing") + return {"error": "No calibrated data available"} - def get_ui_parameters(self) -> List[UIParameter]: + points: list[tuple[float, float]] = calibrated_data.points # list of (real, imag) + n = len(points) + if n == 0: + logger.warning("Calibrated sweep contains zero points") + return {"error": "Empty calibrated sweep"} + + # Frequency axis from VNA config (defaults if not provided) + start_freq = float(vna_config.get("start_frequency", 100e6)) + stop_freq = float(vna_config.get("stop_frequency", 8.8e9)) + + if n == 1: + freqs = [start_freq] + else: + step = (stop_freq - start_freq) / (n - 1) + freqs = [start_freq + i * step for i in range(n)] + + # Magnitude in dB (clamp zero magnitude to -120 dB) + mags_db: list[float] = [] + for real, imag in points: + mag = abs(complex(real, imag)) + mags_db.append(20.0 * np.log10(mag) if mag > 0.0 else -120.0) + + # Optional smoothing + if self._config.get("smoothing_enabled", False): + window = int(self._config.get("smoothing_window", 5)) + mags_db = self._apply_moving_average(mags_db, window) + + result = { + "frequencies": freqs, + "magnitudes_db": mags_db, + "y_min": float(self._config.get("y_min", -80)), + "y_max": float(self._config.get("y_max", 10)), + "marker_enabled": bool(self._config.get("marker_enabled", True)), + "marker_frequency": float( + self._config.get("marker_frequency", freqs[len(freqs) // 2] if freqs else 1e9) + ), + "grid_enabled": bool(self._config.get("grid_enabled", True)), + } + logger.debug("Magnitude sweep processed", points=n) + return result + + def generate_plotly_config(self, processed_data: dict[str, Any], vna_config: dict[str, Any]) -> dict[str, Any]: + """ + Build a Plotly figure config for the magnitude trace and optional marker. + """ + if "error" in processed_data: + return {"error": processed_data["error"]} + + freqs: list[float] = processed_data["frequencies"] + mags_db: list[float] = processed_data["magnitudes_db"] + grid_enabled: bool = processed_data["grid_enabled"] + + # Marker resolution + marker_freq: float = processed_data["marker_frequency"] + if freqs: + idx = min(range(len(freqs)), key=lambda i: abs(freqs[i] - marker_freq)) + marker_mag = mags_db[idx] + marker_x = freqs[idx] / 1e9 + marker_trace = { + "x": [marker_x], + "y": [marker_mag], + "type": "scatter", + "mode": "markers", + "name": f"Marker: {freqs[idx]/1e9:.3f} GHz, {marker_mag:.2f} dB", + "marker": {"color": "red", "size": 8, "symbol": "circle"}, + } + else: + idx = 0 + marker_trace = None + + traces = [ + { + "x": [f / 1e9 for f in freqs], # Hz -> GHz + "y": mags_db, + "type": "scatter", + "mode": "lines", + "name": "Magnitude", + "line": {"color": "blue", "width": 2}, + } + ] + if processed_data["marker_enabled"] and marker_trace: + traces.append(marker_trace) + + fig = { + "data": traces, + "layout": { + "title": "Magnitude Response", + "xaxis": {"title": "Frequency (GHz)", "showgrid": grid_enabled}, + "yaxis": { + "title": "Magnitude (dB)", + "range": [processed_data["y_min"], processed_data["y_max"]], + "showgrid": grid_enabled, + }, + "hovermode": "x unified", + "showlegend": True, + }, + } + return fig + + # ------------------------------------------------------------------ # + # UI schema + # ------------------------------------------------------------------ # + def get_ui_parameters(self) -> list[UIParameter]: + """ + UI/validation schema. + + Conforms to BaseProcessor rules: + - slider: requires dtype + min/max/step alignment checks + - toggle: bool only + - input: numeric only, with {"type": "int"|"float", "min"?, "max"?} + - button: {"action": "..."}; value ignored by validation + """ return [ UIParameter( - name='y_min', - label='Y Axis Min (dB)', - type='slider', - value=self._config.get('y_min', -80), - options={'min': -120, 'max': 0, 'step': 5} + name="y_min", + label="Y Axis Min (dB)", + type="slider", + value=self._config.get("y_min", -80), + options={"min": -120, "max": 0, "step": 5, "dtype": "int"}, ), UIParameter( - name='y_max', - label='Y Axis Max (dB)', - type='slider', - value=self._config.get('y_max', 10), - options={'min': -20, 'max': 20, 'step': 5} + name="y_max", + label="Y Axis Max (dB)", + type="slider", + value=self._config.get("y_max", 10), + options={"min": -20, "max": 20, "step": 5, "dtype": "int"}, ), UIParameter( - name='smoothing_enabled', - label='Enable Smoothing', - type='toggle', - value=self._config.get('smoothing_enabled', False) + name="smoothing_enabled", + label="Enable Smoothing", + type="toggle", + value=self._config.get("smoothing_enabled", False), + options={}, ), UIParameter( - name='smoothing_window', - label='Smoothing Window Size', - type='slider', - value=self._config.get('smoothing_window', 5), - options={'min': 3, 'max': 21, 'step': 2} + name="smoothing_window", + label="Smoothing Window Size", + type="slider", + value=self._config.get("smoothing_window", 5), + options={"min": 3, "max": 21, "step": 2, "dtype": "int"}, ), UIParameter( - name='marker_enabled', - label='Show Marker', - type='toggle', - value=self._config.get('marker_enabled', True) + name="marker_enabled", + label="Show Marker", + type="toggle", + value=self._config.get("marker_enabled", True), + options={}, ), UIParameter( - name='marker_frequency', - label='Marker Frequency (Hz)', - type='input', - value=self._config.get('marker_frequency', 1e9), - options={'type': 'number', 'min': 100e6, 'max': 8.8e9} + name="marker_frequency", + label="Marker Frequency (Hz)", + type="input", + value=self._config.get("marker_frequency", 1e9), + options={"type": "float", "min": 100e6, "max": 8.8e9}, ), UIParameter( - name='grid_enabled', - label='Show Grid', - type='toggle', - value=self._config.get('grid_enabled', True) + name="grid_enabled", + label="Show Grid", + type="toggle", + value=self._config.get("grid_enabled", True), + options={}, ), UIParameter( - name='reset_smoothing', - label='Reset Smoothing', - type='button', - value=False, # Always False for buttons, will be set to True temporarily when clicked - options={'action': 'Reset the smoothing filter state'} - ) + name="reset_smoothing", + label="Reset Smoothing", + type="button", + value=False, # buttons carry no state; ignored by validator + options={"action": "Reset the smoothing filter state"}, + ), ] - def _get_default_config(self) -> Dict[str, Any]: + def _get_default_config(self) -> dict[str, Any]: + """Defaults that align with the UI schema above.""" return { - 'y_min': -80, - 'y_max': 10, - 'smoothing_enabled': False, - 'smoothing_window': 5, - 'marker_enabled': True, - 'marker_frequency': 1e9, - 'grid_enabled': True + "y_min": -80, + "y_max": 10, + "smoothing_enabled": False, + "smoothing_window": 5, + "marker_enabled": True, + "marker_frequency": 1e9, + "grid_enabled": True, } - def update_config(self, updates: Dict[str, Any]): - print(f"🔧 update_config called with: {updates}") - # Handle button parameters specially - button_actions = {} - config_updates = {} + # ------------------------------------------------------------------ # + # Config updates & actions + # ------------------------------------------------------------------ # + def update_config(self, updates: dict[str, Any]) -> None: + """ + Apply config updates; handle UI buttons out-of-band. + + Any key that corresponds to a button triggers an action when True and + is *not* persisted in the config. Other keys are forwarded to the + BaseProcessor (with type conversion + validation). + """ + ui_params = {param.name: param for param in self.get_ui_parameters()} + button_actions: dict[str, bool] = {} + config_updates: dict[str, Any] = {} for key, value in updates.items(): - # Check if this is a button parameter - ui_params = {param.name: param for param in self.get_ui_parameters()} - if key in ui_params and ui_params[key].type == 'button': - if value: # Button was clicked - button_actions[key] = value - # Don't add button values to config + schema = ui_params.get(key) + if schema and schema.type == "button": + if value: + button_actions[key] = True else: config_updates[key] = value - # Update config with non-button parameters if config_updates: super().update_config(config_updates) - # Handle button actions - for action, pressed in button_actions.items(): - if pressed and action == 'reset_smoothing': - # Reset smoothing state (could be a counter, filter state, etc.) - self._smoothing_history = [] # Reset any internal smoothing state - print(f"🔄 Smoothing state reset by button action") - # Note: recalculate() will be called automatically by the processing system + # Execute button actions + if button_actions.get("reset_smoothing"): + self._smoothing_history.clear() + logger.info("Smoothing state reset via UI button") - def _validate_config(self): - required_keys = ['y_min', 'y_max', 'smoothing_enabled', 'smoothing_window', - 'marker_enabled', 'marker_frequency', 'grid_enabled'] + # ------------------------------------------------------------------ # + # Smoothing + # ------------------------------------------------------------------ # + @staticmethod + def _apply_moving_average(data: list[float], window_size: int) -> list[float]: + """ + Centered moving average with clamped edges. - for key in required_keys: - if key not in self._config: - raise ValueError(f"Missing required config key: {key}") - - if self._config['y_min'] >= self._config['y_max']: - raise ValueError("y_min must be less than y_max") - - if self._config['smoothing_window'] < 3 or self._config['smoothing_window'] % 2 == 0: - raise ValueError("smoothing_window must be odd and >= 3") - - def _apply_moving_average(self, data: List[float], window_size: int) -> List[float]: - if window_size >= len(data): + Requirements + ------------ + - window_size must be odd and >= 3 (enforced by UI schema). + """ + n = len(data) + if n == 0 or window_size <= 1 or window_size >= n: return data - smoothed = [] - half_window = window_size // 2 - - for i in range(len(data)): - start_idx = max(0, i - half_window) - end_idx = min(len(data), i + half_window + 1) - smoothed.append(sum(data[start_idx:end_idx]) / (end_idx - start_idx)) - - return smoothed \ No newline at end of file + half = window_size // 2 + out: list[float] = [] + for i in range(n): + lo = max(0, i - half) + hi = min(n, i + half + 1) + out.append(sum(data[lo:hi]) / (hi - lo)) + return out diff --git a/vna_system/core/processors/implementations/phase_processor.py b/vna_system/core/processors/implementations/phase_processor.py index b80e1a8..b879710 100644 --- a/vna_system/core/processors/implementations/phase_processor.py +++ b/vna_system/core/processors/implementations/phase_processor.py @@ -1,242 +1,307 @@ import numpy as np -from typing import Dict, Any, List from pathlib import Path +from typing import Any -from ..base_processor import BaseProcessor, UIParameter +from vna_system.core.logging.logger import get_component_logger +from vna_system.core.processors.base_processor import BaseProcessor, UIParameter + +logger = get_component_logger(__file__) class PhaseProcessor(BaseProcessor): - def __init__(self, config_dir: Path): + """ + Compute and visualize phase (degrees) over frequency from calibrated sweep data. + + Pipeline + -------- + 1) Derive frequency axis from VNA config (start/stop, N points). + 2) Compute phase in degrees from complex samples. + 3) Optional simple unwrapping (+/-180° jumps) and offset. + 4) Optional moving-average smoothing. + 5) Provide Plotly configuration including an optional marker and reference line. + """ + + def __init__(self, config_dir: Path) -> None: super().__init__("phase", config_dir) - def process_sweep(self, sweep_data: Any, calibrated_data: Any, vna_config: Dict[str, Any]) -> Dict[str, Any]: - if not calibrated_data or not hasattr(calibrated_data, 'points'): - return {'error': 'No calibrated data available'} + # ------------------------------------------------------------------ # + # Core processing + # ------------------------------------------------------------------ # + def process_sweep(self, sweep_data: Any, calibrated_data: Any, vna_config: dict[str, Any]) -> dict[str, Any]: + """ + Produce phase trace (degrees) and ancillary info from a calibrated sweep. - frequencies = [] - phases_deg = [] - - for i, (real, imag) in enumerate(calibrated_data.points): - complex_val = complex(real, imag) - phase_rad = np.angle(complex_val) - phase_deg = np.degrees(phase_rad) - - # Phase unwrapping if enabled - if self._config.get('unwrap_phase', True) and i > 0: - phase_diff = phase_deg - phases_deg[-1] - if phase_diff > 180: - phase_deg -= 360 - elif phase_diff < -180: - phase_deg += 360 - - # Calculate frequency - start_freq = vna_config.get('start_frequency', 100e6) - stop_freq = vna_config.get('stop_frequency', 8.8e9) - total_points = len(calibrated_data.points) - frequency = start_freq + (stop_freq - start_freq) * i / (total_points - 1) - - frequencies.append(frequency) - phases_deg.append(phase_deg) - - # Apply offset if configured - phase_offset = self._config.get('phase_offset', 0) - if phase_offset != 0: - phases_deg = [phase + phase_offset for phase in phases_deg] - - # Apply smoothing if enabled - if self._config.get('smoothing_enabled', False): - window_size = self._config.get('smoothing_window', 5) - phases_deg = self._apply_moving_average(phases_deg, window_size) - - return { - 'frequencies': frequencies, - 'phases_deg': phases_deg, - 'y_min': self._config.get('y_min', -180), - 'y_max': self._config.get('y_max', 180), - 'marker_enabled': self._config.get('marker_enabled', True), - 'marker_frequency': self._config.get('marker_frequency', frequencies[len(frequencies)//2] if frequencies else 1e9), - 'grid_enabled': self._config.get('grid_enabled', True), - 'reference_line_enabled': self._config.get('reference_line_enabled', False), - 'reference_phase': self._config.get('reference_phase', 0) - } - - def generate_plotly_config(self, processed_data: Dict[str, Any], vna_config: Dict[str, Any]) -> Dict[str, Any]: - if 'error' in processed_data: - return {'error': processed_data['error']} - - frequencies = processed_data['frequencies'] - phases_deg = processed_data['phases_deg'] - - # Find marker point - marker_freq = processed_data['marker_frequency'] - marker_idx = min(range(len(frequencies)), key=lambda i: abs(frequencies[i] - marker_freq)) - marker_phase = phases_deg[marker_idx] - - traces = [{ - 'x': [f / 1e9 for f in frequencies], # Convert to GHz - 'y': phases_deg, - 'type': 'scatter', - 'mode': 'lines', - 'name': 'S11 Phase', - 'line': {'color': 'green', 'width': 2} - }] - - # Add marker if enabled - if processed_data['marker_enabled']: - traces.append({ - 'x': [frequencies[marker_idx] / 1e9], - 'y': [marker_phase], - 'type': 'scatter', - 'mode': 'markers', - 'name': f'Marker: {frequencies[marker_idx]/1e9:.3f} GHz, {marker_phase:.1f}°', - 'marker': {'color': 'red', 'size': 8, 'symbol': 'circle'} - }) - - # Add reference line if enabled - if processed_data['reference_line_enabled']: - traces.append({ - 'x': [frequencies[0] / 1e9, frequencies[-1] / 1e9], - 'y': [processed_data['reference_phase'], processed_data['reference_phase']], - 'type': 'scatter', - 'mode': 'lines', - 'name': f'Reference: {processed_data["reference_phase"]:.1f}°', - 'line': {'color': 'gray', 'width': 1, 'dash': 'dash'} - }) - - return { - 'data': traces, - 'layout': { - 'title': 'S11 Phase Response', - 'xaxis': { - 'title': 'Frequency (GHz)', - 'showgrid': processed_data['grid_enabled'] - }, - 'yaxis': { - 'title': 'Phase (degrees)', - 'range': [processed_data['y_min'], processed_data['y_max']], - 'showgrid': processed_data['grid_enabled'] - }, - 'hovermode': 'x unified', - 'showlegend': True + Returns + ------- + dict[str, Any] + { + 'frequencies': list[float], + 'phases_deg': list[float], + 'y_min': float, + 'y_max': float, + 'marker_enabled': bool, + 'marker_frequency': float, + 'grid_enabled': bool, + 'reference_line_enabled': bool, + 'reference_phase': float } - } + """ + if not calibrated_data or not hasattr(calibrated_data, "points"): + logger.warning("No calibrated data available for phase processing") + return {"error": "No calibrated data available"} - def get_ui_parameters(self) -> List[UIParameter]: + points: list[tuple[float, float]] = calibrated_data.points + n = len(points) + if n == 0: + logger.warning("Calibrated sweep contains zero points") + return {"error": "Empty calibrated sweep"} + + # Frequency axis from VNA config (defaults if not provided) + start_freq = float(vna_config.get("start_frequency", 100e6)) + stop_freq = float(vna_config.get("stop_frequency", 8.8e9)) + + if n == 1: + freqs = [start_freq] + else: + step = (stop_freq - start_freq) / (n - 1) + freqs = [start_freq + i * step for i in range(n)] + + # Phase in degrees + phases_deg: list[float] = [] + unwrap = bool(self._config.get("unwrap_phase", True)) + + for i, (real, imag) in enumerate(points): + z = complex(real, imag) + deg = float(np.degrees(np.angle(z))) + + if unwrap and phases_deg: + diff = deg - phases_deg[-1] + if diff > 180.0: + deg -= 360.0 + elif diff < -180.0: + deg += 360.0 + + phases_deg.append(deg) + + # Offset + phase_offset = float(self._config.get("phase_offset", 0.0)) + if phase_offset: + phases_deg = [p + phase_offset for p in phases_deg] + + # Optional smoothing + if self._config.get("smoothing_enabled", False): + window = int(self._config.get("smoothing_window", 5)) + phases_deg = self._apply_moving_average(phases_deg, window) + + result = { + "frequencies": freqs, + "phases_deg": phases_deg, + "y_min": float(self._config.get("y_min", -180)), + "y_max": float(self._config.get("y_max", 180)), + "marker_enabled": bool(self._config.get("marker_enabled", True)), + "marker_frequency": float( + self._config.get("marker_frequency", freqs[len(freqs) // 2] if freqs else 1e9) + ), + "grid_enabled": bool(self._config.get("grid_enabled", True)), + "reference_line_enabled": bool(self._config.get("reference_line_enabled", False)), + "reference_phase": float(self._config.get("reference_phase", 0)), + } + logger.debug("Phase sweep processed", points=n) + return result + + def generate_plotly_config(self, processed_data: dict[str, Any], vna_config: dict[str, Any]) -> dict[str, Any]: + """ + Build a Plotly figure config for the phase trace, marker, and optional reference line. + """ + if "error" in processed_data: + return {"error": processed_data["error"]} + + freqs: list[float] = processed_data["frequencies"] + phases: list[float] = processed_data["phases_deg"] + grid_enabled: bool = processed_data["grid_enabled"] + + # Marker + marker_freq: float = processed_data["marker_frequency"] + if freqs: + idx = min(range(len(freqs)), key=lambda i: abs(freqs[i] - marker_freq)) + marker_y = phases[idx] + marker_trace = { + "x": [freqs[idx] / 1e9], + "y": [marker_y], + "type": "scatter", + "mode": "markers", + "name": f"Marker: {freqs[idx]/1e9:.3f} GHz, {marker_y:.1f}°", + "marker": {"color": "red", "size": 8, "symbol": "circle"}, + } + else: + marker_trace = None + + traces = [ + { + "x": [f / 1e9 for f in freqs], # Hz -> GHz + "y": phases, + "type": "scatter", + "mode": "lines", + "name": "Phase", + "line": {"color": "green", "width": 2}, + } + ] + if processed_data["marker_enabled"] and marker_trace: + traces.append(marker_trace) + + # Reference line + if processed_data["reference_line_enabled"] and freqs: + ref = float(processed_data["reference_phase"]) + traces.append( + { + "x": [freqs[0] / 1e9, freqs[-1] / 1e9], + "y": [ref, ref], + "type": "scatter", + "mode": "lines", + "name": f"Reference: {ref:.1f}°", + "line": {"color": "gray", "width": 1, "dash": "dash"}, + } + ) + + fig = { + "data": traces, + "layout": { + "title": "Phase Response", + "xaxis": {"title": "Frequency (GHz)", "showgrid": grid_enabled}, + "yaxis": { + "title": "Phase (degrees)", + "range": [processed_data["y_min"], processed_data["y_max"]], + "showgrid": grid_enabled, + }, + "hovermode": "x unified", + "showlegend": True, + }, + } + return fig + + # ------------------------------------------------------------------ # + # UI schema + # ------------------------------------------------------------------ # + def get_ui_parameters(self) -> list[UIParameter]: + """ + UI/validation schema (compatible with BaseProcessor's validators). + """ return [ UIParameter( - name='y_min', - label='Y Axis Min (degrees)', - type='slider', - value=self._config.get('y_min', -180), - options={'min': -360, 'max': 0, 'step': 15} + name="y_min", + label="Y Axis Min (degrees)", + type="slider", + value=self._config.get("y_min", -180), + options={"min": -360, "max": 0, "step": 15, "dtype": "int"}, ), UIParameter( - name='y_max', - label='Y Axis Max (degrees)', - type='slider', - value=self._config.get('y_max', 180), - options={'min': 0, 'max': 360, 'step': 15} + name="y_max", + label="Y Axis Max (degrees)", + type="slider", + value=self._config.get("y_max", 180), + options={"min": 0, "max": 360, "step": 15, "dtype": "int"}, ), UIParameter( - name='unwrap_phase', - label='Unwrap Phase', - type='toggle', - value=self._config.get('unwrap_phase', True) + name="unwrap_phase", + label="Unwrap Phase", + type="toggle", + value=self._config.get("unwrap_phase", True), + options={}, ), UIParameter( - name='phase_offset', - label='Phase Offset (degrees)', - type='slider', - value=self._config.get('phase_offset', 0), - options={'min': -180, 'max': 180, 'step': 5} + name="phase_offset", + label="Phase Offset (degrees)", + type="slider", + value=self._config.get("phase_offset", 0), + options={"min": -180, "max": 180, "step": 5, "dtype": "int"}, ), UIParameter( - name='smoothing_enabled', - label='Enable Smoothing', - type='toggle', - value=self._config.get('smoothing_enabled', False) + name="smoothing_enabled", + label="Enable Smoothing", + type="toggle", + value=self._config.get("smoothing_enabled", False), + options={}, ), UIParameter( - name='smoothing_window', - label='Smoothing Window Size', - type='slider', - value=self._config.get('smoothing_window', 5), - options={'min': 3, 'max': 21, 'step': 2} + name="smoothing_window", + label="Smoothing Window Size", + type="slider", + value=self._config.get("smoothing_window", 5), + options={"min": 3, "max": 21, "step": 2, "dtype": "int"}, ), UIParameter( - name='marker_enabled', - label='Show Marker', - type='toggle', - value=self._config.get('marker_enabled', True) + name="marker_enabled", + label="Show Marker", + type="toggle", + value=self._config.get("marker_enabled", True), + options={}, ), UIParameter( - name='marker_frequency', - label='Marker Frequency (Hz)', - type='input', - value=self._config.get('marker_frequency', 1e9), - options={'type': 'number', 'min': 100e6, 'max': 8.8e9} + name="marker_frequency", + label="Marker Frequency (Hz)", + type="input", + value=self._config.get("marker_frequency", 1e9), + options={"type": "float", "min": 100e6, "max": 8.8e9}, ), UIParameter( - name='reference_line_enabled', - label='Show Reference Line', - type='toggle', - value=self._config.get('reference_line_enabled', False) + name="reference_line_enabled", + label="Show Reference Line", + type="toggle", + value=self._config.get("reference_line_enabled", False), + options={}, ), UIParameter( - name='reference_phase', - label='Reference Phase (degrees)', - type='slider', - value=self._config.get('reference_phase', 0), - options={'min': -180, 'max': 180, 'step': 15} + name="reference_phase", + label="Reference Phase (degrees)", + type="slider", + value=self._config.get("reference_phase", 0), + options={"min": -180, "max": 180, "step": 15, "dtype": "int"}, ), UIParameter( - name='grid_enabled', - label='Show Grid', - type='toggle', - value=self._config.get('grid_enabled', True) - ) + name="grid_enabled", + label="Show Grid", + type="toggle", + value=self._config.get("grid_enabled", True), + options={}, + ), ] - def _get_default_config(self) -> Dict[str, Any]: + def _get_default_config(self) -> dict[str, Any]: + """Defaults aligned with the UI schema.""" return { - 'y_min': -180, - 'y_max': 180, - 'unwrap_phase': True, - 'phase_offset': 0, - 'smoothing_enabled': False, - 'smoothing_window': 5, - 'marker_enabled': True, - 'marker_frequency': 1e9, - 'reference_line_enabled': False, - 'reference_phase': 0, - 'grid_enabled': True + "y_min": -180, + "y_max": 180, + "unwrap_phase": True, + "phase_offset": 0, + "smoothing_enabled": False, + "smoothing_window": 5, + "marker_enabled": True, + "marker_frequency": 1e9, + "reference_line_enabled": False, + "reference_phase": 0, + "grid_enabled": True, } - def _validate_config(self): - required_keys = ['y_min', 'y_max', 'unwrap_phase', 'phase_offset', - 'smoothing_enabled', 'smoothing_window', 'marker_enabled', - 'marker_frequency', 'reference_line_enabled', 'reference_phase', 'grid_enabled'] + # ------------------------------------------------------------------ # + # Smoothing + # ------------------------------------------------------------------ # + @staticmethod + def _apply_moving_average(data: list[float], window_size: int) -> list[float]: + """ + Centered moving average with clamped edges. - for key in required_keys: - if key not in self._config: - raise ValueError(f"Missing required config key: {key}") - - if self._config['y_min'] >= self._config['y_max']: - raise ValueError("y_min must be less than y_max") - - if self._config['smoothing_window'] < 3 or self._config['smoothing_window'] % 2 == 0: - raise ValueError("smoothing_window must be odd and >= 3") - - def _apply_moving_average(self, data: List[float], window_size: int) -> List[float]: - if window_size >= len(data): + Requirements + ------------ + - `window_size` must be odd and >= 3 (enforced by UI schema). + """ + n = len(data) + if n == 0 or window_size <= 1 or window_size >= n: return data - smoothed = [] - half_window = window_size // 2 - - for i in range(len(data)): - start_idx = max(0, i - half_window) - end_idx = min(len(data), i + half_window + 1) - smoothed.append(sum(data[start_idx:end_idx]) / (end_idx - start_idx)) - - return smoothed \ No newline at end of file + half = window_size // 2 + out: list[float] = [] + for i in range(n): + lo = max(0, i - half) + hi = min(n, i + half + 1) + out.append(sum(data[lo:hi]) / (hi - lo)) + return out diff --git a/vna_system/core/processors/manager.py b/vna_system/core/processors/manager.py index 3bf8b1b..c622fc0 100644 --- a/vna_system/core/processors/manager.py +++ b/vna_system/core/processors/manager.py @@ -1,74 +1,139 @@ -from typing import Dict, List, Optional, Any, Callable -import threading -import logging from pathlib import Path +from typing import Any, Callable -from vna_system.core.settings.preset_manager import ConfigPreset +import threading + +from vna_system.core.logging.logger import get_component_logger from vna_system.core.processors.base_processor import BaseProcessor, ProcessedResult from vna_system.core.processors.calibration_processor import CalibrationProcessor from vna_system.core.acquisition.sweep_buffer import SweepBuffer, SweepData +from vna_system.core.settings.preset_manager import ConfigPreset from vna_system.core.settings.settings_manager import VNASettingsManager +logger = get_component_logger(__file__) class ProcessorManager: - def __init__(self, sweep_buffer: SweepBuffer, settings_manager: VNASettingsManager, config_dir: Path): - self.config_dir = config_dir - self._processors: Dict[str, BaseProcessor] = {} - self._lock = threading.RLock() - self._result_callbacks: List[Callable[[str, ProcessedResult], None]] = [] - self.logger = logging.getLogger(__name__) + """ + Orchestrates VNA processors and pushes sweeps through them in the background. - # Data acquisition integration - self.sweep_buffer: SweepBuffer = sweep_buffer + Responsibilities + ---------------- + • Keep a registry of `BaseProcessor` instances (add/get/list). + • Subscribe result callbacks that receive every `ProcessedResult`. + • Watch the `SweepBuffer` and, when a new sweep arrives: + 1) Optionally apply calibration. + 2) Fetch current VNA preset/config. + 3) Feed the sweep to every registered processor. + 4) Fan-out results to callbacks. + • Offer on-demand (re)calculation for a specific processor (with config updates). + + Threading model + --------------- + A single background thread (`_processing_loop`) polls the `SweepBuffer` for the + newest sweep. Access to internal state (processors, callbacks) is guarded by + `_lock` when mutation is possible. + """ + + def __init__(self, sweep_buffer: SweepBuffer, settings_manager: VNASettingsManager, config_dir: Path) -> None: + # External deps + self.sweep_buffer = sweep_buffer + self.settings_manager = settings_manager + self.config_dir = config_dir + + # Registry & fan-out + self._processors: dict[str, BaseProcessor] = {} + self._result_callbacks: list[Callable[[str, ProcessedResult], None]] = [] + + # Concurrency + self._lock = threading.RLock() self._running = False - self._thread: Optional[threading.Thread] = None + self._thread: threading.Thread | None = None self._stop_event = threading.Event() + + # Sweep progress self._last_processed_sweep = 0 - # Calibration processor for applying calibrations + # Calibration facility self.calibration_processor = CalibrationProcessor() - self.settings_manager = settings_manager - # Register default processors + # Default processors (safe to skip if missing) self._register_default_processors() + logger.debug( + "ProcessorManager initialized", + processors=list(self._processors.keys()), + config_dir=str(self.config_dir), + ) - def register_processor(self, processor: BaseProcessor): + # --------------------------------------------------------------------- # + # Registry + # --------------------------------------------------------------------- # + def register_processor(self, processor: BaseProcessor) -> None: + """Register (or replace) a processor by its `processor_id`.""" with self._lock: self._processors[processor.processor_id] = processor - self.logger.info(f"Registered processor: {processor.processor_id}") + logger.info("Processor registered", processor_id=processor.processor_id) - def get_processor(self, processor_id: str) -> Optional[BaseProcessor]: + def get_processor(self, processor_id: str) -> BaseProcessor | None: + """Return a processor instance by id, or None if not found.""" return self._processors.get(processor_id) - def list_processors(self) -> List[str]: + def list_processors(self) -> list[str]: + """Return a stable snapshot list of registered processor ids.""" return list(self._processors.keys()) - def add_result_callback(self, callback: Callable[[str, ProcessedResult], None]): - print("adding callback") - self._result_callbacks.append(callback) + # --------------------------------------------------------------------- # + # Results fan-out + # --------------------------------------------------------------------- # + def add_result_callback(self, callback: Callable[[str, ProcessedResult], None]) -> None: + """ + Add a callback invoked for every produced result. - def process_sweep(self, sweep_data: SweepData, calibrated_data: Any, vna_config: ConfigPreset | None): - results = {} - print(f"Processing sweep {sweep_data.sweep_number=}") + Callback signature: + (processor_id: str, result: ProcessedResult) -> None + """ with self._lock: - for processor_id, processor in self._processors.items(): - try: - result = processor.add_sweep_data(sweep_data, calibrated_data, vna_config) - if result: - results[processor_id] = result - for callback in self._result_callbacks: - try: - callback(processor_id, result) - except Exception as e: - self.logger.error(f"Callback error for {processor_id}: {e}") + self._result_callbacks.append(callback) + logger.debug("Result callback added", callbacks=len(self._result_callbacks)) - except Exception as e: - self.logger.error(f"Processing error in {processor_id}: {e}") + # --------------------------------------------------------------------- # + # Main processing actions + # --------------------------------------------------------------------- # + def process_sweep(self, sweep_data: SweepData, calibrated_data: Any, vna_config: ConfigPreset | None) -> dict[str, ProcessedResult]: + """ + Feed a sweep into all processors and dispatch results to callbacks. + + Returns a map {processor_id: ProcessedResult} for successfully computed processors. + """ + results: dict[str, ProcessedResult] = {} + with self._lock: + # Snapshot to avoid holding the lock while user callbacks run + processors_items = list(self._processors.items()) + callbacks = list(self._result_callbacks) + + for processor_id, processor in processors_items: + try: + result = processor.add_sweep_data(sweep_data, calibrated_data, vna_config) + if result: + results[processor_id] = result + for cb in callbacks: + try: + cb(processor_id, result) + except Exception as exc: # noqa: BLE001 + logger.error("Result callback failed", processor_id=processor_id, error=repr(exc)) + except Exception as exc: # noqa: BLE001 + logger.error("Processing error", processor_id=processor_id, error=repr(exc)) return results - def recalculate_processor(self, processor_id: str, config_updates: Optional[Dict[str, Any]] = None) -> Optional[ProcessedResult]: + def recalculate_processor(self, processor_id: str, config_updates: dict[str, Any] | None = None) -> ProcessedResult | None: + """ + Recalculate a single processor with optional config updates. + + - If `config_updates` is provided, they are applied and validated first. + - The latest sweep (from the processor's own history) is used for recomputation. + - Result callbacks are invoked if a result is produced. + """ processor = self.get_processor(processor_id) if not processor: raise ValueError(f"Processor {processor_id} not found") @@ -79,111 +144,134 @@ class ProcessorManager: result = processor.recalculate() if result: - for callback in self._result_callbacks: + with self._lock: + callbacks = list(self._result_callbacks) + for cb in callbacks: try: - callback(processor_id, result) - except Exception as e: - self.logger.error(f"Callback error for {processor_id}: {e}") - + cb(processor_id, result) + except Exception as exc: # noqa: BLE001 + logger.error("Result callback failed", processor_id=processor_id, error=repr(exc)) return result - - except Exception as e: - self.logger.error(f"Recalculation error in {processor_id}: {e}") + except Exception as exc: # noqa: BLE001 + logger.error("Recalculation error", processor_id=processor_id, error=repr(exc)) raise - - def get_processor_ui_parameters(self, processor_id: str): - processor = self.get_processor(processor_id) - if not processor: - raise ValueError(f"Processor {processor_id} not found") - return [param.__dict__ for param in processor.get_ui_parameters()] - - - def _register_default_processors(self): - """Register default processors""" - try: - from .implementations import MagnitudeProcessor, PhaseProcessor, SmithChartProcessor - - magnitude_processor = MagnitudeProcessor(self.config_dir) - self.register_processor(magnitude_processor) - - phase_processor = PhaseProcessor(self.config_dir) - self.register_processor(phase_processor) - - smith_processor = SmithChartProcessor(self.config_dir) - self.register_processor(smith_processor) - - self.logger.info("Default processors registered successfully") - except Exception as e: - self.logger.error(f"Failed to register default processors: {e}") - - def set_sweep_buffer(self, sweep_buffer: SweepBuffer): - """Set the sweep buffer for data acquisition integration""" + # --------------------------------------------------------------------- # + # Runtime control + # --------------------------------------------------------------------- # + def set_sweep_buffer(self, sweep_buffer: SweepBuffer) -> None: + """Swap the underlying sweep buffer (takes effect immediately).""" self.sweep_buffer = sweep_buffer + logger.info("Sweep buffer updated") - def start_processing(self): - """Start background processing of sweep data""" - if self._running or not self.sweep_buffer: + def start_processing(self) -> None: + """ + Start the background processing thread. + + Safe to call multiple times (no-op if already running). + """ + if self._running: + logger.debug("start_processing ignored; already running") return self._running = True self._stop_event.clear() - self._thread = threading.Thread(target=self._processing_loop, daemon=True) + self._thread = threading.Thread(target=self._processing_loop, daemon=True, name="VNA-ProcessorManager") self._thread.start() - self.logger.info("Processor manager started") + logger.info("Processor manager started") - def stop_processing(self): - """Stop background processing""" + def stop_processing(self) -> None: + """ + Stop the background thread and wait briefly for it to join. + """ if not self._running: + logger.debug("stop_processing ignored; not running") return self._running = False self._stop_event.set() if self._thread: self._thread.join(timeout=1.0) - self.logger.info("Processor manager stopped") + logger.info("Processor manager stopped") - def _processing_loop(self): - """Main processing loop""" + # --------------------------------------------------------------------- # + # Background loop + # --------------------------------------------------------------------- # + def _processing_loop(self) -> None: + """ + Poll the sweep buffer and process any new sweep. + + The loop: + • Grabs the latest sweep. + • Skips if it's already processed. + • Applies calibration (when available). + • Retrieves current VNA preset. + • Sends the sweep to all processors. + • Sleeps briefly to keep CPU usage low. + """ while self._running and not self._stop_event.is_set(): try: - latest_sweep = self.sweep_buffer.get_latest_sweep() + latest = self.sweep_buffer.get_latest_sweep() + if latest and latest.sweep_number > self._last_processed_sweep: + calibrated = self._apply_calibration(latest) + vna_cfg = self.settings_manager.get_current_preset() + self.process_sweep(latest, calibrated, vna_cfg) + self._last_processed_sweep = latest.sweep_number - if latest_sweep and latest_sweep.sweep_number > self._last_processed_sweep: - # Apply calibration - calibrated_data = self._apply_calibration(latest_sweep) - - # Get VNA configuration - vna_config = self.settings_manager.get_current_preset() - - # Process through all processors (results handled by callbacks) - self.process_sweep(latest_sweep, calibrated_data, vna_config) - - self._last_processed_sweep = latest_sweep.sweep_number - - # Check every 50ms + # Light-duty polling to reduce wakeups self._stop_event.wait(0.05) - - except Exception as e: - self.logger.error(f"Error in processing loop: {e}") + except Exception as exc: # noqa: BLE001 + logger.error("Error in processing loop", error=repr(exc)) self._stop_event.wait(0.1) + # --------------------------------------------------------------------- # + # Calibration + # --------------------------------------------------------------------- # def _apply_calibration(self, sweep_data: SweepData) -> SweepData: - """Apply calibration to sweep data""" + """ + Apply calibration to the sweep when a complete set is available. + + Returns the original sweep on failure or when no calibration is present. + """ try: - # Get current calibration set through settings manager - calibration_set = self.settings_manager.get_current_calibration() - if calibration_set and calibration_set.is_complete(): - # Apply calibration using our calibration processor - calibrated_points = self.calibration_processor.apply_calibration(sweep_data, calibration_set) - return SweepData( + calib_set = self.settings_manager.get_current_calibration() + if calib_set and calib_set.is_complete(): + points = self.calibration_processor.apply_calibration(sweep_data, calib_set) + calibrated = SweepData( sweep_number=sweep_data.sweep_number, timestamp=sweep_data.timestamp, - points=calibrated_points, - total_points=len(calibrated_points) + points=points, + total_points=len(points), ) - except Exception as e: - self.logger.error(f"Calibration failed: {e}") + logger.debug( + "Sweep calibrated", + sweep_number=calibrated.sweep_number, + points=calibrated.total_points, + ) + return calibrated + except Exception as exc: # noqa: BLE001 + logger.error("Calibration failed", error=repr(exc)) - # Return original data if calibration fails or not available + # Fallback: return the original data return sweep_data + + # --------------------------------------------------------------------- # + # Defaults + # --------------------------------------------------------------------- # + def _register_default_processors(self) -> None: + """ + Attempt to import and register default processors. + + This is best-effort: if anything fails (e.g., module not present), + we log an error and keep going with whatever is available. + """ + try: + from .implementations import MagnitudeProcessor, PhaseProcessor, SmithChartProcessor + + self.register_processor(MagnitudeProcessor(self.config_dir)) + self.register_processor(PhaseProcessor(self.config_dir)) + # self.register_processor(SmithChartProcessor(self.config_dir)) + + logger.info("Default processors registered", count=len(self._processors)) + except Exception as exc: # noqa: BLE001 + logger.error("Failed to register default processors", error=repr(exc)) diff --git a/vna_system/core/processors/websocket_handler.py b/vna_system/core/processors/websocket_handler.py index 12195d6..c68861b 100644 --- a/vna_system/core/processors/websocket_handler.py +++ b/vna_system/core/processors/websocket_handler.py @@ -1,94 +1,114 @@ -from typing import Dict, Any, Set, Optional -import json import asyncio -import logging +import json +from dataclasses import asdict from datetime import datetime +from typing import Any + from fastapi import WebSocket, WebSocketDisconnect +from vna_system.core.logging.logger import get_component_logger from vna_system.core.processors.base_processor import ProcessedResult from vna_system.core.processors.manager import ProcessorManager from vna_system.core.processors.storage import DataStorage +logger = get_component_logger(__file__) + class ProcessorWebSocketHandler: """ - Handles incoming websocket messages and broadcasts processor results - to all connected clients. Safe to call from non-async threads via - _broadcast_result_sync(). + WebSocket hub for processor results. + + Responsibilities + ---------------- + • Accept and manage client connections. + • Handle client commands (e.g., recalculate, fetch history). + • Broadcast `ProcessedResult` objects to all connected clients. + • Bridge results produced on worker threads into the main asyncio loop. + + Threading model + --------------- + - Processor callbacks arrive on non-async worker threads. + - We capture the main running event loop when the first client connects. + - Cross-thread scheduling uses `asyncio.run_coroutine_threadsafe`. """ - def __init__(self, processor_manager: ProcessorManager, data_storage: DataStorage): + def __init__(self, processor_manager: ProcessorManager, data_storage: DataStorage) -> None: self.processor_manager = processor_manager self.data_storage = data_storage - self.active_connections: Set[WebSocket] = set() - self.logger = logging.getLogger(__name__) - # Главный (running) event loop FastAPI/uvicorn. - # Устанавливается при принятии первого соединения. - self._loop: Optional[asyncio.AbstractEventLoop] = None + self.active_connections: set[WebSocket] = set() - # Регистрируемся как колбэк на готовые результаты процессоров + # Main FastAPI/uvicorn event loop handle (set on first connection). + self._loop: asyncio.AbstractEventLoop | None = None + + # Subscribe to processor results (thread-safe callback). self.processor_manager.add_result_callback(self._on_processor_result) + logger.debug("ProcessorWebSocketHandler initialized") - # --------------- Публичные async-обработчики входящих сообщений --------------- + # --------------------------------------------------------------------- # + # Connection lifecycle + # --------------------------------------------------------------------- # + async def handle_websocket_connection(self, websocket: WebSocket) -> None: + """ + Accept a WebSocket, then serve client messages until disconnect. - async def handle_websocket_connection(self, websocket: WebSocket): + Stores a reference to the running event loop so worker threads can + safely schedule broadcasts into it. """ - Accepts a websocket and serves messages until disconnect. - Сохраняет ссылку на главный running loop, чтобы из других потоков - можно было безопасно шедулить корутины. - """ - # Сохраним ссылку на активный loop (гарантированно внутри async-контекста) if self._loop is None: - try: - self._loop = asyncio.get_running_loop() - self.logger.info("Stored main event loop reference for broadcasting") - except RuntimeError: - # Теоретически маловероятно здесь - self.logger.warning("Could not obtain running loop; broadcasts may be skipped") - + self._loop = asyncio.get_running_loop() + logger.info("Main event loop captured for broadcasts") + await websocket.accept() self.active_connections.add(websocket) - self.logger.info(f"WebSocket connected. Total connections: {len(self.active_connections)}") + logger.info("WebSocket connected", total_connections=len(self.active_connections)) try: while True: - data = await websocket.receive_text() - await self.handle_message(websocket, data) + raw = await websocket.receive_text() + await self.handle_message(websocket, raw) except WebSocketDisconnect: await self.disconnect(websocket) - except Exception as e: - self.logger.error(f"WebSocket error: {e}") + except Exception as exc: # noqa: BLE001 + logger.error("WebSocket error", error=repr(exc)) await self.disconnect(websocket) - async def handle_message(self, websocket: WebSocket, data: str): - try: - message = json.loads(data) - message_type = message.get('type') - - if message_type == 'recalculate': - await self._handle_recalculate(websocket, message) - elif message_type == 'get_history': - await self._handle_get_history(websocket, message) - else: - await self._send_error(websocket, f"Unknown message type: {message_type}") - - except json.JSONDecodeError: - await self._send_error(websocket, "Invalid JSON format") - except Exception as e: - self.logger.exception("Error handling websocket message") - await self._send_error(websocket, f"Internal error: {str(e)}") - - async def disconnect(self, websocket: WebSocket): + async def disconnect(self, websocket: WebSocket) -> None: + """Remove a connection and log the updated count.""" if websocket in self.active_connections: self.active_connections.remove(websocket) - self.logger.info(f"WebSocket disconnected. Total connections: {len(self.active_connections)}") + logger.info("WebSocket disconnected", total_connections=len(self.active_connections)) - # --------------- Команды клиента --------------- + # --------------------------------------------------------------------- # + # Inbound messages + # --------------------------------------------------------------------- # + async def handle_message(self, websocket: WebSocket, data: str) -> None: + """Parse and route an inbound client message.""" + try: + message = json.loads(data) + mtype = message.get("type") - async def _handle_recalculate(self, websocket: WebSocket, message: Dict[str, Any]): - processor_id = message.get('processor_id') - config_updates = message.get('config_updates') + if mtype == "recalculate": + await self._handle_recalculate(websocket, message) + elif mtype == "get_history": + await self._handle_get_history(websocket, message) + else: + await self._send_error(websocket, f"Unknown message type: {mtype!r}") + except json.JSONDecodeError: + await self._send_error(websocket, "Invalid JSON format") + except Exception as exc: # noqa: BLE001 + logger.error("Error handling websocket message") + await self._send_error(websocket, f"Internal error: {exc}") + + # --------------------------------------------------------------------- # + # Client commands + # --------------------------------------------------------------------- # + async def _handle_recalculate(self, websocket: WebSocket, message: dict[str, Any]) -> None: + """ + Recalculate a processor (optionally with config updates) and send the result back. + """ + processor_id = message.get("processor_id") + config_updates = message.get("config_updates") if not processor_id: await self._send_error(websocket, "processor_id is required") @@ -97,18 +117,19 @@ class ProcessorWebSocketHandler: try: result = self.processor_manager.recalculate_processor(processor_id, config_updates) if result: - response = self._result_to_message(processor_id, result) - await websocket.send_text(json.dumps(response)) + await websocket.send_text(json.dumps(self._result_to_message(processor_id, result))) else: await self._send_error(websocket, f"No result from processor {processor_id}") + except Exception as exc: # noqa: BLE001 + logger.error("Recalculation failed") + await self._send_error(websocket, f"Recalculation failed: {exc}") - except Exception as e: - self.logger.exception("Recalculation failed") - await self._send_error(websocket, f"Recalculation failed: {str(e)}") - - async def _handle_get_history(self, websocket: WebSocket, message: Dict[str, Any]): - processor_id = message.get('processor_id') - limit = message.get('limit', 10) + async def _handle_get_history(self, websocket: WebSocket, message: dict[str, Any]) -> None: + """ + Fetch recent results history for a given processor and send it to the client. + """ + processor_id = message.get("processor_id") + limit = int(message.get("limit", 10)) if not processor_id: await self._send_error(websocket, "processor_id is required") @@ -117,108 +138,114 @@ class ProcessorWebSocketHandler: try: history = self.data_storage.get_results_history(processor_id, limit) response = { - 'type': 'processor_history', - 'processor_id': processor_id, - 'history': [ + "type": "processor_history", + "processor_id": processor_id, + "history": [ { - 'timestamp': r.timestamp, - 'data': r.data, - 'plotly_config': r.plotly_config, - 'metadata': r.metadata + "timestamp": r.timestamp, + "data": r.data, + "plotly_config": r.plotly_config, + "metadata": r.metadata, } for r in history - ] + ], } await websocket.send_text(json.dumps(response)) + except Exception as exc: # noqa: BLE001 + logger.error("Error getting history") + await self._send_error(websocket, f"Error getting history: {exc}") - except Exception as e: - self.logger.exception("Error getting history") - await self._send_error(websocket, f"Error getting history: {str(e)}") - - # --------------- Служебные методы --------------- - - def _result_to_message(self, processor_id: str, result: ProcessedResult) -> Dict[str, Any]: + # --------------------------------------------------------------------- # + # Outbound helpers + # --------------------------------------------------------------------- # + def _result_to_message(self, processor_id: str, result: ProcessedResult) -> dict[str, Any]: + """Convert a `ProcessedResult` into a JSON-serializable message.""" return { - 'type': 'processor_result', - 'processor_id': processor_id, - 'timestamp': result.timestamp, - 'data': result.data, - 'plotly_config': result.plotly_config, - 'ui_parameters': [param.__dict__ for param in result.ui_parameters], - 'metadata': result.metadata + "type": "processor_result", + "processor_id": processor_id, + "timestamp": result.timestamp, + "data": result.data, + "plotly_config": result.plotly_config, + "ui_parameters": [asdict(param) for param in result.ui_parameters], + "metadata": result.metadata, } - async def _send_error(self, websocket: WebSocket, message: str): + async def _send_error(self, websocket: WebSocket, message: str) -> None: + """Send a standardized error payload to a single client.""" try: - response = { - 'type': 'error', - 'message': message, - 'timestamp': datetime.now().timestamp() + payload = { + "type": "error", + "message": message, + "timestamp": datetime.now().timestamp(), } - await websocket.send_text(json.dumps(response)) - except Exception as e: - self.logger.error(f"Error sending error message: {e}") + await websocket.send_text(json.dumps(payload)) + except Exception as exc: # noqa: BLE001 + logger.error("Error sending error message", error=repr(exc)) - # --------------- Получение результатов из процессоров (из другого потока) --------------- + # --------------------------------------------------------------------- # + # Result callback bridge (worker thread -> asyncio loop) + # --------------------------------------------------------------------- # + def _on_processor_result(self, processor_id: str, result: ProcessedResult) -> None: + """ + Callback invoked on a worker thread when a processor produces a result. - def _on_processor_result(self, processor_id: str, result: ProcessedResult): + We: + - Store the result synchronously in `DataStorage`. + - Schedule a coroutine on the main event loop to broadcast to clients. """ - Колбэк вызывается из потока обработки свипов (не из asyncio loop). - Здесь нельзя напрямую await'ить — нужно перепоручить рассылку в главный loop. - """ - # Сохраняем результат в хранилище (синхронно) + # Best-effort persistence try: self.data_storage.store_result(processor_id, result) - except Exception: - self.logger.exception("Failed to store processor result") + except Exception: # noqa: BLE001 + logger.error("Failed to store processor result") - # Рассылаем клиентам + # Broadcast to clients self._broadcast_result_sync(processor_id, result) - def _broadcast_result_sync(self, processor_id: str, result: ProcessedResult): + def _broadcast_result_sync(self, processor_id: str, result: ProcessedResult) -> None: """ - Потокобезопасная рассылка в активный event loop. - Вызывается из НЕ-async потока. + Thread-safe broadcast entrypoint from worker threads. + + Serializes once and schedules `_send_to_connections(...)` on the main loop. """ if not self.active_connections: return - # Подготовим строку JSON один раз - message_str = json.dumps(self._result_to_message(processor_id, result)) - loop = self._loop if loop is None or not loop.is_running(): - # Луп ещё не был сохранён (нет подключений) или уже остановлен - self.logger.debug("No running event loop available for broadcast; skipping") + logger.debug("No running event loop available for broadcast; skipping") return try: - # Перекидываем корутину в главный loop из стороннего потока - fut = asyncio.run_coroutine_threadsafe(self._send_to_connections(message_str), loop) - # Опционально: можно добавить обработку результата/исключений: - # fut.add_done_callback(lambda f: f.exception() and self.logger.error(f"Broadcast error: {f.exception()}")) - except Exception as e: - self.logger.error(f"Failed to schedule broadcast: {e}") + message_str = json.dumps(self._result_to_message(processor_id, result)) + except Exception as exc: # noqa: BLE001 + logger.error(f"Failed to serialize result for broadcast, {processor_id=}", error=repr(exc)) + return - async def _send_to_connections(self, message_str: str): + try: + asyncio.run_coroutine_threadsafe(self._send_to_connections(message_str), loop) + except Exception as exc: # noqa: BLE001 + logger.error("Failed to schedule broadcast", error=repr(exc)) + + async def _send_to_connections(self, message_str: str) -> None: """ - Реальная рассылка по всем активным соединениям (внутри event loop). + Broadcast a pre-serialized JSON string to all active connections. + + Removes connections that fail during send. """ if not self.active_connections: return - disconnected = [] - # Снимок, чтобы итерация была стабильной - for websocket in list(self.active_connections): + disconnected: list[WebSocket] = [] + for websocket in list(self.active_connections): # snapshot try: await websocket.send_text(message_str) - except Exception as e: - self.logger.error(f"Error broadcasting to a websocket: {e}") + except Exception as exc: # noqa: BLE001 + logger.error("Broadcast to client failed; marking for disconnect", error=repr(exc)) disconnected.append(websocket) - # Очистим отключившиеся for websocket in disconnected: try: await self.disconnect(websocket) - except Exception as e: - self.logger.error(f"Error during disconnect cleanup: {e}") + except Exception as exc: # noqa: BLE001 + logger.error("Error during disconnect cleanup", error=repr(exc)) diff --git a/vna_system/core/settings/calibration_manager.py b/vna_system/core/settings/calibration_manager.py index b75cd3f..48e2f20 100644 --- a/vna_system/core/settings/calibration_manager.py +++ b/vna_system/core/settings/calibration_manager.py @@ -1,18 +1,19 @@ -from __future__ import annotations - import json import shutil from datetime import datetime from enum import Enum from pathlib import Path -from typing import Dict, List from vna_system.core import config as cfg +from vna_system.core.logging.logger import get_component_logger from vna_system.core.acquisition.sweep_buffer import SweepData -from .preset_manager import ConfigPreset, VNAMode +from vna_system.core.settings.preset_manager import ConfigPreset, VNAMode + +logger = get_component_logger(__file__) class CalibrationStandard(Enum): + """Supported calibration standards.""" OPEN = "open" SHORT = "short" LOAD = "load" @@ -20,291 +21,354 @@ class CalibrationStandard(Enum): class CalibrationSet: - def __init__(self, preset: ConfigPreset, name: str = ""): + """ + In-memory container of calibration measurements for a specific VNA preset. + + A set is *complete* when all standards required by the preset mode are present: + - S11: OPEN, SHORT, LOAD + - S21: THROUGH + """ + + def __init__(self, preset: ConfigPreset, name: str = "") -> None: self.preset = preset self.name = name - self.standards: Dict[CalibrationStandard, SweepData] = {} + self.standards: dict[CalibrationStandard, SweepData] = {} - def add_standard(self, standard: CalibrationStandard, sweep_data: SweepData): - """Add calibration data for specific standard""" + # ------------------------------ mutation ------------------------------ # + def add_standard(self, standard: CalibrationStandard, sweep_data: SweepData) -> None: + """Attach sweep data for a given standard.""" self.standards[standard] = sweep_data + logger.debug("Calibration standard added", standard=standard.value, points=sweep_data.total_points) - def remove_standard(self, standard: CalibrationStandard): - """Remove calibration data for specific standard""" + def remove_standard(self, standard: CalibrationStandard) -> None: + """Remove sweep data for a given standard if present.""" if standard in self.standards: del self.standards[standard] + logger.debug("Calibration standard removed", standard=standard.value) + # ------------------------------ queries -------------------------------- # def has_standard(self, standard: CalibrationStandard) -> bool: - """Check if standard is present in calibration set""" + """Return True if the standard is present in the set.""" return standard in self.standards def is_complete(self) -> bool: - """Check if all required standards are present""" - required_standards = self._get_required_standards() - return all(std in self.standards for std in required_standards) + """Return True if all required standards for the preset mode are present.""" + required = self._get_required_standards() + complete = all(s in self.standards for s in required) + logger.debug("Calibration completeness checked", complete=complete, required=[s.value for s in required]) + return complete - def get_missing_standards(self) -> List[CalibrationStandard]: - """Get list of missing required standards""" - required_standards = self._get_required_standards() - return [std for std in required_standards if std not in self.standards] + def get_missing_standards(self) -> list[CalibrationStandard]: + """List the standards still missing for a complete set.""" + required = self._get_required_standards() + return [s for s in required if s not in self.standards] def get_progress(self) -> tuple[int, int]: - """Get calibration progress as (completed, total)""" - required_standards = self._get_required_standards() - completed = len([std for std in required_standards if std in self.standards]) - return completed, len(required_standards) + """Return (completed, total_required) for progress display.""" + required = self._get_required_standards() + completed = sum(1 for s in required if s in self.standards) + return completed, len(required) - def _get_required_standards(self) -> List[CalibrationStandard]: - """Get required calibration standards for preset mode""" + # ------------------------------ internals ------------------------------ # + def _get_required_standards(self) -> list[CalibrationStandard]: + """Standards required by the current preset mode.""" if self.preset.mode == VNAMode.S11: return [CalibrationStandard.OPEN, CalibrationStandard.SHORT, CalibrationStandard.LOAD] - elif self.preset.mode == VNAMode.S21: + if self.preset.mode == VNAMode.S21: return [CalibrationStandard.THROUGH] return [] class CalibrationManager: - def __init__(self, base_dir: Path | None = None): + """ + Filesystem-backed manager for calibration sets. + + Layout + ------ + /calibration/ + ├─ current_calibration -> / + ├─ / + │ └─ / + │ ├─ open.json / short.json / load.json / through.json + │ ├─ open_metadata.json ... (per-standard metadata) + │ └─ calibration_info.json (set-level metadata) + """ + + def __init__(self, base_dir: Path | None = None) -> None: self.base_dir = Path(base_dir or cfg.BASE_DIR) self.calibration_dir = self.base_dir / "calibration" self.current_calibration_symlink = self.calibration_dir / "current_calibration" - self.calibration_dir.mkdir(parents=True, exist_ok=True) - # Current working calibration set self._current_working_set: CalibrationSet | None = None + logger.debug("CalibrationManager initialized", base_dir=str(self.base_dir)) + # ------------------------------------------------------------------ # + # Working set lifecycle + # ------------------------------------------------------------------ # def start_new_calibration(self, preset: ConfigPreset) -> CalibrationSet: - """Start new calibration set for preset""" + """Start a new, empty working set for a given preset.""" self._current_working_set = CalibrationSet(preset) + logger.info("New calibration session started", preset=preset.filename, mode=preset.mode.value) return self._current_working_set def get_current_working_set(self) -> CalibrationSet | None: - """Get current working calibration set""" + """Return the current working set (if any).""" return self._current_working_set - def add_calibration_standard(self, standard: CalibrationStandard, sweep_data: SweepData): - """Add calibration standard to current working set""" + def add_calibration_standard(self, standard: CalibrationStandard, sweep_data: SweepData) -> None: + """Add a standard measurement to the active working set.""" if self._current_working_set is None: raise RuntimeError("No active calibration set. Call start_new_calibration first.") - self._current_working_set.add_standard(standard, sweep_data) - def remove_calibration_standard(self, standard: CalibrationStandard): - """Remove calibration standard from current working set""" + def remove_calibration_standard(self, standard: CalibrationStandard) -> None: + """Remove a standard measurement from the working set.""" if self._current_working_set is None: raise RuntimeError("No active calibration set.") - self._current_working_set.remove_standard(standard) + # ------------------------------------------------------------------ # + # Persistence + # ------------------------------------------------------------------ # def save_calibration_set(self, calibration_name: str) -> CalibrationSet: - """Save current working calibration set to disk""" + """ + Persist the working set to disk under the preset directory. + + Writes: + - per-standard sweeps as JSON + - per-standard metadata + - set-level metadata + """ if self._current_working_set is None: raise RuntimeError("No active calibration set to save.") if not self._current_working_set.is_complete(): - missing = self._current_working_set.get_missing_standards() - raise ValueError(f"Calibration incomplete. Missing standards: {[s.value for s in missing]}") + missing = [s.value for s in self._current_working_set.get_missing_standards()] + raise ValueError(f"Calibration incomplete. Missing standards: {missing}") preset = self._current_working_set.preset - preset_dir = self._get_preset_calibration_dir(preset) - calib_dir = preset_dir / calibration_name + calib_dir = self._get_preset_calibration_dir(preset) / calibration_name calib_dir.mkdir(parents=True, exist_ok=True) - # Save each standard - for standard, sweep_data in self._current_working_set.standards.items(): - # Save sweep data as JSON + # Save standards + for standard, sweep in self._current_working_set.standards.items(): sweep_json = { - 'sweep_number': sweep_data.sweep_number, - 'timestamp': sweep_data.timestamp, - 'points': sweep_data.points, - 'total_points': sweep_data.total_points + "sweep_number": sweep.sweep_number, + "timestamp": sweep.timestamp, + "points": sweep.points, + "total_points": sweep.total_points, } + self._atomic_json_write(calib_dir / f"{standard.value}.json", sweep_json) - file_path = calib_dir / f"{standard.value}.json" - with open(file_path, 'w') as f: - json.dump(sweep_json, f, indent=2) - - # Save metadata for each standard metadata = { - 'preset': { - 'filename': preset.filename, - 'mode': preset.mode.value, - 'start_freq': preset.start_freq, - 'stop_freq': preset.stop_freq, - 'points': preset.points, - 'bandwidth': preset.bandwidth + "preset": { + "filename": preset.filename, + "mode": preset.mode.value, + "start_freq": preset.start_freq, + "stop_freq": preset.stop_freq, + "points": preset.points, + "bandwidth": preset.bandwidth, }, - 'calibration_name': calibration_name, - 'standard': standard.value, - 'sweep_number': sweep_data.sweep_number, - 'sweep_timestamp': sweep_data.timestamp, - 'created_timestamp': datetime.now().isoformat(), - 'total_points': sweep_data.total_points + "calibration_name": calibration_name, + "standard": standard.value, + "sweep_number": sweep.sweep_number, + "sweep_timestamp": sweep.timestamp, + "created_timestamp": datetime.now().isoformat(), + "total_points": sweep.total_points, } + self._atomic_json_write(calib_dir / f"{standard.value}_metadata.json", metadata) - metadata_path = calib_dir / f"{standard.value}_metadata.json" - with open(metadata_path, 'w') as f: - json.dump(metadata, f, indent=2) - - # Save calibration set metadata + # Save set-level metadata set_metadata = { - 'preset': { - 'filename': preset.filename, - 'mode': preset.mode.value, - 'start_freq': preset.start_freq, - 'stop_freq': preset.stop_freq, - 'points': preset.points, - 'bandwidth': preset.bandwidth + "preset": { + "filename": preset.filename, + "mode": preset.mode.value, + "start_freq": preset.start_freq, + "stop_freq": preset.stop_freq, + "points": preset.points, + "bandwidth": preset.bandwidth, }, - 'calibration_name': calibration_name, - 'standards': [std.value for std in self._current_working_set.standards.keys()], - 'created_timestamp': datetime.now().isoformat(), - 'is_complete': True + "calibration_name": calibration_name, + "standards": [s.value for s in self._current_working_set.standards], + "created_timestamp": datetime.now().isoformat(), + "is_complete": True, } + self._atomic_json_write(calib_dir / "calibration_info.json", set_metadata) - set_metadata_path = calib_dir / "calibration_info.json" - with open(set_metadata_path, 'w') as f: - json.dump(set_metadata, f, indent=2) - - # Set name for the working set + # Update working set name self._current_working_set.name = calibration_name - + logger.info("Calibration set saved", preset=preset.filename, name=calibration_name) return self._current_working_set def load_calibration_set(self, preset: ConfigPreset, calibration_name: str) -> CalibrationSet: - """Load existing calibration set from disk""" + """Load a calibration set from disk for the given preset.""" preset_dir = self._get_preset_calibration_dir(preset) calib_dir = preset_dir / calibration_name - if not calib_dir.exists(): raise FileNotFoundError(f"Calibration not found: {calibration_name}") calib_set = CalibrationSet(preset, calibration_name) - # Load all standard files for standard in CalibrationStandard: file_path = calib_dir / f"{standard.value}.json" - if file_path.exists(): - with open(file_path, 'r') as f: - sweep_json = json.load(f) - - sweep_data = SweepData( - sweep_number=sweep_json['sweep_number'], - timestamp=sweep_json['timestamp'], - points=sweep_json['points'], - total_points=sweep_json['total_points'] + if not file_path.exists(): + continue + try: + data = json.loads(file_path.read_text(encoding="utf-8")) + sweep = SweepData( + sweep_number=int(data["sweep_number"]), + timestamp=float(data["timestamp"]), + points=[(float(r), float(i)) for r, i in data["points"]], + total_points=int(data["total_points"]), ) + calib_set.add_standard(standard, sweep) + except Exception as exc: # noqa: BLE001 + logger.warning("Failed to load standard file", file=str(file_path), error=repr(exc)) - calib_set.add_standard(standard, sweep_data) - + logger.info("Calibration set loaded", preset=preset.filename, name=calibration_name) return calib_set - def get_available_calibrations(self, preset: ConfigPreset) -> List[str]: - """Get list of available calibration sets for preset""" + # ------------------------------------------------------------------ # + # Discovery & info + # ------------------------------------------------------------------ # + def get_available_calibrations(self, preset: ConfigPreset) -> list[str]: + """Return sorted list of calibration set names available for a preset.""" preset_dir = self._get_preset_calibration_dir(preset) - if not preset_dir.exists(): return [] + names = sorted([p.name for p in preset_dir.iterdir() if p.is_dir()]) + logger.debug("Available calibrations listed", preset=preset.filename, count=len(names)) + return names - calibrations = [] - for item in preset_dir.iterdir(): - if item.is_dir(): - calibrations.append(item.name) - - return sorted(calibrations) - - def get_calibration_info(self, preset: ConfigPreset, calibration_name: str) -> Dict: - """Get information about specific calibration""" + def get_calibration_info(self, preset: ConfigPreset, calibration_name: str) -> dict: + """ + Return set-level info for a calibration (from cached metadata if present, + or by scanning the directory as a fallback). + """ preset_dir = self._get_preset_calibration_dir(preset) calib_dir = preset_dir / calibration_name info_file = calib_dir / "calibration_info.json" if info_file.exists(): - with open(info_file, 'r') as f: - return json.load(f) + try: + return json.loads(info_file.read_text(encoding="utf-8")) + except Exception as exc: # noqa: BLE001 + logger.warning("Failed to read calibration_info.json; falling back to scan", error=repr(exc)) - # Fallback: scan files - standards = {} - required_standards = self._get_required_standards(preset.mode) - - for standard in required_standards: - file_path = calib_dir / f"{standard.value}.json" - standards[standard.value] = file_path.exists() + required = self._get_required_standards(preset.mode) + standards: dict[str, bool] = {} + for s in required: + standards[s.value] = (calib_dir / f"{s.value}.json").exists() return { - 'calibration_name': calibration_name, - 'standards': standards, - 'is_complete': all(standards.values()) + "calibration_name": calibration_name, + "standards": standards, + "is_complete": all(standards.values()), } - def set_current_calibration(self, preset: ConfigPreset, calibration_name: str): - """Set current calibration by creating symlink""" + # ------------------------------------------------------------------ # + # Current calibration (symlink) + # ------------------------------------------------------------------ # + def set_current_calibration(self, preset: ConfigPreset, calibration_name: str) -> None: + """Point the `current_calibration` symlink to the chosen calibration dir.""" preset_dir = self._get_preset_calibration_dir(preset) calib_dir = preset_dir / calibration_name - if not calib_dir.exists(): raise FileNotFoundError(f"Calibration not found: {calibration_name}") - # Check if calibration is complete info = self.get_calibration_info(preset, calibration_name) - if not info.get('is_complete', False): + if not info.get("is_complete", False): raise ValueError(f"Calibration {calibration_name} is incomplete") - # Remove existing symlink if present - if self.current_calibration_symlink.exists() or self.current_calibration_symlink.is_symlink(): - self.current_calibration_symlink.unlink() - - # Create new symlink + # Refresh symlink try: - relative_path = calib_dir.relative_to(self.calibration_dir) - except ValueError: - relative_path = calib_dir + if self.current_calibration_symlink.exists() or self.current_calibration_symlink.is_symlink(): + self.current_calibration_symlink.unlink() + except Exception as exc: # noqa: BLE001 + logger.warning("Failed to remove existing current_calibration link", error=repr(exc)) - self.current_calibration_symlink.symlink_to(relative_path) + try: + # Create a relative link when possible to keep the tree portable + relative = calib_dir + try: + relative = calib_dir.relative_to(self.calibration_dir) + except ValueError: + pass + self.current_calibration_symlink.symlink_to(relative) + logger.info("Current calibration set", preset=preset.filename, name=calibration_name) + except Exception as exc: # noqa: BLE001 + logger.error("Failed to create current_calibration symlink", error=repr(exc)) + raise def get_current_calibration(self, current_preset: ConfigPreset) -> CalibrationSet | None: - """Get currently selected calibration as CalibrationSet""" + """ + Resolve and load the calibration currently pointed to by the symlink. + + Returns None if the link doesn't exist, points to an invalid location, + or targets a different preset. + """ if not self.current_calibration_symlink.exists(): return None try: target = self.current_calibration_symlink.resolve() calibration_name = target.name - preset_name = target.parent.name + preset_dir_name = target.parent.name # (without .bin) - # If current_preset matches, use it - if current_preset.filename == f"{preset_name}.bin": - return self.load_calibration_set(current_preset, calibration_name) - else: - raise RuntimeError("Current calibration is set and is meant for different preset.") + expected_preset_name = current_preset.filename.replace(".bin", "") + if preset_dir_name != expected_preset_name: + logger.warning( + "Current calibration preset mismatch", + expected=expected_preset_name, + actual=preset_dir_name, + ) + raise RuntimeError("Current calibration belongs to a different preset") - except Exception: + return self.load_calibration_set(current_preset, calibration_name) + except Exception as exc: # noqa: BLE001 + logger.warning("Failed to resolve current calibration", error=repr(exc)) return None - def clear_current_calibration(self): - """Clear current calibration symlink""" + def clear_current_calibration(self) -> None: + """Remove the current calibration symlink.""" if self.current_calibration_symlink.exists() or self.current_calibration_symlink.is_symlink(): - self.current_calibration_symlink.unlink() - - def delete_calibration(self, preset: ConfigPreset, calibration_name: str): - """Delete calibration set""" - preset_dir = self._get_preset_calibration_dir(preset) - calib_dir = preset_dir / calibration_name + try: + self.current_calibration_symlink.unlink() + logger.info("Current calibration cleared") + except Exception as exc: # noqa: BLE001 + logger.warning("Failed to clear current calibration", error=repr(exc)) + # ------------------------------------------------------------------ # + # Deletion + # ------------------------------------------------------------------ # + def delete_calibration(self, preset: ConfigPreset, calibration_name: str) -> None: + """Delete a calibration set directory.""" + calib_dir = self._get_preset_calibration_dir(preset) / calibration_name if calib_dir.exists(): shutil.rmtree(calib_dir) + logger.info("Calibration deleted", preset=preset.filename, name=calibration_name) + # ------------------------------------------------------------------ # + # Helpers + # ------------------------------------------------------------------ # def _get_preset_calibration_dir(self, preset: ConfigPreset) -> Path: - """Get calibration directory for specific preset""" - preset_dir = self.calibration_dir / preset.filename.replace('.bin', '') + """Return the directory where calibrations for this preset are stored.""" + preset_dir = self.calibration_dir / preset.filename.replace(".bin", "") preset_dir.mkdir(parents=True, exist_ok=True) return preset_dir - def _get_required_standards(self, mode: VNAMode) -> List[CalibrationStandard]: - """Get required calibration standards for VNA mode""" + def _get_required_standards(self, mode: VNAMode) -> list[CalibrationStandard]: + """Standards required for a given VNA mode.""" if mode == VNAMode.S11: return [CalibrationStandard.OPEN, CalibrationStandard.SHORT, CalibrationStandard.LOAD] - elif mode == VNAMode.S21: + if mode == VNAMode.S21: return [CalibrationStandard.THROUGH] - return [] \ No newline at end of file + return [] + + @staticmethod + def _atomic_json_write(path: Path, payload: dict) -> None: + """Write JSON atomically via a temporary sidecar file.""" + tmp = path.with_suffix(path.suffix + ".tmp") + tmp.write_text(json.dumps(payload, indent=2, ensure_ascii=False), encoding="utf-8") + tmp.replace(path) diff --git a/vna_system/core/settings/preset_manager.py b/vna_system/core/settings/preset_manager.py index 56a95ef..cfaccb4 100644 --- a/vna_system/core/settings/preset_manager.py +++ b/vna_system/core/settings/preset_manager.py @@ -1,21 +1,40 @@ -from __future__ import annotations - import re from dataclasses import dataclass from enum import Enum from pathlib import Path -from typing import List from vna_system.core import config as cfg +from vna_system.core.logging.logger import get_component_logger + +logger = get_component_logger(__file__) class VNAMode(Enum): + """Supported VNA measurement modes.""" S11 = "s11" S21 = "s21" -@dataclass +@dataclass(slots=True) class ConfigPreset: + """ + Parsed configuration preset derived from a filename. + + Fields + ------ + filename: + Original filename (e.g., 's11_start100_stop8800_points1000_bw1khz.bin'). + mode: + VNA mode (S11 or S21). + start_freq: + Start frequency in Hz (None if not provided in the filename). + stop_freq: + Stop frequency in Hz (None if not provided in the filename). + points: + Number of sweep points (None if not provided). + bandwidth: + IF bandwidth in Hz (None if not provided). + """ filename: str mode: VNAMode start_freq: float | None = None @@ -25,105 +44,187 @@ class ConfigPreset: class PresetManager: - def __init__(self, binary_input_dir: Path | None = None): - self.binary_input_dir = Path(binary_input_dir or cfg.BASE_DIR / "vna_system" / "binary_input") + """ + Discover, parse, and manage configuration presets stored on disk. + + Directory layout + ---------------- + /vna_system/binary_input/ + ├─ config_inputs/ + │ └─ *.bin (preset files; configuration encoded in filename) + └─ current_input.bin -> config_inputs/.bin + + Filenames encode parameters, e.g.: + s11_start100_stop8800_points1000_bw1khz.bin + s21_start0.1ghz_stop3.0ghz_points1001_bw10kHz.bin + + Parsing rules + ------------- + - Mode must be the prefix: 's11' or 's21' + - start/stop: numbers with optional unit suffix (hz|khz|mhz|ghz). If no suffix, defaults to MHz. + - points: integer (points or point also accepted) + - bw: number with optional unit suffix (hz|khz|mhz). Defaults to Hz if absent. + """ + + def __init__(self, binary_input_dir: Path | None = None) -> None: + self.binary_input_dir = Path(binary_input_dir or (cfg.BASE_DIR / "vna_system" / "binary_input")) self.config_inputs_dir = self.binary_input_dir / "config_inputs" self.current_input_symlink = self.binary_input_dir / "current_input.bin" self.config_inputs_dir.mkdir(parents=True, exist_ok=True) + logger.debug( + "PresetManager initialized", + binary_input=str(self.binary_input_dir), + config_inputs=str(self.config_inputs_dir), + ) - def _parse_filename(self, filename: str) -> ConfigPreset | None: - """Parse configuration parameters from filename like s11_start100_stop8800_points1000_bw1khz.bin""" - base_name = Path(filename).stem.lower() + # ------------------------------------------------------------------ # + # Parsing + # ------------------------------------------------------------------ # + def _parse_filename(self, filename: str) -> ConfigPreset | None: # type: ignore[name-defined] + """ + Parse configuration parameters from a preset filename. - # Extract mode - must be at the beginning - mode = None - if base_name.startswith('s11'): + Accepted fragments (case-insensitive): + - ^s11 or ^s21 + - start + - stop + - points? + - bw + + Units + ----- + - For start/stop: hz|khz|mhz|ghz (default: MHz when absent) + - For bw: hz|khz|mhz (default: Hz when absent) + """ + base = Path(filename).stem.lower() + + # Mode at the beginning + if base.startswith("s11"): mode = VNAMode.S11 - elif base_name.startswith('s21'): + elif base.startswith("s21"): mode = VNAMode.S21 else: + logger.debug("Filename does not start with mode token", filename=filename) return None preset = ConfigPreset(filename=filename, mode=mode) - # Extract parameters using regex - patterns = { - 'start': r'start(\d+(?:\.\d+)?)', - 'stop': r'stop(\d+(?:\.\d+)?)', - 'points': r'points?(\d+)', - 'bw': r'bw(\d+(?:\.\d+)?)(hz|khz|mhz)?' - } + # Patterns with optional unit suffixes + pat_start = r"start(?P\d+(?:\.\d+)?)(?Phz|khz|mhz|ghz)?" + pat_stop = r"stop(?P\d+(?:\.\d+)?)(?Phz|khz|mhz|ghz)?" + pat_points = r"points?(?P\d+)" + pat_bw = r"bw(?P\d+(?:\.\d+)?)(?Phz|khz|mhz)?" - for param, pattern in patterns.items(): - match = re.search(pattern, base_name) - if match: - value = float(match.group(1)) + def _match(pattern: str) -> re.Match[str] | None: + return re.search(pattern, base, flags=re.IGNORECASE) - if param == 'start': - # Assume MHz if no unit specified - preset.start_freq = value * 1e6 - elif param == 'stop': - # Assume MHz if no unit specified - preset.stop_freq = value * 1e6 - elif param == 'points': - preset.points = int(value) - elif param == 'bw': - unit = match.group(2) if len(match.groups()) > 1 and match.group(2) else 'hz' - if unit == 'khz': - value *= 1e3 - elif unit == 'mhz': - value *= 1e6 - # hz is base unit, no multiplication needed - preset.bandwidth = value + m = _match(pat_start) + if m: + preset.start_freq = self._to_hz(float(m.group("val")), (m.group("unit") or "mhz")) + m = _match(pat_stop) + if m: + preset.stop_freq = self._to_hz(float(m.group("val")), (m.group("unit") or "mhz")) + + m = _match(pat_points) + if m: + preset.points = int(m.group("val")) + + m = _match(pat_bw) + if m: + preset.bandwidth = self._to_hz(float(m.group("val")), (m.group("unit") or "hz")) + + logger.debug( + "Preset filename parsed", + filename=filename, + start=preset.start_freq, + stop=preset.stop_freq, + points=preset.points, + bw=preset.bandwidth, + ) return preset - def get_available_presets(self) -> List[ConfigPreset]: - """Return list of all available configuration presets""" - presets = [] + @staticmethod + def _to_hz(value: float, unit: str) -> float: + """Convert a numeric value with textual unit into Hz.""" + u = unit.lower() + if u == "hz": + return value + if u == "khz": + return value * 1e3 + if u == "mhz": + return value * 1e6 + if u == "ghz": + return value * 1e9 + # Fallback: treat as Hz if unknown + return value + # ------------------------------------------------------------------ # + # Discovery & selection + # ------------------------------------------------------------------ # + def get_available_presets(self) -> list[ConfigPreset]: + """ + Return a list of available presets discovered in `config_inputs_dir`. + + Only files that parse successfully are returned. + """ + presets: list[ConfigPreset] = [] if not self.config_inputs_dir.exists(): return presets - for file_path in self.config_inputs_dir.glob("*.bin"): - preset = self._parse_filename(file_path.name) - if preset is not None: - presets.append(preset) - return sorted(presets, key=lambda x: x.filename) + for path in self.config_inputs_dir.glob("*.bin"): + p = self._parse_filename(path.name) + if p is not None: + presets.append(p) + + presets.sort(key=lambda x: x.filename.lower()) + logger.debug("Available presets enumerated", count=len(presets)) + return presets def set_current_preset(self, preset: ConfigPreset) -> ConfigPreset: - """Set current configuration by creating symlink to specified preset""" - preset_path = self.config_inputs_dir / preset.filename - - if not preset_path.exists(): + """ + Select a preset by (re)pointing `current_input.bin` to the chosen file. + """ + src = self.config_inputs_dir / preset.filename + if not src.exists(): raise FileNotFoundError(f"Preset file not found: {preset.filename}") - # Remove existing symlink if present + # Remove any existing link/file if self.current_input_symlink.exists() or self.current_input_symlink.is_symlink(): - self.current_input_symlink.unlink() + try: + self.current_input_symlink.unlink() + except Exception as exc: # noqa: BLE001 + logger.warning("Failed to remove existing current_input.bin", error=repr(exc)) - # Create new symlink + # Prefer a relative symlink for portability try: - relative_path = preset_path.relative_to(self.binary_input_dir) + target = src.relative_to(self.binary_input_dir) except ValueError: - relative_path = preset_path - - self.current_input_symlink.symlink_to(relative_path) + target = src + self.current_input_symlink.symlink_to(target) + logger.info("Current preset set", filename=preset.filename) return preset def get_current_preset(self) -> ConfigPreset | None: - """Get currently selected configuration preset""" + """ + Resolve the `current_input.bin` symlink and parse the underlying preset. + + Returns None if the symlink is missing or the filename cannot be parsed. + """ if not self.current_input_symlink.exists(): return None try: target = self.current_input_symlink.resolve() return self._parse_filename(target.name) - except Exception: + except Exception as exc: # noqa: BLE001 + logger.warning("Failed to resolve current preset", error=repr(exc)) return None def preset_exists(self, preset: ConfigPreset) -> bool: - """Check if preset file exists""" - return (self.config_inputs_dir / preset.filename).exists() \ No newline at end of file + """Return True if the underlying file for `preset` exists.""" + exists = (self.config_inputs_dir / preset.filename).exists() + logger.debug("Preset existence checked", filename=preset.filename, exists=exists) + return exists diff --git a/vna_system/core/settings/settings_manager.py b/vna_system/core/settings/settings_manager.py index e53ba15..8e8d900 100644 --- a/vna_system/core/settings/settings_manager.py +++ b/vna_system/core/settings/settings_manager.py @@ -1,124 +1,194 @@ -from __future__ import annotations - -import logging from pathlib import Path -from typing import Dict, List +from typing import Any from vna_system.core import config as cfg +from vna_system.core.logging.logger import get_component_logger +from vna_system.core.acquisition.data_acquisition import VNADataAcquisition from vna_system.core.acquisition.sweep_buffer import SweepData -from .preset_manager import PresetManager, ConfigPreset, VNAMode -from .calibration_manager import CalibrationManager, CalibrationSet, CalibrationStandard +from vna_system.core.settings.preset_manager import PresetManager, ConfigPreset, VNAMode +from vna_system.core.settings.calibration_manager import ( + CalibrationManager, + CalibrationSet, + CalibrationStandard, +) -logger = logging.getLogger(__name__) +logger = get_component_logger(__file__) class VNASettingsManager: """ - Main settings manager that coordinates preset and calibration management. + High-level coordinator for presets and calibrations. - Provides high-level interface for: - - Managing configuration presets - - Managing calibration data - - Coordinating between preset selection and calibration + Responsibilities + ---------------- + • Discover/select configuration presets (via `PresetManager`). + • Create/store/select calibration sets (via `CalibrationManager`). + • Provide combined status used by API/UI. + • Offer helpers to capture calibration directly from acquisition. + + Notes + ----- + - All IO paths are derived from `cfg.BASE_DIR`. + - Logging is performed via the project logger. """ - def __init__(self, base_dir: Path | None = None): + def __init__(self, base_dir: Path | None = None) -> None: self.base_dir = Path(base_dir or cfg.BASE_DIR) - # Initialize sub-managers + # Sub-managers self.preset_manager = PresetManager(self.base_dir / "binary_input") self.calibration_manager = CalibrationManager(self.base_dir) - # ---------- Preset Management ---------- + logger.debug( + "VNASettingsManager initialized", + base_dir=str(self.base_dir), + ) - def get_available_presets(self) -> List[ConfigPreset]: - """Get all available configuration presets""" + # ------------------------------------------------------------------ # + # Preset Management + # ------------------------------------------------------------------ # + def get_available_presets(self) -> list[ConfigPreset]: + """Return all available configuration presets.""" return self.preset_manager.get_available_presets() - def get_presets_by_mode(self, mode: VNAMode) -> List[ConfigPreset]: - """Get presets filtered by VNA mode""" - all_presets = self.get_available_presets() - return [p for p in all_presets if p.mode == mode] + def get_presets_by_mode(self, mode: VNAMode) -> list[ConfigPreset]: + """Return presets filtered by VNA mode.""" + return [p for p in self.get_available_presets() if p.mode == mode] def set_current_preset(self, preset: ConfigPreset) -> ConfigPreset: - """Set current configuration preset""" - return self.preset_manager.set_current_preset(preset) + """Set the current configuration preset (updates the symlink).""" + chosen = self.preset_manager.set_current_preset(preset) + logger.info("Current preset selected", filename=chosen.filename, mode=chosen.mode.value) + return chosen def get_current_preset(self) -> ConfigPreset | None: - """Get currently selected preset""" + """Return the currently selected preset, or None if not set.""" return self.preset_manager.get_current_preset() - # ---------- Calibration Management ---------- - + # ------------------------------------------------------------------ # + # Calibration Management + # ------------------------------------------------------------------ # def start_new_calibration(self, preset: ConfigPreset | None = None) -> CalibrationSet: - """Start new calibration for current or specified preset""" + """ + Begin a new in-memory calibration session for a preset. + + If `preset` is omitted, the current preset must be set. + """ + preset = preset or self.get_current_preset() if preset is None: - preset = self.get_current_preset() - if preset is None: - raise RuntimeError("No current preset selected") - - return self.calibration_manager.start_new_calibration(preset) + raise RuntimeError("No current preset selected") + calib = self.calibration_manager.start_new_calibration(preset) + logger.info("Calibration session started", preset=preset.filename, mode=preset.mode.value) + return calib def get_current_working_calibration(self) -> CalibrationSet | None: - """Get current working calibration set (in-progress, not yet saved)""" + """Return the in-progress (unsaved) calibration set, if any.""" return self.calibration_manager.get_current_working_set() - def add_calibration_standard(self, standard: CalibrationStandard, sweep_data: SweepData): - """Add calibration standard to current working set""" + def add_calibration_standard(self, standard: CalibrationStandard, sweep_data: SweepData) -> None: + """Add a standard measurement to the working calibration set.""" self.calibration_manager.add_calibration_standard(standard, sweep_data) + logger.info( + "Calibration standard added", + standard=standard.value, + sweep_number=sweep_data.sweep_number, + points=sweep_data.total_points, + ) - def remove_calibration_standard(self, standard: CalibrationStandard): - """Remove calibration standard from current working set""" + def remove_calibration_standard(self, standard: CalibrationStandard) -> None: + """Remove a standard measurement from the working calibration set.""" self.calibration_manager.remove_calibration_standard(standard) + logger.info("Calibration standard removed", standard=standard.value) def save_calibration_set(self, calibration_name: str) -> CalibrationSet: - """Save current working calibration set""" - return self.calibration_manager.save_calibration_set(calibration_name) + """Persist the current working calibration set to disk.""" + saved = self.calibration_manager.save_calibration_set(calibration_name) + logger.info("Calibration set saved", name=calibration_name, preset=saved.preset.filename) + return saved - def get_available_calibrations(self, preset: ConfigPreset | None = None) -> List[str]: - """Get available calibrations for current or specified preset""" + def get_available_calibrations(self, preset: ConfigPreset | None = None) -> list[str]: + """List available calibration set names for a preset (current if omitted).""" + preset = preset or self.get_current_preset() if preset is None: - preset = self.get_current_preset() - if preset is None: - return [] - + return [] return self.calibration_manager.get_available_calibrations(preset) - def set_current_calibration(self, calibration_name: str, preset: ConfigPreset | None = None): - """Set current calibration""" + def set_current_calibration(self, calibration_name: str, preset: ConfigPreset | None = None) -> None: + """Activate a calibration set by updating the symlink.""" + preset = preset or self.get_current_preset() if preset is None: - preset = self.get_current_preset() - if preset is None: - raise RuntimeError("No current preset selected") - + raise RuntimeError("No current preset selected") self.calibration_manager.set_current_calibration(preset, calibration_name) + logger.info("Current calibration set", name=calibration_name, preset=preset.filename) def get_current_calibration(self) -> CalibrationSet | None: - """Get currently selected calibration set (saved and active via symlink)""" - current_preset = self.get_current_preset() - if current_preset is not None: - return self.calibration_manager.get_current_calibration(current_preset) - else: + """ + Return the active (saved and selected) calibration set for the current preset, + or None if not set/invalid. + """ + current = self.get_current_preset() + if current is None: return None + return self.calibration_manager.get_current_calibration(current) - def get_calibration_info(self, calibration_name: str, preset: ConfigPreset | None = None) -> Dict: - """Get calibration information""" + def get_calibration_info(self, calibration_name: str, preset: ConfigPreset | None = None) -> dict[str, Any]: + """Return info/metadata for a specific calibration set.""" + preset = preset or self.get_current_preset() if preset is None: - preset = self.get_current_preset() - if preset is None: - raise RuntimeError("No current preset selected") - + raise RuntimeError("No current preset selected") return self.calibration_manager.get_calibration_info(preset, calibration_name) - # ---------- Combined Status and UI helpers ---------- + @staticmethod + def get_required_standards(mode: VNAMode) -> list[CalibrationStandard]: + """Return the list of required standards for a given VNA mode.""" + if mode == VNAMode.S11: + return [CalibrationStandard.OPEN, CalibrationStandard.SHORT, CalibrationStandard.LOAD] + if mode == VNAMode.S21: + return [CalibrationStandard.THROUGH] + return [] - def get_status_summary(self) -> Dict[str, object]: + # ------------------------------------------------------------------ # + # Acquisition integration + # ------------------------------------------------------------------ # + def capture_calibration_standard_from_acquisition( + self, + standard: CalibrationStandard, + data_acquisition: VNADataAcquisition, + ) -> int: + """ + Capture the latest sweep from acquisition as a calibration standard. + + Returns + ------- + int + The sweep number captured. + + Raises + ------ + RuntimeError + If no sweep is available in the acquisition buffer. + """ + latest = data_acquisition.sweep_buffer.get_latest_sweep() + if latest is None: + raise RuntimeError("No sweep data available in acquisition buffer") + + self.add_calibration_standard(standard, latest) + logger.info( + "Captured calibration standard from acquisition", + standard=standard.value, + sweep_number=latest.sweep_number, + ) + return latest.sweep_number + + def get_status_summary(self) -> dict[str, object]: """Get comprehensive status of current configuration and calibration""" current_preset = self.get_current_preset() current_calibration = self.get_current_calibration() working_calibration = self.get_current_working_calibration() - + + logger.info(f"Settings status requested") + summary = { "current_preset": None, "current_calibration": None, @@ -153,28 +223,4 @@ class VNASettingsManager: "missing_standards": [s.value for s in working_calibration.get_missing_standards()] } - return summary - - @staticmethod - def get_required_standards(mode: VNAMode) -> List[CalibrationStandard]: - """Get required calibration standards for VNA mode""" - if mode == VNAMode.S11: - return [CalibrationStandard.OPEN, CalibrationStandard.SHORT, CalibrationStandard.LOAD] - elif mode == VNAMode.S21: - return [CalibrationStandard.THROUGH] - return [] - - # ---------- Integration with VNADataAcquisition ---------- - - def capture_calibration_standard_from_acquisition(self, standard: CalibrationStandard, data_acquisition): - """Capture calibration standard from VNADataAcquisition instance""" - # Get latest sweep from acquisition - latest_sweep = data_acquisition._sweep_buffer.get_latest_sweep() - if latest_sweep is None: - raise RuntimeError("No sweep data available in acquisition buffer") - - # Add to current working calibration - self.add_calibration_standard(standard, latest_sweep) - - logger.info(f"Captured {standard.value} calibration standard from sweep {latest_sweep.sweep_number}") - return latest_sweep.sweep_number \ No newline at end of file + return summary \ No newline at end of file diff --git a/vna_system/core/singletons.py b/vna_system/core/singletons.py index 80be95e..c712912 100644 --- a/vna_system/core/singletons.py +++ b/vna_system/core/singletons.py @@ -11,14 +11,14 @@ from vna_system.core.processors.storage.data_storage import DataStorage from vna_system.core.settings.settings_manager import VNASettingsManager from vna_system.core.processors.manager import ProcessorManager from vna_system.core.processors.websocket_handler import ProcessorWebSocketHandler +from vna_system.core.config import PROCESSORS_CONFIG_DIR_PATH # Global singleton instances vna_data_acquisition_instance: VNADataAcquisition = VNADataAcquisition() settings_manager: VNASettingsManager = VNASettingsManager() # Processor system -processor_config_dir = Path("vna_system/core/processors/configs") -processor_manager: ProcessorManager = ProcessorManager(vna_data_acquisition_instance.sweep_buffer, settings_manager, processor_config_dir) +processor_manager: ProcessorManager = ProcessorManager(vna_data_acquisition_instance.sweep_buffer, settings_manager, Path(PROCESSORS_CONFIG_DIR_PATH)) data_storage = DataStorage() processor_websocket_handler: ProcessorWebSocketHandler = ProcessorWebSocketHandler( processor_manager, data_storage diff --git a/vna_system/core/visualization/magnitude_chart.py b/vna_system/core/visualization/magnitude_chart.py index b6c52e4..e0a5033 100644 --- a/vna_system/core/visualization/magnitude_chart.py +++ b/vna_system/core/visualization/magnitude_chart.py @@ -1,264 +1,292 @@ -import numpy as np -from typing import Dict, Any, List, Tuple -import json from pathlib import Path +import json +from typing import Any +import numpy as np + +from vna_system.core.logging.logger import get_component_logger from vna_system.core.acquisition.sweep_buffer import SweepData from vna_system.core.settings.preset_manager import ConfigPreset +logger = get_component_logger(__file__) -def generate_magnitude_plot_from_sweep_data(sweep_data: SweepData, preset: ConfigPreset = None) -> Dict[str, Any]: + +# ----------------------------------------------------------------------------- +# Plot builders +# ----------------------------------------------------------------------------- +def generate_magnitude_plot_from_sweep_data( + sweep_data: SweepData, + preset: ConfigPreset | None = None, +) -> dict[str, Any]: """ - Generate Plotly configuration for magnitude plot from SweepData + Build a Plotly configuration for magnitude-vs-frequency from a `SweepData`. - Args: - sweep_data: SweepData instance with points list of [real, imag] complex pairs - preset: Optional ConfigPreset with frequency info + Parameters + ---------- + sweep_data + Sweep payload with `.points: list[tuple[float, float]]` of (real, imag). + preset + Optional preset carrying frequency range (Hz). If absent, defaults are used. - Returns: - Plotly configuration dict for magnitude plot + Returns + ------- + dict[str, Any] + Plotly figure spec. If input is invalid, returns {"error": "..."}. """ if not sweep_data or not sweep_data.points: - return {'error': 'Invalid sweep data'} + logger.warning("Invalid sweep passed to magnitude plot") + return {"error": "Invalid sweep data"} - # Extract frequency range from preset or use defaults - start_freq = 100e6 # 100 MHz - stop_freq = 8.8e9 # 8.8 GHz + # Frequency range (Hz) + start_freq = float(preset.start_freq) if (preset and preset.start_freq is not None) else 100e6 + stop_freq = float(preset.stop_freq) if (preset and preset.stop_freq is not None) else 8.8e9 - if preset: - start_freq = preset.start_freq or start_freq - stop_freq = preset.stop_freq or stop_freq + n = len(sweep_data.points) + if n == 1: + freqs = [start_freq] + else: + step = (stop_freq - start_freq) / max(1, n - 1) + freqs = [start_freq + i * step for i in range(n)] - frequencies = [] - magnitudes_db = [] + # Magnitudes (dB). Clamp zero magnitude to -120 dB to avoid -inf. + mags_db: list[float] = [] + for real, imag in sweep_data.points: + mag = abs(complex(real, imag)) + mags_db.append(20.0 * np.log10(mag) if mag > 0.0 else -120.0) - # Calculate magnitude in dB for each point - for i, (real, imag) in enumerate(sweep_data.points): - complex_val = complex(real, imag) - magnitude_db = 20 * np.log10(abs(complex_val)) if abs(complex_val) > 0 else -120 + # Reasonable Y range with margin + ymin = float(min(mags_db)) + ymax = float(max(mags_db)) + ymargin = (ymax - ymin) * 0.1 if ymax > ymin else 10.0 + y_min = max(ymin - ymargin, -120.0) + y_max = min(ymax + ymargin, 20.0) - # Calculate frequency based on point index - total_points = len(sweep_data.points) - frequency = start_freq + (stop_freq - start_freq) * i / (total_points - 1) - - frequencies.append(frequency) - magnitudes_db.append(magnitude_db) - - # Create Plotly trace trace = { - 'x': [f / 1e9 for f in frequencies], # Convert to GHz - 'y': magnitudes_db, - 'type': 'scatter', - 'mode': 'lines', - 'name': 'Magnitude', - 'line': {'color': '#1f77b4', 'width': 2} + "x": [f / 1e9 for f in freqs], # Hz -> GHz + "y": mags_db, + "type": "scatter", + "mode": "lines", + "name": "Magnitude", + "line": {"color": "#1f77b4", "width": 2}, } - # Calculate reasonable Y-axis range - min_mag = min(magnitudes_db) - max_mag = max(magnitudes_db) - y_margin = (max_mag - min_mag) * 0.1 - y_min = max(min_mag - y_margin, -120) - y_max = min(max_mag + y_margin, 20) - - return { - 'data': [trace], - 'layout': { - 'title': 'Magnitude Response', - 'xaxis': { - 'title': 'Frequency (GHz)', - 'showgrid': True, - 'gridcolor': '#e5e5e5', - 'gridwidth': 1 + fig = { + "data": [trace], + "layout": { + "title": "Magnitude Response", + "xaxis": { + "title": "Frequency (GHz)", + "showgrid": True, + "gridcolor": "#e5e5e5", + "gridwidth": 1, }, - 'yaxis': { - 'title': 'Magnitude (dB)', - 'range': [y_min, y_max], - 'showgrid': True, - 'gridcolor': '#e5e5e5', - 'gridwidth': 1 + "yaxis": { + "title": "Magnitude (dB)", + "range": [y_min, y_max], + "showgrid": True, + "gridcolor": "#e5e5e5", + "gridwidth": 1, }, - 'plot_bgcolor': '#fafafa', - 'paper_bgcolor': '#ffffff', - 'font': { - 'family': 'Arial, sans-serif', - 'size': 12, - 'color': '#333333' - }, - 'hovermode': 'x unified', - 'showlegend': True, - 'margin': {'l': 60, 'r': 40, 't': 60, 'b': 60} - } + "plot_bgcolor": "#fafafa", + "paper_bgcolor": "#ffffff", + "font": {"family": "Arial, sans-serif", "size": 12, "color": "#333333"}, + "hovermode": "x unified", + "showlegend": True, + "margin": {"l": 60, "r": 40, "t": 60, "b": 60}, + }, } + logger.debug("Magnitude plot generated", points=n) + return fig +# ----------------------------------------------------------------------------- +# IO helpers +# ----------------------------------------------------------------------------- def load_sweep_data_from_json(json_file: Path) -> SweepData: """ - Load SweepData from JSON file + Load a `SweepData` structure from a JSON file. - Args: - json_file: Path to JSON file containing sweep data + The file is expected to contain: + { "sweep_number": int, "timestamp": float, "points": [[r, i], ...], "total_points": int } - Returns: - SweepData instance + If `total_points` is missing, it is derived from the length of `points`. """ - with open(json_file, 'r') as f: - data = json.load(f) + data = json.loads(Path(json_file).read_text(encoding="utf-8")) - return SweepData( - sweep_number=data.get('sweep_number', 0), - timestamp=data.get('timestamp', 0.0), - points=data.get('points', []), - total_points=data.get('total_points', len(data.get('points', []))) + points = data.get("points", []) + if not isinstance(points, list): + raise ValueError(f"Invalid 'points' in file: {json_file}") + + # Normalize to list[tuple[float, float]] + norm_points: list[tuple[float, float]] = [] + for pt in points: + if not (isinstance(pt, (list, tuple)) and len(pt) == 2): + raise ValueError(f"Invalid point format in {json_file}: {pt!r}") + r, i = pt + norm_points.append((float(r), float(i))) + + sweep = SweepData( + sweep_number=int(data.get("sweep_number", 0)), + timestamp=float(data.get("timestamp", 0.0)), + points=norm_points, + total_points=int(data.get("total_points", len(norm_points))), ) + return sweep -def generate_standards_magnitude_plots(calibration_path: Path, preset: ConfigPreset = None) -> Dict[str, Any]: +# ----------------------------------------------------------------------------- +# Calibration plots +# ----------------------------------------------------------------------------- +def generate_standards_magnitude_plots( + calibration_path: Path, + preset: ConfigPreset | None = None, +) -> dict[str, Any]: """ - Generate magnitude plots for all calibration standards in a calibration set + Build individual magnitude plots for all calibration standards found under a folder. - Args: - calibration_path: Path to calibration directory - preset: Optional ConfigPreset + The function scans `calibration_path` for `*.json` (ignoring `*metadata.json`), loads each + sweep, and produces a Plotly config per standard. Raw sweep data and (optional) frequency + info are embedded into the output for convenience. - Returns: - Dictionary with plots for each standard, including raw data + Returns + ------- + dict[str, Any] + { "": , ... } """ - plots = {} + plots: dict[str, Any] = {} + standard_colors = { - 'open': '#2ca02c', # Green - 'short': '#d62728', # Red - 'load': '#ff7f0e', # Orange - 'through': '#1f77b4' # Blue + "open": "#2ca02c", # Green + "short": "#d62728", # Red + "load": "#ff7f0e", # Orange + "through": "#1f77b4", # Blue } - # Find all standard JSON files - for standard_file in calibration_path.glob('*.json'): + for standard_file in Path(calibration_path).glob("*.json"): standard_name = standard_file.stem - - # Skip metadata files - if 'metadata' in standard_name: + if "metadata" in standard_name: continue try: - sweep_data = load_sweep_data_from_json(standard_file) - plot_config = generate_magnitude_plot_from_sweep_data(sweep_data, preset) + sweep = load_sweep_data_from_json(standard_file) + fig = generate_magnitude_plot_from_sweep_data(sweep, preset) - if 'error' not in plot_config: - # Customize color and title for this standard - if plot_config.get('data'): - plot_config['data'][0]['line']['color'] = standard_colors.get(standard_name, '#1f77b4') - plot_config['data'][0]['name'] = f'{standard_name.upper()} Standard' - plot_config['layout']['title'] = f'{standard_name.upper()} Standard Magnitude' + if "error" in fig: + plots[standard_name] = fig + continue - # Include raw sweep data for download - plot_config['raw_sweep_data'] = { - 'sweep_number': sweep_data.sweep_number, - 'timestamp': sweep_data.timestamp, - 'total_points': sweep_data.total_points, - 'points': sweep_data.points, # Raw complex data points - 'file_path': str(standard_file) + # Customize per-standard appearance/title + if fig.get("data"): + fig["data"][0]["line"]["color"] = standard_colors.get(standard_name, "#1f77b4") + fig["data"][0]["name"] = f"{standard_name.upper()} Standard" + fig["layout"]["title"] = f"{standard_name.upper()} Standard Magnitude" + + # Attach raw sweep block for UI download/inspection + fig["raw_sweep_data"] = { + "sweep_number": sweep.sweep_number, + "timestamp": sweep.timestamp, + "total_points": sweep.total_points, + "points": sweep.points, + "file_path": str(standard_file), + } + + # Optional frequency info + if preset: + fig["frequency_info"] = { + "start_freq": preset.start_freq, + "stop_freq": preset.stop_freq, + "points": preset.points, + "bandwidth": preset.bandwidth, } - # Add frequency information if available - if preset: - plot_config['frequency_info'] = { - 'start_freq': preset.start_freq, - 'stop_freq': preset.stop_freq, - 'points': preset.points, - 'bandwidth': preset.bandwidth - } + plots[standard_name] = fig - plots[standard_name] = plot_config - except (json.JSONDecodeError, FileNotFoundError, KeyError) as e: - plots[standard_name] = {'error': f'Failed to load {standard_name}: {str(e)}'} + except (json.JSONDecodeError, FileNotFoundError, KeyError, ValueError) as exc: + logger.warning("Failed to load standard plot", file=str(standard_file), error=repr(exc)) + plots[standard_name] = {"error": f"Failed to load {standard_name}: {exc}"} return plots -def generate_combined_standards_plot(calibration_path: Path, preset: ConfigPreset = None) -> Dict[str, Any]: +def generate_combined_standards_plot( + calibration_path: Path, + preset: ConfigPreset | None = None, +) -> dict[str, Any]: """ - Generate a combined plot showing all calibration standards + Build a combined Plotly figure that overlays all available calibration standards. - Args: - calibration_path: Path to calibration directory - preset: Optional ConfigPreset - - Returns: - Plotly configuration dict with all standards overlaid + Each standard is rendered as a separate trace with a canonical color. """ - traces = [] + traces: list[dict[str, Any]] = [] standard_colors = { - 'open': '#2ca02c', # Green - 'short': '#d62728', # Red - 'load': '#ff7f0e', # Orange - 'through': '#1f77b4' # Blue + "open": "#2ca02c", # Green + "short": "#d62728", # Red + "load": "#ff7f0e", # Orange + "through": "#1f77b4", # Blue } - y_min, y_max = 0, -120 + # Initialize Y range trackers inversely so first update sets them correctly. + y_min, y_max = 0.0, -120.0 - # Process each standard - for standard_file in calibration_path.glob('*.json'): - standard_name = standard_file.stem - - # Skip metadata files - if 'metadata' in standard_name: + for standard_file in Path(calibration_path).glob("*.json"): + name = standard_file.stem + if "metadata" in name: continue try: - sweep_data = load_sweep_data_from_json(standard_file) - plot_config = generate_magnitude_plot_from_sweep_data(sweep_data, preset) + sweep = load_sweep_data_from_json(standard_file) + fig = generate_magnitude_plot_from_sweep_data(sweep, preset) + if "error" in fig or not fig.get("data"): + continue - if 'error' not in plot_config and plot_config.get('data'): - trace = plot_config['data'][0].copy() - trace['line']['color'] = standard_colors.get(standard_name, '#1f77b4') - trace['name'] = f'{standard_name.upper()} Standard' - traces.append(trace) + trace = dict(fig["data"][0]) # shallow copy + trace["line"]["color"] = standard_colors.get(name, "#1f77b4") + trace["name"] = f"{name.upper()} Standard" + traces.append(trace) - # Update Y range - if trace['y']: - trace_min = min(trace['y']) - trace_max = max(trace['y']) - y_min = min(y_min, trace_min) - y_max = max(y_max, trace_max) + # Update Y range + y_vals = trace.get("y") or [] + if y_vals: + tmin = float(min(y_vals)) + tmax = float(max(y_vals)) + y_min = min(y_min, tmin) + y_max = max(y_max, tmax) - except (json.JSONDecodeError, FileNotFoundError, KeyError): + except (json.JSONDecodeError, FileNotFoundError, KeyError, ValueError) as exc: + logger.warning("Failed to include standard in combined plot", file=str(standard_file), error=repr(exc)) continue if not traces: - return {'error': 'No valid calibration standards found'} + return {"error": "No valid calibration standards found"} - # Add margin to Y range - y_margin = (y_max - y_min) * 0.1 - y_min = max(y_min - y_margin, -120) - y_max = min(y_max + y_margin, 20) + ymargin = (y_max - y_min) * 0.1 if y_max > y_min else 10.0 + y_min = max(y_min - ymargin, -120.0) + y_max = min(y_max + ymargin, 20.0) - return { - 'data': traces, - 'layout': { - 'title': 'Calibration Standards Comparison', - 'xaxis': { - 'title': 'Frequency (GHz)', - 'showgrid': True, - 'gridcolor': '#e5e5e5', - 'gridwidth': 1 + fig = { + "data": traces, + "layout": { + "title": "Calibration Standards Comparison", + "xaxis": { + "title": "Frequency (GHz)", + "showgrid": True, + "gridcolor": "#e5e5e5", + "gridwidth": 1, }, - 'yaxis': { - 'title': 'Magnitude (dB)', - 'range': [y_min, y_max], - 'showgrid': True, - 'gridcolor': '#e5e5e5', - 'gridwidth': 1 + "yaxis": { + "title": "Magnitude (dB)", + "range": [y_min, y_max], + "showgrid": True, + "gridcolor": "#e5e5e5", + "gridwidth": 1, }, - 'plot_bgcolor': '#fafafa', - 'paper_bgcolor': '#ffffff', - 'font': { - 'family': 'Arial, sans-serif', - 'size': 12, - 'color': '#333333' - }, - 'hovermode': 'x unified', - 'showlegend': True, - 'margin': {'l': 60, 'r': 40, 't': 60, 'b': 60} - } - } \ No newline at end of file + "plot_bgcolor": "#fafafa", + "paper_bgcolor": "#ffffff", + "font": {"family": "Arial, sans-serif", "size": 12, "color": "#333333"}, + "hovermode": "x unified", + "showlegend": True, + "margin": {"l": 60, "r": 40, "t": 60, "b": 60}, + }, + } + logger.debug("Combined standards plot generated", traces=len(traces)) + return fig diff --git a/vna_system/main.py b/vna_system/main.py new file mode 100644 index 0000000..fba59d7 --- /dev/null +++ b/vna_system/main.py @@ -0,0 +1,106 @@ +import logging +import os +from contextlib import asynccontextmanager +from pathlib import Path + +import uvicorn +from fastapi import FastAPI +from fastapi.staticfiles import StaticFiles + +import vna_system.core.singletons as singletons +from vna_system.api.endpoints import acquisition, health, settings, web_ui +from vna_system.api.websockets import processing as ws_processing +from vna_system.core.config import API_HOST, API_PORT +from vna_system.core.logging.logger import get_component_logger, setup_logging + +PROJECT_ROOT = Path(__file__).resolve().parents[1] +LOG_DIR = PROJECT_ROOT / "logs" +setup_logging(log_level=os.getenv("VNA_LOG_LEVEL", "INFO"), log_dir=LOG_DIR) + +for noisy in ( + "uvicorn.error", + "uvicorn.access", +): + logging.getLogger(noisy).setLevel(logging.ERROR) + +logger = get_component_logger(__file__) + + +@asynccontextmanager +async def lifespan(app: FastAPI): + logger.info("Starting VNA API Server") + try: + logger.info("Starting data acquisition") + singletons.vna_data_acquisition_instance.start() + + logger.info("Starting processor system") + singletons.processor_manager.start_processing() + logger.info( + "Processor system started", + processors=singletons.processor_manager.list_processors(), + ) + + logger.info("VNA API Server started successfully") + yield + except Exception as exc: + logger.error("Error during startup", error=repr(exc)) + raise + logger.info("Shutting down VNA API Server") + + if singletons.processor_manager: + singletons.processor_manager.stop_processing() + logger.info("Processor system stopped") + + if getattr(singletons, "vna_data_acquisition_instance", None) and singletons.vna_data_acquisition_instance._running: + singletons.vna_data_acquisition_instance.stop() + logger.info("Acquisition stopped") + + logger.info("VNA API Server shutdown complete") + + +app = FastAPI( + title="VNA System API", + description="Real-time VNA data acquisition and processing API", + version="1.0.0", + lifespan=lifespan, +) + +WEB_UI_DIR = Path(__file__).parent / "web_ui" +STATIC_DIR = WEB_UI_DIR / "static" +if STATIC_DIR.exists(): + app.mount("/static", StaticFiles(directory=str(STATIC_DIR)), name="static") + logger.info("Mounted static files", directory=str(STATIC_DIR)) +else: + logger.warning("Static directory not found", directory=str(STATIC_DIR)) + +app.include_router(web_ui.router) +app.include_router(health.router) +app.include_router(acquisition.router) +app.include_router(settings.router) +app.include_router(ws_processing.router) + + +def main() -> None: + host = os.getenv("VNA_HOST", API_HOST) + port_env = os.getenv("VNA_PORT") + if port_env is not None: + try: + port = int(port_env) + except ValueError: + logger.warning("Invalid VNA_PORT, falling back to config", VNA_PORT=port_env) + port = API_PORT + else: + port = API_PORT + + logger.info("Launching Uvicorn", host=host, port=port) + uvicorn.run( + "vna_system.main:app", + host=host, + port=port, + log_level="info", + reload=False, + ) + + +if __name__ == "__main__": + main() diff --git a/vna_system/scripts/start.sh b/vna_system/scripts/start.sh index 5705385..23de43f 100755 --- a/vna_system/scripts/start.sh +++ b/vna_system/scripts/start.sh @@ -36,7 +36,7 @@ log_error() { } # Check if we're in the right directory -if [ ! -f "$PROJECT_ROOT/vna_system/api/main.py" ]; then +if [ ! -f "$PROJECT_ROOT/vna_system/main.py" ]; then log_error "VNA System main.py not found. Please run this script from the project directory." exit 1 fi @@ -89,6 +89,6 @@ log_info "Press Ctrl+C to stop the server" echo # Run the main application -exec python3 -m vna_system.api.main +exec python3 -m vna_system.main