Skip to content

Inclinometer

Inclinometer

Inclinometer(path: Path, logpath: str | None = None, sensor_type: Literal['kernel', 'imx5'] | None = None)

Unified inclinometer class that auto-detects and loads either Kernel-100 (binary) or IMX-5 (CSV) inclinometer data.

Parameters:

Name Type Description Default
path str

Path to inclinometer file (for Kernel) or sensors directory (for IMX-5).

required
logpath str

Path to log file for timing information.

None
sensor_type str

Force sensor type: 'kernel', 'imx5', or None for auto-detect.

None
Source code in pils/sensors/inclinometer.py
def __init__(
    self,
    path: Path,
    logpath: str | None = None,
    sensor_type: Literal["kernel", "imx5"] | None = None,
) -> None:
    self._lookout_path = path

    if sensor_type is None:
        self._auto_detect()
    else:
        self.sensor_type = sensor_type

    logger.info(f"Inclinometer sensor type: {self.sensor_type}")

    self.logpath = logpath
    self._decoder: KernelInclinometer | IMX5Inclinometer | None = None

    # Initialize the appropriate decoder
    self._init_decoder()

tstart property

tstart

Get start time (Kernel only).

ins_data property

ins_data: DataFrame | None

Get INS data (IMX-5 only).

imu_data property

imu_data: DataFrame | None

Get IMU data (IMX-5 only).

inl2_data property

inl2_data: DataFrame | None

Get INL2 data (IMX-5 only).

load_data

load_data() -> None

Load inclinometer data using the detected decoder.

Raises:

Type Description
ValueError

If no inclinometer data found at path.

Source code in pils/sensors/inclinometer.py
def load_data(self) -> None:
    """Load inclinometer data using the detected decoder.

    Raises
    ------
    ValueError
        If no inclinometer data found at path.
    """
    if self._decoder is None:
        raise ValueError(
            f"No inclinometer data found at {self._lookout_path}. "
            "Expected either *_INC.bin (Kernel) or *_INC_*.csv (IMX-5) files."
        )

    self._decoder.load_data()
    self.data = self._decoder.data

plot

plot() -> None

Plot roll, pitch, yaw over time.

Raises:

Type Description
ValueError

If data not loaded.

Source code in pils/sensors/inclinometer.py
def plot(self) -> None:
    """Plot roll, pitch, yaw over time.

    Raises
    ------
    ValueError
        If data not loaded.
    """
    if self.data is None:
        raise ValueError("Data not loaded. Run load_data() first.")

    fig, axs = plt.subplots(3, 1, sharex=True, figsize=(10, 8))

    # Determine x-axis (prefer timestamp)
    # Handle both DataFrame and dict types
    if isinstance(self.data, pl.DataFrame):
        if "timestamp" in self.data.columns:
            xlabel = "Time [s]"
        elif "datetime" in self.data.columns:
            xlabel = "Time"
        else:
            xlabel = "Sample"
    elif isinstance(self.data, dict):
        if "timestamp" in self.data:
            xlabel = "Time [s]"
        elif "datetime" in self.data:
            xlabel = "Time"
        else:
            # Estimate length from first available key
            xlabel = "Sample"
    else:
        _x = np.arange(len(self.data))
        xlabel = "Sample"

    # Extract data based on type
    if isinstance(self.data, pl.DataFrame):
        # yaw, pitch, roll would be used for plotting if implemented
        pass
    elif isinstance(self.data, dict):
        _yaw = np.array(self.data.get("yaw", []))
        _pitch = np.array(self.data.get("pitch", []))
        _roll = np.array(self.data.get("roll", []))
    else:
        return

    axs[0].set_ylabel("Yaw [°]")
    axs[1].set_ylabel("Pitch [°]")
    axs[2].set_ylabel("Roll [°]")
    axs[-1].set_xlabel(xlabel)

    plt.suptitle(f"Inclinometer Data ({self.sensor_type or 'unknown'})")
    plt.tight_layout()
    plt.show()