{
 "cells": [
  {
   "cell_type": "raw",
   "metadata": {},
   "source": [
    "---\n",
    "description: API details.\n",
    "output-file: riann.html\n",
    "title: riann\n",
    "\n",
    "---\n",
    "\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<!-- WARNING: THIS FILE WAS AUTOGENERATED! DO NOT EDIT! -->"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 0,
   "has_sd": true,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/markdown": [
       "---\n",
       "\n",
       "### RIANN\n",
       "\n",
       ">      RIANN (onnx_path=None)\n",
       "\n",
       "*Robust IMU-based Attitude Neural Network for orientation estimation using IMU data.\n",
       "\n",
       "This class implements efficient quaternion-based attitude estimation from \n",
       "accelerometer and gyroscope data using a neural network approach. The implementation\n",
       "is optimized for step-by-step processing in real-time applications.*\n",
       "\n",
       "|    | **Type** | **Default** | **Details** |\n",
       "| -- | -------- | ----------- | ----------- |\n",
       "| onnx_path | NoneType | None | Path to the RIANN onnx file. Defaults to the file provided with the package. |"
      ],
      "text/plain": [
       "---\n",
       "\n",
       "### RIANN\n",
       "\n",
       ">      RIANN (onnx_path=None)\n",
       "\n",
       "*Robust IMU-based Attitude Neural Network for orientation estimation using IMU data.\n",
       "\n",
       "This class implements efficient quaternion-based attitude estimation from \n",
       "accelerometer and gyroscope data using a neural network approach. The implementation\n",
       "is optimized for step-by-step processing in real-time applications.*\n",
       "\n",
       "|    | **Type** | **Default** | **Details** |\n",
       "| -- | -------- | ----------- | ----------- |\n",
       "| onnx_path | NoneType | None | Path to the RIANN onnx file. Defaults to the file provided with the package. |"
      ]
     },
     "execution_count": null,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "#| echo: false\n",
    "#| output: asis\n",
    "show_doc(RIANN)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "language": "python"
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Quaternions shape: (100, 4)\n"
     ]
    }
   ],
   "source": [
    "# | eval: false\n",
    "# Example 1: Basic usage with batch processing\n",
    "\n",
    "# Prepare sample IMU data\n",
    "sequence_length = 100\n",
    "acc = np.ones((sequence_length, 3))  # Accelerometer data [m/s²]\n",
    "gyr = np.zeros((sequence_length, 3))  # Gyroscope data [rad/s]\n",
    "fs = 200  # Sampling rate [Hz]\n",
    "\n",
    "# Initialize RIANN\n",
    "riann = RIANN()\n",
    "\n",
    "# Process all data at once\n",
    "quaternions = riann.predict(acc, gyr, fs)\n",
    "print(f\"Quaternions shape: {quaternions.shape}\")  # (100, 4)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "language": "python"
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Collected 100 orientation estimates\n"
     ]
    }
   ],
   "source": [
    "# | eval: false\n",
    "# Example 2: Real-time processing\n",
    "\n",
    "# Initialize RIANN for real-time processing\n",
    "riann = RIANN()\n",
    "riann.set_sampling_rate(100)  # 100 Hz\n",
    "riann.reset_state()\n",
    "\n",
    "# Simulated IMU data stream\n",
    "def simulate_imu_data():\n",
    "    \"\"\"Simulate a single IMU reading\"\"\"\n",
    "    # In a real application, this would read from actual sensors\n",
    "    acc = np.array([0.0, 0.0, 9.81]) + np.random.normal(0, 0.1, 3)  # Add noise\n",
    "    gyr = np.array([0.0, 0.0, 0.0]) + np.random.normal(0, 0.01, 3)  # Add noise\n",
    "    return acc, gyr\n",
    "\n",
    "# Simulated real-time loop\n",
    "orientations = []\n",
    "for _ in range(100):  # Process 100 readings\n",
    "    # Read IMU data\n",
    "    acc, gyr = simulate_imu_data()\n",
    "    \n",
    "    # Process data to get orientation\n",
    "    quaternion = riann.predict_step(acc, gyr)\n",
    "    orientations.append(quaternion)\n",
    "    \n",
    "    # In a real application, you might use the orientation here\n",
    "    # for control, visualization, etc.\n",
    "    \n",
    "    # Simulate sensor sampling rate\n",
    "    time.sleep(0.01)  # 100 Hz\n",
    "\n",
    "orientations = np.array(orientations)\n",
    "print(f\"Collected {len(orientations)} orientation estimates\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "language": "python"
   },
   "outputs": [],
   "source": [
    "# | eval: false\n",
    "# Example 3: Processing existing datasets\n",
    "import h5py\n",
    "\n",
    "# Load data from file (example using the BROAD dataset as shown in RIANN_Example.ipynb)\n",
    "# In your application, adapt this to your data source\n",
    "try:\n",
    "    with h5py.File('data_hdf5/01_undisturbed_slow_rotation_A.hdf5', 'r') as f:\n",
    "        acc = f['imu_acc'][:]  # Accelerometer data\n",
    "        gyr = f['imu_gyr'][:]  # Gyroscope data\n",
    "        ref_quat = f['opt_quat'][:]  # Reference quaternions (if available)\n",
    "        fs = f.attrs['sampling_rate']  # Sampling rate\n",
    "except FileNotFoundError:\n",
    "    # Create dummy data if file not found\n",
    "    sequence_length = 1000\n",
    "    acc = np.ones((sequence_length, 3))\n",
    "    gyr = np.zeros((sequence_length, 3))\n",
    "    ref_quat = None\n",
    "    fs = 200\n",
    "\n",
    "# Initialize RIANN\n",
    "riann = RIANN()\n",
    "\n",
    "# Process data\n",
    "est_quat = riann.predict(acc, gyr, fs)\n",
    "\n",
    "# If reference data is available, calculate error\n",
    "if ref_quat is not None:\n",
    "    # Helper function for attitude error calculation\n",
    "    def calculate_attitude_error(q1, q2):\n",
    "        \"\"\"Calculate attitude error in degrees between two quaternions\"\"\"\n",
    "        # Simple dot product method (accurate for small angles)\n",
    "        dot_products = np.sum(q1 * q2, axis=1)\n",
    "        dot_products = np.clip(dot_products, -1.0, 1.0)  # Ensure valid acos input\n",
    "        angles_rad = 2 * np.arccos(np.abs(dot_products))\n",
    "        return angles_rad * 180 / np.pi  # Convert to degrees\n",
    "\n",
    "    # Calculate errors\n",
    "    errors = calculate_attitude_error(est_quat, ref_quat)\n",
    "    \n",
    "    # Plot error\n",
    "    plt.figure(figsize=(10, 6))\n",
    "    plt.plot(errors)\n",
    "    plt.xlabel('Sample')\n",
    "    plt.ylabel('Attitude Error (degrees)')\n",
    "    plt.title('Orientation Estimation Error')\n",
    "    plt.grid(True)\n",
    "    plt.show()\n",
    "    \n",
    "    print(f\"Mean error: {np.mean(errors):.2f} degrees\")\n",
    "    print(f\"Max error: {np.max(errors):.2f} degrees\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "language": "python"
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Processed chunk 1/10, current orientation: w=-0.79, x=0.00, y=-0.00, z=0.61\n",
      "Processed chunk 2/10, current orientation: w=-0.81, x=-0.00, y=-0.00, z=0.59\n",
      "Processed chunk 3/10, current orientation: w=-0.90, x=-0.04, y=-0.09, z=0.42\n",
      "Processed chunk 4/10, current orientation: w=-0.98, x=-0.00, y=-0.16, z=0.09\n",
      "Processed chunk 5/10, current orientation: w=-0.94, x=0.08, y=-0.18, z=-0.28\n",
      "Processed chunk 6/10, current orientation: w=-0.87, x=0.15, y=-0.17, z=-0.44\n",
      "Processed chunk 7/10, current orientation: w=-0.75, x=0.04, y=0.02, z=0.66\n",
      "Processed chunk 8/10, current orientation: w=-0.56, x=0.08, y=0.10, z=0.82\n",
      "Processed chunk 9/10, current orientation: w=-0.53, x=0.11, y=0.13, z=0.83\n",
      "Processed chunk 10/10, current orientation: w=-0.55, x=0.15, y=0.15, z=0.81\n",
      "Generated 500 orientation estimates\n"
     ]
    }
   ],
   "source": [
    "# | eval: false\n",
    "# Example 4: Advanced usage with step-by-step processing and state tracking\n",
    "\n",
    "# Create synthetic IMU data with known motion pattern\n",
    "def generate_synthetic_data(fs=100, duration=5):\n",
    "    \"\"\"Generate synthetic IMU data for a specific motion pattern\"\"\"\n",
    "    n_samples = int(fs * duration)\n",
    "    t = np.linspace(0, duration, n_samples)\n",
    "    \n",
    "    # Initialize arrays\n",
    "    acc = np.zeros((n_samples, 3))\n",
    "    gyr = np.zeros((n_samples, 3))\n",
    "    \n",
    "    # Create a simple rotation pattern (rotation around y-axis)\n",
    "    for i, time in enumerate(t):\n",
    "        # Gyroscope data (constant rotation around y-axis)\n",
    "        if 1.0 <= time <= 3.0:\n",
    "            gyr[i, 1] = 0.5  # 0.5 rad/s around y-axis\n",
    "        \n",
    "        # Accelerometer data (gravity vector rotated accordingly)\n",
    "        if time < 1.0:\n",
    "            # Initial position - gravity along z\n",
    "            acc[i] = [0, 0, 9.81]\n",
    "        elif time < 3.0:\n",
    "            # During rotation - rotate gravity vector\n",
    "            angle = 0.5 * (time - 1.0)  # 0.5 rad/s * time\n",
    "            acc[i] = [9.81 * np.sin(angle), 0, 9.81 * np.cos(angle)]\n",
    "        else:\n",
    "            # Final position - gravity rotated\n",
    "            acc[i] = [9.81 * np.sin(1.0), 0, 9.81 * np.cos(1.0)]\n",
    "    \n",
    "    # Add noise to make it realistic\n",
    "    acc += np.random.normal(0, 0.1, acc.shape)\n",
    "    gyr += np.random.normal(0, 0.01, gyr.shape)\n",
    "    \n",
    "    return t, acc, gyr\n",
    "\n",
    "# Generate data\n",
    "fs = 100\n",
    "t, acc, gyr = generate_synthetic_data(fs=fs)\n",
    "\n",
    "# Initialize RIANN\n",
    "riann = RIANN()\n",
    "\n",
    "# Process data in chunks to simulate real-time processing with state tracking\n",
    "chunk_size = 50  # Process 50 samples at a time\n",
    "n_chunks = len(acc) // chunk_size\n",
    "\n",
    "# Store all quaternions\n",
    "all_quaternions = []\n",
    "\n",
    "for chunk in range(n_chunks):\n",
    "    start_idx = chunk * chunk_size\n",
    "    end_idx = start_idx + chunk_size\n",
    "    \n",
    "    # Process this chunk\n",
    "    if chunk == 0:\n",
    "        # First chunk - initialize state\n",
    "        riann.reset_state()\n",
    "    \n",
    "    # Process chunk step by step\n",
    "    for i in range(start_idx, end_idx):\n",
    "        quat = riann.predict_step(acc[i], gyr[i], fs)\n",
    "        all_quaternions.append(quat)\n",
    "    \n",
    "    # At this point in a real application, you could:\n",
    "    # 1. Use the current orientation for feedback\n",
    "    # 2. Save the current state for later resume\n",
    "    # 3. Transmit the orientation to another system\n",
    "    print(f\"Processed chunk {chunk+1}/{n_chunks}, \" +\n",
    "          f\"current orientation: w={quat[0]:.2f}, x={quat[1]:.2f}, \" +\n",
    "          f\"y={quat[2]:.2f}, z={quat[3]:.2f}\")\n",
    "\n",
    "all_quaternions = np.array(all_quaternions)\n",
    "print(f\"Generated {len(all_quaternions)} orientation estimates\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "language": "python"
   },
   "outputs": [],
   "source": [
    "#| include: false\n",
    "import nbdev; nbdev.nbdev_export()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "language": "python"
   },
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "python3",
   "language": "python",
   "name": "python3"
  },
  "widgets": {
   "application/vnd.jupyter.widget-state+json": {
    "state": {},
    "version_major": 2,
    "version_minor": 0
   }
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
