From 1cd972202e7d605c44a07d0de296cb21e5a657c1 Mon Sep 17 00:00:00 2001 From: theOehrly <23384863+theOehrly@users.noreply.github.com> Date: Wed, 4 Oct 2023 22:47:43 +0200 Subject: [PATCH] ENH: kwarg to override resampling freq in get_telemetry --- docs/changelog/index.rst | 2 +- docs/changelog/previous.rst | 1 + docs/changelog/v3.2.x.rst | 12 ++++++ fastf1/core.py | 77 ++++++++++++++++++++++++------------- fastf1/tests/test_laps.py | 16 ++++++++ 5 files changed, 81 insertions(+), 27 deletions(-) create mode 100644 docs/changelog/v3.2.x.rst diff --git a/docs/changelog/index.rst b/docs/changelog/index.rst index d79d805da..e46919ff2 100644 --- a/docs/changelog/index.rst +++ b/docs/changelog/index.rst @@ -3,5 +3,5 @@ Release Notes Looking for :ref:`previous-release-notes`? -.. include:: v3.1.x.rst +.. include:: v3.2.x.rst diff --git a/docs/changelog/previous.rst b/docs/changelog/previous.rst index 84d7d73a7..5d3932ca9 100644 --- a/docs/changelog/previous.rst +++ b/docs/changelog/previous.rst @@ -8,6 +8,7 @@ Release Notes for Older Versions .. toctree:: :maxdepth: 1 + v3.1.x v3.0.x v2.3.2 v2.3.1 diff --git a/docs/changelog/v3.2.x.rst b/docs/changelog/v3.2.x.rst new file mode 100644 index 000000000..c3cd85b89 --- /dev/null +++ b/docs/changelog/v3.2.x.rst @@ -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. diff --git a/fastf1/core.py b/fastf1/core.py index 814527889..7a4202e12 100644 --- a/fastf1/core.py +++ b/fastf1/core.py @@ -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 @@ -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. @@ -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 @@ -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` @@ -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: @@ -3050,20 +3063,32 @@ 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` @@ -3071,7 +3096,7 @@ def get_telemetry(self) -> 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() \ @@ -3079,8 +3104,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: diff --git a/fastf1/tests/test_laps.py b/fastf1/tests/test_laps.py index ebf4bac04..d36f98c26 100644 --- a/fastf1/tests/test_laps.py +++ b/fastf1/tests/test_laps.py @@ -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 + tel = drv_laps.get_telemetry(frequency=10) + assert (tel['Time'].diff().iloc[2:-2].unique() + == pd.Timedelta(0.1, 'seconds')) + + # test for + 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