Skip to content

Commit

Permalink
ENH: kwarg to override resampling freq in get_telemetry
Browse files Browse the repository at this point in the history
  • Loading branch information
theOehrly committed Oct 4, 2023
1 parent 0250bb3 commit 1cd9722
Show file tree
Hide file tree
Showing 5 changed files with 81 additions and 27 deletions.
2 changes: 1 addition & 1 deletion docs/changelog/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,5 @@ Release Notes

Looking for :ref:`previous-release-notes`?

.. include:: v3.1.x.rst
.. include:: v3.2.x.rst

1 change: 1 addition & 0 deletions docs/changelog/previous.rst
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ Release Notes for Older Versions
.. toctree::
:maxdepth: 1

v3.1.x
v3.0.x
v2.3.2
v2.3.1
Expand Down
12 changes: 12 additions & 0 deletions docs/changelog/v3.2.x.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
What's new in v3.2.0
--------------------

(released dd/mm/2023)

New Features
^^^^^^^^^^^^

- Methods :meth:`fastf1.core.Lap.get_telemetry` and
:meth:`fastf1.core.Laps.get_telemetry` now take an additional ``frequency``
keyword argument to override the default frequency that is used for
resampling.
77 changes: 51 additions & 26 deletions fastf1/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@
from functools import cached_property
import warnings
import typing
from typing import Optional, List, Iterable, Union, Tuple, Any
from typing import Optional, List, Literal, Iterable, Union, Tuple, Any

import numpy as np
import pandas as pd
Expand Down Expand Up @@ -370,7 +370,7 @@ def slice_by_time(
def merge_channels(
self,
other: Union["Telemetry", pd.DataFrame],
frequency: Union[int, str] = None
frequency: Union[int, Literal['original'], None] = None
):
"""Merge telemetry objects containing different telemetry channels.
Expand Down Expand Up @@ -406,7 +406,8 @@ def merge_channels(
Args:
other: Object to be merged with self
frequency: Optional frequency to overwrite global preset.
frequency: Optional frequency to overwrite the default value set by
:attr:`~Telemetry.TELEMETRY_FREQUENCY`.
(Either string 'original' or integer for a frequency in Hz)
"""
# merge the data and interpolate missing; 'Date' needs to be the index
Expand Down Expand Up @@ -2474,22 +2475,34 @@ def telemetry(self) -> Telemetry:
instance of :class:`Telemetry`"""
return self.get_telemetry()

def get_telemetry(self) -> Telemetry:
def get_telemetry(self,
*,
frequency: Union[int, Literal['original'], None] = None
) -> Telemetry:
"""Telemetry data for all laps in `self`
Telemetry data is the result of merging the returned data from :meth:`get_car_data` and :meth:`get_pos_data`.
This means that telemetry data at least partially contains interpolated values! Telemetry data additionally
already has computed channels added (e.g. Distance).
Telemetry data is the result of merging the returned data from
:meth:`get_car_data` and :meth:`get_pos_data`. This means that
telemetry data at least partially contains interpolated values!
Telemetry data additionally already has computed channels added
(e.g. Distance).
This method is provided for convenience and compatibility reasons. But using it does usually not produce
the most accurate possible result.
It is recommended to use :meth:`get_car_data` or :meth:`get_pos_data` when possible. This is also faster if
merging of car and position data is not necessary and if not all computed channels are needed.
This method is provided for convenience and compatibility reasons. But
using it does usually not produce the most accurate possible result.
It is recommended to use :meth:`get_car_data` or :meth:`get_pos_data`
when possible. This is also faster if merging of car and position data
is not necessary and if not all computed channels are needed.
Resampling during merging is done according to the frequency set by
:attr:`~Telemetry.TELEMETRY_FREQUENCY`.
.. note:: Telemetry can only be returned if `self` contains laps of one driver only.
.. note:: Telemetry can only be returned if `self` contains laps of one
driver only.
Args:
frequency: Optional frequency to overwrite the default value set by
:attr:`~Telemetry.TELEMETRY_FREQUENCY`.
(Either string 'original' or integer for a frequency in Hz)
Returns:
instance of :class:`Telemetry`
Expand All @@ -2505,8 +2518,8 @@ def get_telemetry(self) -> Telemetry:
'Date', 'Time', 'SessionTime')]

