> ## Documentation Index
> Fetch the complete documentation index at: https://mintlify.com/TracingInsights/tif1/llms.txt
> Use this file to discover all available pages before exploring further.

# Laps and Telemetry

> Working with lap timing data and telemetry in tif1

## Overview

Tif1 provides two main classes for working with lap data:

* **`Laps`**: A DataFrame containing multiple laps with timing data
* **`Lap`**: A single lap with access to its telemetry
* **`Telemetry`**: Multi-channel time series data (speed, throttle, brake, etc.)

All three classes are pandas-compatible and provide fastf1-like APIs.

## Laps Class

The `Laps` class is a pandas DataFrame with additional methods for filtering and querying lap data.

### Getting Laps Data

```python theme={null}
import tif1

session = tif1.get_session(2024, "Monaco", "Race")
laps = session.laps  # Returns Laps object

print(type(laps))  # <class 'tif1.core.Laps'>
print(laps.shape)  # (1200, 35) - varies by session
```

### Laps DataFrame Columns

The `Laps` DataFrame contains comprehensive timing data:

<Accordion title="Core Timing Columns">
  * **LapNumber** (float): Lap number (1, 2, 3, ...)
  * **LapTime** (timedelta): Total lap time
  * **LapTimeSeconds** (float): Lap time in seconds
  * **Sector1Time** (timedelta): Sector 1 time
  * **Sector2Time** (timedelta): Sector 2 time
  * **Sector3Time** (timedelta): Sector 3 time
  * **Time** (timedelta): Session time when lap ended
  * **LapStartTime** (timedelta): Session time when lap started
  * **LapStartDate** (datetime): Absolute timestamp of lap start
</Accordion>

<Accordion title="Driver & Team Columns">
  * **Driver** (str): Driver code (e.g., 'VER', 'HAM')
  * **DriverNumber** (str): Driver racing number
  * **Team** (str): Team name
</Accordion>

<Accordion title="Tire & Strategy Columns">
  * **Compound** (str): Tire compound ('SOFT', 'MEDIUM', 'HARD')
  * **TyreLife** (float): Laps on current tire set
  * **Stint** (float): Stint number
  * **FreshTyre** (bool): Whether tire is new
</Accordion>

<Accordion title="Track Position & Status">
  * **Position** (float): Track position (1st, 2nd, 3rd, ...)
  * **TrackStatus** (str): Track status code ('1', '2', '4', '6')
  * **IsPersonalBest** (bool): Whether this is driver's fastest lap
  * **IsAccurate** (bool): Whether timing data is accurate
  * **Deleted** (bool): Whether lap was deleted
  * **DeletedReason** (str): Reason for deletion (if applicable)
</Accordion>

<Accordion title="Speed Trap Columns">
  * **SpeedI1** (float): Speed at intermediate 1 (km/h)
  * **SpeedI2** (float): Speed at intermediate 2 (km/h)
  * **SpeedFL** (float): Finish line speed (km/h)
  * **SpeedST** (float): Speed trap speed (km/h)
</Accordion>

<Accordion title="Pit Stop Columns">
  * **PitInTime** (timedelta): Time when entering pits
  * **PitOutTime** (timedelta): Time when exiting pits
</Accordion>

<Accordion title="Weather Columns">
  * **AirTemp** (float): Air temperature (°C)
  * **Humidity** (float): Humidity (%)
  * **Pressure** (float): Air pressure (mbar)
  * **TrackTemp** (float): Track temperature (°C)
  * **WindSpeed** (float): Wind speed (m/s)
  * **WindDirection** (int): Wind direction (degrees)
  * **Rainfall** (bool): Whether it's raining
</Accordion>

### Filtering Laps

The `Laps` class provides convenient filtering methods:

