diff --git a/CHANGELOG.md b/CHANGELOG.md
index 3d68502a4..74a4bec60 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -3,6 +3,7 @@
 ## Features
 
 -   Added NCA parameter set ([#824](https://github.com/pybamm-team/PyBaMM/pull/824))
+-   Added functionality to `Solution` that automatically gets `t_eval` from the data when simulating drive cycles and performs checks to ensure the output has the required resolution to accurately capture the input current ([#819](https://github.com/pybamm-team/PyBaMM/pull/819))
 -   Added options to export a solution to matlab or csv ([#811](https://github.com/pybamm-team/PyBaMM/pull/811))
 -   Allow porosity to vary in space ([#809](https://github.com/pybamm-team/PyBaMM/pull/809))
 -   Added functionality to solve DAE models with non-smooth current inputs ([#808](https://github.com/pybamm-team/PyBaMM/pull/808))
@@ -52,6 +53,7 @@
 
 ## Bug fixes
 
+-   Fixed a bug where the first line of the data wasn't loaded when parameters are loaded from data ([#819](https://github.com/pybamm-team/PyBaMM/pull/819))
 -   Made `graphviz` an optional dependency ([#810](https://github.com/pybamm-team/PyBaMM/pull/810))
 -   Fixed examples to run with basic pip installation ([#800](https://github.com/pybamm-team/PyBaMM/pull/800))
 -   Added events for CasADi solver when stepping ([#800](https://github.com/pybamm-team/PyBaMM/pull/800))
diff --git a/examples/scripts/drive_cycle.py b/examples/scripts/drive_cycle.py
new file mode 100644
index 000000000..1e9c708da
--- /dev/null
+++ b/examples/scripts/drive_cycle.py
@@ -0,0 +1,17 @@
+#
+# Simulate drive cycle loaded from csv file
+#
+import pybamm
+
+# load model and update parameters so the input current is the US06 drive cycle
+model = pybamm.lithium_ion.DFN()
+param = model.default_parameter_values
+param["Current function [A]"] = "[current data]US06"
+
+# create and run simulation using the CasadiSolver in "fast" mode, remembering to
+# pass in the updated parameters
+sim = pybamm.Simulation(
+    model, parameter_values=param, solver=pybamm.CasadiSolver(mode="fast")
+)
+sim.solve()
+sim.plot()
diff --git a/pybamm/__init__.py b/pybamm/__init__.py
index 5f48a2648..022ac6437 100644
--- a/pybamm/__init__.py
+++ b/pybamm/__init__.py
@@ -120,6 +120,7 @@ from .expression_tree.exceptions import (
     OptionError,
     ModelError,
     SolverError,
+    SolverWarning,
     ShapeError,
     ModelWarning,
     UndefinedOperationError,
diff --git a/pybamm/expression_tree/exceptions.py b/pybamm/expression_tree/exceptions.py
index 7097c475a..a71172cc4 100644
--- a/pybamm/expression_tree/exceptions.py
+++ b/pybamm/expression_tree/exceptions.py
@@ -37,6 +37,14 @@ class SolverError(Exception):
     pass
 
 
+class SolverWarning(UserWarning):
+    """
+    Solver warning: the chosen solver settings may not give the desired output
+    """
+
+    pass
+
+
 class ShapeError(Exception):
     """
     Shape error: cannot evaluate an object to find its shape
@@ -67,4 +75,3 @@ class InputError(Exception):
     """
 
     pass
-
diff --git a/pybamm/parameters/parameter_values.py b/pybamm/parameters/parameter_values.py
index a5a41afbf..aeb0fe7fa 100644
--- a/pybamm/parameters/parameter_values.py
+++ b/pybamm/parameters/parameter_values.py
@@ -227,7 +227,7 @@ class ParameterValues:
                         filename = os.path.join(path, value[6:] + ".csv")
                         function_name = value[6:]
                     data = pd.read_csv(
-                        filename, comment="#", skip_blank_lines=True
+                        filename, comment="#", skip_blank_lines=True, header=None
                     ).to_numpy()
                     # Save name and data
                     self._dict_items[name] = (function_name, data)
diff --git a/pybamm/simulation.py b/pybamm/simulation.py
index b16c83f46..9f3f02069 100644
--- a/pybamm/simulation.py
+++ b/pybamm/simulation.py
@@ -5,6 +5,8 @@ import pickle
 import pybamm
 import numpy as np
 import copy
+import warnings
+import sys
 
 
 def isnotebook():
@@ -317,10 +319,11 @@ class Simulation:
         Parameters
         ----------
         t_eval : numeric type, optional
-            The times at which to compute the solution. If None the model will
-            be solved for a full discharge (1 hour / C_rate) if the discharge
-            timescale is provided. Otherwise the model will be solved up to a
-            non-dimensional time of 1.
+            The times at which to compute the solution. If None and the parameter
+            "Current function [A]" is not read from data the model will
+            be solved for a full discharge (1 hour / C_rate). If None and the
+            parameter "Current function [A]" is read from data the model will be
+            solved at the times provided in the data.
         solver : :class:`pybamm.BaseSolver`
             The solver to use to solve the model.
         external_variables : dict
@@ -340,19 +343,68 @@ class Simulation:
             solver = self.solver
 
         if self.operating_mode == "without experiment":
-            # Solve the normal way, with a single solve
-            if t_eval is None:
-                try:
-                    # Try to compute discharge time
-                    tau = self._parameter_values.evaluate(self.model.param.timescale)
-                    C_rate = self._parameter_values["C-rate"]
-                    t_end = 3600 / tau / C_rate
-                    t_eval = np.linspace(0, t_end, 100)
-                except AttributeError:
-                    t_eval = np.linspace(0, 1, 100)
+            # For drive cycles (current provided as data) we perform additional tests
+            # on t_eval (if provided) to ensure the returned solution captures the
+            # input. If the current is provided as data then the "Current function [A]"
+            # is the tuple (filename, data).
+            if isinstance(self._parameter_values["Current function [A]"], tuple):
+                filename = self._parameter_values["Current function [A]"][0]
+                tau = self._parameter_values.evaluate(self.model.param.timescale)
+                time_data = (
+                    self._parameter_values["Current function [A]"][1][:, 0] / tau
+                )
+                # If no t_eval is provided, we use the times provided in the data.
+                if t_eval is None:
+                    pybamm.logger.info(
+                        "Setting t_eval as specified by the data '{}'".format(filename)
+                    )
+                    t_eval = time_data
+                # If t_eval is provided we first check if it contains all of the times
+                # in the data to within 10-12. If it doesn't, we then check
+                # that the largest gap in t_eval is smaller than the smallest gap in the
+                # time data (to ensure the resolution of t_eval is fine enough).
+                # We only raise a warning here as users may genuinely only want
+                # the solution returned at some specified points.
+                elif (
+                    set(np.round(time_data, 12)).issubset(set(np.round(t_eval, 12)))
+                ) is False:
+                    warnings.warn(
+                        """
+                        t_eval does not contain all of the time points in the data
+                        '{}'. Note: passing t_eval = None automatically sets t_eval
+                        to be the points in the data.
+                        """.format(
+                            filename
+                        ),
+                        pybamm.SolverWarning,
+                    )
+                    dt_data_min = np.min(np.diff(time_data))
+                    dt_eval_max = np.max(np.diff(t_eval))
+                    if dt_eval_max > dt_data_min + sys.float_info.epsilon:
+                        warnings.warn(
+                            """
+                            The largest timestep in t_eval ({}) is larger than
+                            the smallest timestep in the data ({}). The returned
+                            solution may not have the correct resolution to accurately
+                            capture the input. Try refining t_eval. Alternatively,
+                            passing t_eval = None automatically sets t_eval to be the
+                            points in the data.
+                            """.format(
+                                dt_eval_max, dt_data_min
+                            ),
+                            pybamm.SolverWarning,
+                        )
+            # If not using a drive cycle and t_eval is not provided, set t_eval
+            # to correspond to a single discharge
+            elif t_eval is None:
+                tau = self._parameter_values.evaluate(self.model.param.timescale)
+                C_rate = self._parameter_values["C-rate"]
+                t_end = 3600 / tau / C_rate
+                t_eval = np.linspace(0, t_end, 100)
 
             self.t_eval = t_eval
             self._solution = solver.solve(self.built_model, t_eval, inputs=inputs)
+
         elif self.operating_mode == "with experiment":
             if t_eval is not None:
                 pybamm.logger.warning(

fix t_eval to data for drive cycles
when simulating drive cycles the solvers work if `t_eval` is the same as the times provided in the data. when solving we should check if the current function has "[current data]" and then force the solve times to be those in the data (with a warning message that the solver is fixing t_eval). see below example

```
#
# Simulate drive cycle loaded from csv file
#
import pybamm
import numpy as np
import pandas as pd
import os

# load model
pybamm.set_logging_level("INFO")
model = pybamm.lithium_ion.DFN()

# create geometry
geometry = model.default_geometry

# get drive cycle data
cycle_name = "US06"
drive_cycle = pd.read_csv(
    os.path.join(pybamm.root_dir(), "input", "drive_cycles", cycle_name+".csv"),
    comment="#",
    skip_blank_lines=True
)
time_dim = drive_cycle.values[:, 0]
current_dim = drive_cycle.values[:, 1]

# load parameter values and process model and geometry
param = model.default_parameter_values
param["Current function [A]"] = "[current data]" + cycle_name
param.process_model(model)
param.process_geometry(geometry)

# set mesh
var = pybamm.standard_spatial_vars
var_pts = {var.x_n: 11, var.x_s: 11, var.x_p: 11, var.r_n: 5, var.r_p: 5}
mesh = pybamm.Mesh(geometry, model.default_submesh_types, var_pts)

# discretise model
disc = pybamm.Discretisation(mesh, model.default_spatial_methods)
disc.process_model(model)

# get dimensionless times for evaluation
tau = param.evaluate(pybamm.standard_parameters_lithium_ion.tau_discharge)
t_eval = time_dim / tau  # this works
# t_eval = np.linspace(0, 600 / tau, 600)  # this fails

# simulate US06 drive cycle
solver = pybamm.CasadiSolver(mode="fast")
solution = solver.solve(model, t_eval)

# plot
plot = pybamm.QuickPlot(solution)
plot.dynamic_plot()
```

Note that this works with Casadi in "fast" mode!
diff --git a/tests/unit/test_simulation.py b/tests/unit/test_simulation.py
index 5e3a090a4..c2aa884c2 100644
--- a/tests/unit/test_simulation.py
+++ b/tests/unit/test_simulation.py
@@ -1,5 +1,7 @@
 import pybamm
 import numpy as np
+import pandas as pd
+import os
 import unittest
 
 
@@ -347,6 +349,40 @@ class TestSimulation(unittest.TestCase):
         sim.solve(t_eval=t_eval)
         sim.plot(testing=True)
 
+    def test_drive_cycle_data(self):
+        model = pybamm.lithium_ion.SPM()
+        param = model.default_parameter_values
+        param["Current function [A]"] = "[current data]US06"
+
+        drive_cycle = pd.read_csv(
+            os.path.join(pybamm.root_dir(), "input", "drive_cycles", "US06.csv"),
+            comment="#",
+            skip_blank_lines=True,
+            header=None,
+        )
+        time_data = drive_cycle.values[:, 0]
+        tau = param.evaluate(pybamm.standard_parameters_lithium_ion.tau_discharge)
+
+        sim = pybamm.Simulation(model, parameter_values=param)
+
+        # check solution is returned at the times in the data (only almost equal due
+        # to multiplication by tau)
+        sim.solve()
+        np.testing.assert_array_almost_equal(sim.solution.t * tau, time_data)
+
+        # check warning raised if the largest gap in t_eval is bigger than the
+        # smallest gap in the data
+        sim.reset()
+        with self.assertWarns(pybamm.SolverWarning):
+            sim.solve(t_eval=np.linspace(0, 1, 100))
+
+        # check warning raised if t_eval doesnt conatin time_data , but has a finer
+        # resolution (can still solve, but good for users to know they dont have
+        # the solution returned at the data points)
+        sim.reset()
+        with self.assertWarns(pybamm.SolverWarning):
+            sim.solve(t_eval=np.linspace(0, time_data[-1] / tau, 800))
+
 
 if __name__ == "__main__":
     print("Add -v for more debug output")

pip install -e .[dev,docs]
parse_log_pytest
pytest
flake8 pytest
apt-get update apt-get install -y wget
3.7
pytest --no-header -rA --tb=line --color=no -p no:cacheprovider -W ignore::DeprecationWarning
alabaster==0.7.13
anyio==3.7.1
anytree==2.12.1
argon2-cffi==23.1.0
argon2-cffi-bindings==21.2.0
attrs @ file:///croot/attrs_1668696182826/work
autograd==1.6.2
Babel==2.14.0
backcall==0.2.0
beautifulsoup4==4.13.3
black==23.3.0
bleach==6.0.0
casadi==3.7.0
certifi @ file:///croot/certifi_1671487769961/work/certifi
cffi==1.15.1
charset-normalizer==3.4.1
click==8.1.8
comm==0.1.4
cycler==0.11.0
debugpy==1.7.0
decorator==5.1.1
defusedxml==0.7.1
docutils==0.17.1
entrypoints==0.4
exceptiongroup==1.2.2
fastjsonschema==2.21.1
flake8==5.0.4
flit_core @ file:///opt/conda/conda-bld/flit-core_1644941570762/work/source/flit_core
fonttools==4.38.0
future==1.0.0
guzzle-sphinx-theme==0.7.11
idna==3.10
imagesize==1.4.1
importlib-metadata==4.2.0
importlib-resources==5.12.0
iniconfig @ file:///home/linux1/recipes/ci/iniconfig_1610983019677/work
ipykernel==6.16.2
ipython==7.34.0
ipython-genutils==0.2.0
ipywidgets==8.1.5
jedi==0.19.2
Jinja2==3.1.6
json5==0.9.16
jsonschema==4.17.3
jupyter==1.1.1
jupyter-console==6.6.3
jupyter-server==1.24.0
jupyter_client==7.4.9
jupyter_core==4.12.0
jupyterlab==3.5.3
jupyterlab-pygments==0.2.2
jupyterlab_server==2.15.2
jupyterlab_widgets==3.0.13
kiwisolver==1.4.5
Levenshtein==0.23.0
MarkupSafe==2.1.5
matplotlib==3.5.3
matplotlib-inline==0.1.6
mccabe==0.7.0
mistune==3.0.2
mypy-extensions==1.0.0
nbclassic==1.2.0
nbclient==0.7.4
nbconvert==7.6.0
nbformat==5.8.0
nest-asyncio==1.6.0
notebook==6.5.7
notebook_shim==0.2.4
numpy==1.21.6
packaging @ file:///croot/packaging_1671697413597/work
pandas==1.3.5
pandocfilters==1.5.1
parso==0.8.4
pathspec==0.11.2
pexpect==4.9.0
pickleshare==0.7.5
Pillow==9.5.0
pkgutil_resolve_name==1.3.10
platformdirs==4.0.0
pluggy @ file:///tmp/build/80754af9/pluggy_1648042572264/work
prometheus-client==0.17.1
prompt_toolkit==3.0.48
psutil==7.0.0
ptyprocess==0.7.0
py @ file:///opt/conda/conda-bld/py_1644396412707/work
-e git+https://github.com/pybamm-team/PyBaMM.git@ad890a73b9325e83150fc5fa03b66db6c330faba#egg=pybamm
pycodestyle==2.9.1
pycparser==2.21
pyflakes==2.5.0
Pygments==2.17.2
pyparsing==3.1.4
pyrsistent==0.19.3
pytest==7.1.2
python-dateutil==2.9.0.post0
python-Levenshtein==0.23.0
pytz==2025.2
pyzmq==26.2.1
rapidfuzz==3.4.0
requests==2.31.0
scikit-fem==8.1.0
scipy==1.7.3
Send2Trash==1.8.3
six==1.17.0
sniffio==1.3.1
snowballstemmer==2.2.0
soupsieve==2.4.1
Sphinx==4.3.2
sphinxcontrib-applehelp==1.0.2
sphinxcontrib-devhelp==1.0.2
sphinxcontrib-htmlhelp==2.0.0
sphinxcontrib-jsmath==1.0.1
sphinxcontrib-qthelp==1.0.3
sphinxcontrib-serializinghtml==1.1.5
terminado==0.17.1
tinycss2==1.2.1
tomli @ file:///opt/conda/conda-bld/tomli_1657175507142/work
tornado==6.2
traitlets==5.9.0
typed-ast==1.5.5
typing_extensions==4.7.1
urllib3==2.0.7
wcwidth==0.2.13
webencodings==0.5.1
websocket-client==1.6.1
widgetsnbextension==4.0.13
zipp @ file:///croot/zipp_1672387121353/work

name: PyBaMM
channels:
  - defaults
  - https://repo.anaconda.com/pkgs/main
  - https://repo.anaconda.com/pkgs/r
  - conda-forge
dependencies:
  - _libgcc_mutex=0.1=main
  - _openmp_mutex=5.1=1_gnu
  - attrs=22.1.0=py37h06a4308_0
  - ca-certificates=2025.2.25=h06a4308_0
  - certifi=2022.12.7=py37h06a4308_0
  - flit-core=3.6.0=pyhd3eb1b0_0
  - importlib_metadata=4.11.3=hd3eb1b0_0
  - iniconfig=1.1.1=pyhd3eb1b0_0
  - ld_impl_linux-64=2.40=h12ee557_0
  - libffi=3.4.4=h6a678d5_1
  - libgcc-ng=11.2.0=h1234567_1
  - libgomp=11.2.0=h1234567_1
  - libstdcxx-ng=11.2.0=h1234567_1
  - ncurses=6.4=h6a678d5_0
  - openssl=1.1.1w=h7f8727e_0
  - packaging=22.0=py37h06a4308_0
  - pip=22.3.1=py37h06a4308_0
  - pluggy=1.0.0=py37h06a4308_1
  - py=1.11.0=pyhd3eb1b0_0
  - pytest=7.1.2=py37h06a4308_0
  - python=3.7.16=h7a1cb2a_0
  - readline=8.2=h5eee18b_0
  - setuptools=65.6.3=py37h06a4308_0
  - sqlite=3.45.3=h5eee18b_0
  - tk=8.6.14=h39e8969_0
  - tomli=2.0.1=py37h06a4308_0
  - wheel=0.38.4=py37h06a4308_0
  - xz=5.6.4=h5eee18b_1
  - zipp=3.11.0=py37h06a4308_0
  - zlib=1.2.13=h5eee18b_1
  - pip:
      - alabaster==0.7.13
      - anyio==3.7.1
      - anytree==2.12.1
      - argon2-cffi==23.1.0
      - argon2-cffi-bindings==21.2.0
      - autograd==1.6.2
      - babel==2.14.0
      - backcall==0.2.0
      - beautifulsoup4==4.13.3
      - black==23.3.0
      - bleach==6.0.0
      - casadi==3.7.0
      - cffi==1.15.1
      - charset-normalizer==3.4.1
      - click==8.1.8
      - comm==0.1.4
      - cycler==0.11.0
      - debugpy==1.7.0
      - decorator==5.1.1
      - defusedxml==0.7.1
      - docutils==0.17.1
      - entrypoints==0.4
      - exceptiongroup==1.2.2
      - fastjsonschema==2.21.1
      - flake8==5.0.4
      - fonttools==4.38.0
      - future==1.0.0
      - guzzle-sphinx-theme==0.7.11
      - idna==3.10
      - imagesize==1.4.1
      - importlib-metadata==4.2.0
      - importlib-resources==5.12.0
      - ipykernel==6.16.2
      - ipython==7.34.0
      - ipython-genutils==0.2.0
      - ipywidgets==8.1.5
      - jedi==0.19.2
      - jinja2==3.1.6
      - json5==0.9.16
      - jsonschema==4.17.3
      - jupyter==1.1.1
      - jupyter-client==7.4.9
      - jupyter-console==6.6.3
      - jupyter-core==4.12.0
      - jupyter-server==1.24.0
      - jupyterlab==3.5.3
      - jupyterlab-pygments==0.2.2
      - jupyterlab-server==2.15.2
      - jupyterlab-widgets==3.0.13
      - kiwisolver==1.4.5
      - levenshtein==0.23.0
      - markupsafe==2.1.5
      - matplotlib==3.5.3
      - matplotlib-inline==0.1.6
      - mccabe==0.7.0
      - mistune==3.0.2
      - mypy-extensions==1.0.0
      - nbclassic==1.2.0
      - nbclient==0.7.4
      - nbconvert==7.6.0
      - nbformat==5.8.0
      - nest-asyncio==1.6.0
      - notebook==6.5.7
      - notebook-shim==0.2.4
      - numpy==1.21.6
      - pandas==1.3.5
      - pandocfilters==1.5.1
      - parso==0.8.4
      - pathspec==0.11.2
      - pexpect==4.9.0
      - pickleshare==0.7.5
      - pillow==9.5.0
      - pkgutil-resolve-name==1.3.10
      - platformdirs==4.0.0
      - prometheus-client==0.17.1
      - prompt-toolkit==3.0.48
      - psutil==7.0.0
      - ptyprocess==0.7.0
      - pycodestyle==2.9.1
      - pycparser==2.21
      - pyflakes==2.5.0
      - pygments==2.17.2
      - pyparsing==3.1.4
      - pyrsistent==0.19.3
      - python-dateutil==2.9.0.post0
      - python-levenshtein==0.23.0
      - pytz==2025.2
      - pyzmq==26.2.1
      - rapidfuzz==3.4.0
      - requests==2.31.0
      - scikit-fem==8.1.0
      - scipy==1.7.3
      - send2trash==1.8.3
      - six==1.17.0
      - sniffio==1.3.1
      - snowballstemmer==2.2.0
      - soupsieve==2.4.1
      - sphinx==4.3.2
      - sphinxcontrib-applehelp==1.0.2
      - sphinxcontrib-devhelp==1.0.2
      - sphinxcontrib-htmlhelp==2.0.0
      - sphinxcontrib-jsmath==1.0.1
      - sphinxcontrib-qthelp==1.0.3
      - sphinxcontrib-serializinghtml==1.1.5
      - terminado==0.17.1
      - tinycss2==1.2.1
      - tornado==6.2
      - traitlets==5.9.0
      - typed-ast==1.5.5
      - typing-extensions==4.7.1
      - urllib3==2.0.7
      - wcwidth==0.2.13
      - webencodings==0.5.1
      - websocket-client==1.6.1
      - widgetsnbextension==4.0.13
prefix: /opt/conda/envs/PyBaMM

tests/unit/test_simulation.py::TestSimulation::test_drive_cycle_data
tests/unit/test_simulation.py::TestSimulation::test_basic_ops tests/unit/test_simulation.py::TestSimulation::test_get_variable_array tests/unit/test_simulation.py::TestSimulation::test_plot tests/unit/test_simulation.py::TestSimulation::test_reuse_commands tests/unit/test_simulation.py::TestSimulation::test_save_load tests/unit/test_simulation.py::TestSimulation::test_save_load_dae tests/unit/test_simulation.py::TestSimulation::test_set_crate tests/unit/test_simulation.py::TestSimulation::test_set_defaults tests/unit/test_simulation.py::TestSimulation::test_set_defaults2 tests/unit/test_simulation.py::TestSimulation::test_set_external_variable tests/unit/test_simulation.py::TestSimulation::test_solve tests/unit/test_simulation.py::TestSimulation::test_specs tests/unit/test_simulation.py::TestSimulation::test_step tests/unit/test_simulation.py::TestSimulation::test_step_with_inputs
pybamm/__init__.py pybamm/parameters/parameter_values.py pybamm/expression_tree/exceptions.py examples/scripts/drive_cycle.py pybamm/simulation.py CHANGELOG.md
pybamm/__init__.py pybamm/parameters/parameter_values.py pybamm/expression_tree/exceptions.py examples/scripts/drive_cycle.py pybamm/simulation.py CHANGELOG.md