car_data = car_data.add_distance().add_relative_distance()
car_data = car_data.merge_channels(drv_ahead)
merged = pos_data.merge_channels(car_data)
car_data = car_data.merge_channels(drv_ahead, frequency=frequency)
merged = pos_data.merge_channels(car_data, frequency=frequency)
return merged.slice_by_lap(self, interpolate_edges=True)

def get_car_data(self, **kwargs) -> Telemetry:
Expand Down Expand Up @@ -3050,37 +3063,49 @@ def telemetry(self) -> Telemetry:
instance of :class:`Telemetry`"""
return self.get_telemetry()

def get_telemetry(self) -> Telemetry:
def get_telemetry(self,
*,
frequency: Union[int, Literal['original'], None] = None
) -> Telemetry:
"""Telemetry data for this lap
Telemetry data is the result of merging the returned data from :meth:`get_car_data` and :meth:`get_pos_data`.
This means that telemetry data at least partially contains interpolated values! Telemetry data additionally
already has computed channels added (e.g. Distance).
Telemetry data is the result of merging the returned data from
:meth:`get_car_data` and :meth:`get_pos_data`. This means that
telemetry data at least partially contains interpolated values!
Telemetry data additionally already has computed channels added
(e.g. Distance).
This method is provided for convenience and compatibility reasons. But using it does usually not produce
the most accurate possible result.
It is recommended to use :meth:`get_car_data` or :meth:`get_pos_data` when possible. This is also faster if
merging of car and position data is not necessary and if not all computed channels are needed.
This method is provided for convenience and compatibility reasons. But
using it does usually not produce the most accurate possible result.
It is recommended to use :meth:`get_car_data` or :meth:`get_pos_data`
when possible. This is also faster if merging of car and position data
is not necessary and if not all computed channels are needed.
Resampling during merging is done according to the frequency set by
:attr:`~Telemetry.TELEMETRY_FREQUENCY`.
:attr:`~Telemetry.TELEMETRY_FREQUENCY` if not overwritten with the
``frequency`` argument.
Args:
frequency: Optional frequency to overwrite default value set by
:attr:`~Telemetry.TELEMETRY_FREQUENCY`.
(Either string 'original' or integer for a frequency in Hz)
Returns:
instance of :class:`Telemetry`
"""
pos_data = self.get_pos_data(pad=1, pad_side='both')
car_data = self.get_car_data(pad=1, pad_side='both')

# calculate driver ahead from from data without padding to
# calculate driver ahead from data without padding to
# prevent out of bounds errors
drv_ahead = car_data.iloc[1:-1] \
.add_driver_ahead() \
.loc[:, ('DriverAhead', 'DistanceToDriverAhead',
'Date', 'Time', 'SessionTime')]

car_data = car_data.add_distance().add_relative_distance()
car_data = car_data.merge_channels(drv_ahead)
merged = pos_data.merge_channels(car_data)
car_data = car_data.merge_channels(drv_ahead, frequency=frequency)
merged = pos_data.merge_channels(car_data, frequency=frequency)
return merged.slice_by_lap(self, interpolate_edges=True)

def get_car_data(self, **kwargs) -> Telemetry:
Expand Down
16 changes: 16 additions & 0 deletions fastf1/tests/test_laps.py
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,22 @@ def test_laps_get_telemetry(reference_laps_data):
assert col in tel.columns


@pytest.mark.f1telapi
def test_laps_get_telemetry_non_default_frequency(reference_laps_data):
session, laps = reference_laps_data
drv_laps = laps.pick_drivers('BOT')

# test for <Laps>
tel = drv_laps.get_telemetry(frequency=10)
assert (tel['Time'].diff().iloc[2:-2].unique()
== pd.Timedelta(0.1, 'seconds'))

# test for <Lap>
ftel = drv_laps.pick_fastest().get_telemetry(frequency=10)
assert (ftel['Time'].diff().iloc[2:-2].unique()
== pd.Timedelta(0.1, 'seconds'))


@pytest.mark.f1telapi
def test_laps_get_weather_data(reference_laps_data):
session, laps = reference_laps_data
Expand Down

0 comments on commit 1cd9722

Please sign in to comment.