<CodeGroup>
  ```python By Driver theme={null}
  # Get laps for single driver
  ver_laps = laps.pick_driver('VER')

  # Get laps for multiple drivers
  top3_laps = laps.pick_drivers(['VER', 'HAM', 'LEC'])
  ```

  ```python By Lap Number theme={null}
  # Get specific lap
  lap_10 = laps.pick_lap(10)

  # Get range of laps
  early_laps = laps.pick_laps([1, 2, 3, 4, 5])

  # Get laps using slice
  mid_race = laps.pick_laps(slice(20, 40))
  ```

  ```python By Team theme={null}
  # Get all Red Bull laps
  red_bull = laps.pick_team('Red Bull Racing')

  # Get multiple teams
  top_teams = laps.pick_teams(['Red Bull Racing', 'Mercedes', 'Ferrari'])
  ```

  ```python By Tire Compound theme={null}
  # Get all soft tire laps
  soft_laps = laps.pick_tyre('SOFT')

  # Get multiple compounds
  soft_medium = laps.pick_compounds(['SOFT', 'MEDIUM'])
  ```

  ```python By Track Status theme={null}
  # Get green flag laps only
  green_laps = laps.pick_track_status('1', how='equals')

  # Get all yellow flag laps (includes '2', '4', '6')
  yellow_laps = laps.pick_track_status('2', how='contains')
  ```

  ```python Pit Stops theme={null}
  # Exclude pit in/out laps
  no_pits = laps.pick_wo_box()

  # Get pit in laps only
  pit_in = laps.pick_box_laps(which='in')

  # Get pit out laps only
  pit_out = laps.pick_box_laps(which='out')

  # Get all pit laps (in + out)
  all_pit = laps.pick_box_laps(which='both')
  ```

  ```python Data Quality theme={null}
  # Get valid laps only (not deleted)
  valid = laps.pick_not_deleted()

  # Get accurate timing data only
  accurate = laps.pick_accurate()

  # Get quick laps (within 107% of fastest)
  quick = laps.pick_quicklaps(threshold=1.07)
  ```
</CodeGroup>

### Getting Fastest Lap

```python theme={null}
laps = session.laps

# Get overall fastest lap
fastest = laps.pick_fastest()
print(fastest['Driver'])      # 'VER'
print(fastest['LapTime'])     # Timedelta('0 days 00:01:12.345')
print(fastest['LapNumber'])   # 45

# Get fastest lap for specific driver
ver_laps = laps.pick_driver('VER')
ver_fastest = ver_laps.pick_fastest()
```

### Chaining Filters

You can chain multiple filters together:

```python theme={null}
laps = session.laps

# Get Verstappen's valid race laps on soft tires
ver_soft = (laps
    .pick_driver('VER')
    .pick_tyre('SOFT')
    .pick_wo_box()
    .pick_not_deleted()
    .pick_accurate()
)

print(f"Found {len(ver_soft)} laps")
print(ver_soft[['LapNumber', 'LapTime', 'TyreLife']].head())
```

## Lap Class

The `Lap` class represents a single lap and provides access to its telemetry data.

### Getting a Single Lap

```python theme={null}
laps = session.laps

# Get single lap by index
lap = laps.iloc[0]  # First lap
print(type(lap))    # <class 'tif1.core.Lap'>

# Get lap using pick_fastest
fastest = laps.pick_fastest()
print(fastest['Driver'])     # 'VER'
print(fastest['LapNumber'])  # 45
```

### Accessing Lap Properties

```python theme={null}
lap = laps.pick_fastest()

# Access lap data as pandas Series
print(lap['LapTime'])      # Timedelta
print(lap['Driver'])       # 'VER'
print(lap['Compound'])     # 'SOFT'
print(lap['LapNumber'])    # 45

# Access via properties
print(lap.driver)          # 'VER'
print(lap.lap_number)      # 45
```

### Accessing Telemetry from a Lap

```python theme={null}
lap = laps.pick_fastest()

# Get telemetry data for this lap
tel = lap.telemetry
print(type(tel))  # <class 'tif1.core.Telemetry'>

# Or use get_telemetry() (fastf1 compatibility)
tel = lap.get_telemetry()
```

## Telemetry Class

The `Telemetry` class is a pandas DataFrame containing high-frequency sensor data.

### Telemetry Channels

Telemetry data includes:

<Accordion title="Time & Position Channels">
  * **Time** (timedelta): Time relative to lap start
  * **SessionTime** (timedelta): Absolute session time
  * **Distance** (float): Distance along track (meters)
  * **RelativeDistance** (float): Normalized distance (0-1)
  * **X** (float): Track X coordinate
  * **Y** (float): Track Y coordinate
  * **Z** (float): Track Z coordinate (elevation)
</Accordion>

<Accordion title="Speed & Drivetrain">
  * **Speed** (float): Speed in km/h
  * **RPM** (float): Engine RPM
  * **nGear** (int): Gear number (1-8)
  * **Throttle** (float): Throttle position (0-100%)
  * **Brake** (bool/float): Brake application
</Accordion>

<Accordion title="Aerodynamics">
  * **DRS** (int): DRS status (0=closed, 1=open)
</Accordion>

<Accordion title="Positioning">
  * **Driver** (str): Driver code
  * **DriverAhead** (str): Driver ahead
  * **DistanceToDriverAhead** (float): Gap in meters
  * **LapNumber** (int): Lap number
  * **TrackStatus** (str): Track status code
</Accordion>

### Getting Telemetry

<CodeGroup>
  ```python From a Lap theme={null}
  lap = laps.pick_fastest()

  # Get telemetry for this lap
  tel = lap.telemetry
  print(tel.shape)  # (500, 20) - varies by lap
  ```

  ```python From Multiple Laps theme={null}
  laps_subset = laps.pick_driver('VER').head(5)

  # Get combined telemetry
  tel = laps_subset.telemetry  # Only works for single driver
  print(tel.shape)  # (2500, 20) - 5 laps × ~500 samples
  ```

  ```python Directly from Session theme={null}
  # Get all telemetry data
  car_data = session.car_data  # or session.pos_data

  # This loads ALL telemetry for ALL drivers
  # Use with caution on large sessions
  ```
</CodeGroup>

### Telemetry Operations

#### Adding Computed Channels

```python theme={null}
tel = lap.telemetry

# Add distance channel
tel = tel.add_distance()
print('Distance' in tel.columns)  # True

# Add relative distance (0-1 normalized)
tel = tel.add_relative_distance()
print('RelativeDistance' in tel.columns)  # True

# Add differential distance
tel = tel.add_differential_distance()
print('DifferentialDistance' in tel.columns)  # True

# Add driver ahead info
tel = tel.add_driver_ahead()
print('DriverAhead' in tel.columns)  # True
print('DistanceToDriverAhead' in tel.columns)  # True
```

#### Slicing Telemetry

<CodeGroup>
  ```python By Time theme={null}
  # Get telemetry between 10s and 20s
  tel_slice = tel.slice_by_time(
      start_time=10.0,  # seconds
      end_time=20.0,
      pad=10,           # Add 10 samples padding
      pad_side='both'   # Pad both sides
  )
  ```

  ```python By Lap theme={null}
  # Get telemetry for specific lap(s)
  lap = laps.iloc[0]
  tel_lap = tel.slice_by_lap(lap)

  # With padding
  tel_lap = tel.slice_by_lap(lap, pad=50, pad_side='after')
  ```

  ```python By Mask theme={null}
  import numpy as np

  # Create boolean mask
  mask = tel['Speed'] > 300  # High speed sections

  # Slice using mask
  fast_sections = tel.slice_by_mask(mask, pad=20)
  ```
</CodeGroup>

#### Resampling and Interpolation

```python theme={null}
tel = lap.telemetry

# Resample to 1Hz
tel_1hz = tel.resample_channels(rule='1S')

# Fill missing values with interpolation
tel_filled = tel.fill_missing()
```

#### Merging Telemetry

```python theme={null}
lap1 = laps.iloc[0]
lap2 = laps.iloc[1]

tel1 = lap1.telemetry
tel2 = lap2.telemetry

# Merge two telemetry streams (time-aligned)
merged = tel1.merge_channels(tel2)
```

## Data Access Patterns

### Pattern 1: Single Driver Analysis

```python theme={null}
session = tif1.get_session(2024, "Monaco", "Race")
laps = session.laps

# Get all Verstappen laps
ver_laps = laps.pick_driver('VER')

# Get fastest lap
fastest = ver_laps.pick_fastest()

# Get telemetry
tel = fastest.telemetry

# Analyze speed trace
import matplotlib.pyplot as plt
plt.plot(tel['Distance'], tel['Speed'])
plt.xlabel('Distance (m)')
plt.ylabel('Speed (km/h)')
plt.title(f"VER Lap {fastest['LapNumber']} - Speed Trace")
plt.show()
```

### Pattern 2: Driver Comparison

```python theme={null}
session = tif1.get_session(2024, "Monaco", "Qualifying")
laps = session.laps

# Get fastest laps for two drivers
ver_fastest = laps.pick_driver('VER').pick_fastest()
ham_fastest = laps.pick_driver('HAM').pick_fastest()

# Get telemetry
ver_tel = ver_fastest.telemetry
ham_tel = ham_fastest.telemetry

# Compare speed traces
import matplotlib.pyplot as plt
plt.plot(ver_tel['Distance'], ver_tel['Speed'], label='VER')
plt.plot(ham_tel['Distance'], ham_tel['Speed'], label='HAM')
plt.xlabel('Distance (m)')
plt.ylabel('Speed (km/h)')
plt.legend()
plt.show()
```

### Pattern 3: Race Pace Analysis

```python theme={null}
session = tif1.get_session(2024, "Monaco", "Race")
laps = session.laps

# Get clean race laps for a driver
ver_race = (laps
    .pick_driver('VER')
    .pick_wo_box()        # Exclude pit laps
    .pick_not_deleted()   # Exclude deleted laps
    .pick_accurate()      # Only accurate timing
)

# Analyze pace by stint
for stint in ver_race['Stint'].unique():
    stint_laps = ver_race[ver_race['Stint'] == stint]
    avg_time = stint_laps['LapTime'].mean()
    tire = stint_laps['Compound'].iloc[0]
    print(f"Stint {int(stint)} ({tire}): {avg_time}")
```

### Pattern 4: Telemetry-Based Corner Analysis

```python theme={null}
session = tif1.get_session(2024, "Monaco", "Qualifying")
lap = session.laps.pick_fastest()
tel = lap.telemetry.add_distance()

# Find braking zones (speed drops)
tel['SpeedDelta'] = tel['Speed'].diff()
braking_zones = tel[tel['SpeedDelta'] < -10]  # Speed drops > 10 km/h

print("Braking zones:")
for idx, point in braking_zones.iterrows():
    print(f"Distance: {point['Distance']:.0f}m, Speed: {point['Speed']:.1f} km/h")
```

## Performance Considerations

### Telemetry Loading Performance

<Warning>
  Telemetry data is large! A single lap can have 300-800 data points.
</Warning>

```python theme={null}
# ❌ Slow - loads all telemetry for all drivers
all_telemetry = session.car_data  # Can be 100+ MB

# ✅ Fast - load only what you need
ver_fastest = session.laps.pick_driver('VER').pick_fastest()
tel = ver_fastest.telemetry  # Only ~50 KB
```

### Caching

Telemetry is automatically cached:

```python theme={null}
lap = session.laps.pick_fastest()

# First access - fetched from CDN
tel1 = lap.telemetry  # ~0.5s

# Second access - from cache
tel2 = lap.telemetry  # Instant
```

### Batch Loading

For loading multiple telemetry streams, use the optimized batch methods:

```python theme={null}
# ✅ Optimized - parallel loading
fastest_tels = session.get_fastest_laps_tels(by_driver=True)
# Loads all drivers' fastest lap telemetry in parallel (~0.4s for 20 drivers)

# ❌ Slow - sequential loading
for driver in session.drivers:
    driver_laps = session.laps.pick_driver(driver)
    fastest = driver_laps.pick_fastest()
    tel = fastest.telemetry  # Sequential - ~10s for 20 drivers
```

## Related Topics

<CardGroup cols={2}>
  <Card title="Sessions" icon="flag-checkered" href="/concepts/sessions">
    Learn about Session objects and data loading
  </Card>

  <Card title="Drivers" icon="user-helmet-safety" href="/concepts/drivers">
    Working with driver-specific operations
  </Card>

  <Card title="Data Flow" icon="diagram-project" href="/concepts/data-flow">
    Understand the data loading pipeline
  </Card>

  <Card title="API Reference" icon="code" href="/api/laps">
    Complete Laps and Telemetry API documentation
  </Card>
</CardGroup>
