diff --git a/kwant/physics/dispersion.py b/kwant/physics/dispersion.py
index 9934ad71a8f2ea236c09e31b239094adf5a994ce..94e8a6b0da18d274dc9c09b845fc7ccbecfc29fc 100644
--- a/kwant/physics/dispersion.py
+++ b/kwant/physics/dispersion.py
@@ -35,7 +35,8 @@ class Bands:
     An instance of this class can be called like a function.  Given a momentum
     (currently this must be a scalar as all infinite systems are quasi-1-d), it
     returns a NumPy array containing the eigenenergies of all modes at this
-    momentum
+    momentum. Velocities and velocity derivatives are calculated if the flag
+    ``deriv`` is set.
 
     Examples
     --------
@@ -57,9 +58,65 @@ class Bands:
         self.hop[:, : hop.shape[1]] = hop
         self.hop[:, hop.shape[1]:] = 0
 
-    def __call__(self, k):
-        # Note: Equation to solve is
-        #       (V^\dagger e^{ik} + H + V e^{-ik}) \psi = E \psi
+    def __call__(self, k, deriv=0):
+        """Calculate all energies :math:`E`, velocities :math:`v`
+        and velocity derivatives `v'` for a given momentum :math:`k`
+
+        :math:`E_n, \quad v_n = dE_n / dk, \quad v'_n = d^2E_n / dk^2,
+        \quad n \in \{0, nbands - 1\}`
+
+        :math:`nbands` is the number of open modes
+
+        Parameters
+        ----------
+        k : float
+            momentum
+
+        deriv : {0, 1, 2}, optional
+            Maximal derivative order to calculate. Default is zero
+
+
+        Returns
+        ----------
+        ener : numpy float array
+            energies (and optionally also higher momentum derivatives)
+
+            if deriv = 0
+                numpy float array of the energies :math:`E`, shape (nbands,)
+            if deriv > 0
+                numpy float array, shape (deriv + 1, nbands) of
+                energies and derivatives :math:`(E, E', E'')`
+
+        Notes
+        -----
+        *   The ordering of the energies and velocities is the same and
+            according to the magnitude of the energy eigenvalues.
+            Therefore, the bands are not continously ordered.
+        *   The curvature `E''` can be only calculated
+            for non-degenerate bands.
+        """
+        # Equation to solve is
+        # (V^\dagger e^{ik} + H + V e^{-ik}) \psi = E \psi
+        # we obtain the derivatives by perturbing around momentum k
+
         mat = self.hop * complex(math.cos(k), -math.sin(k))
-        mat += mat.conjugate().transpose() + self.ham
-        return np.sort(np.linalg.eigvalsh(mat).real)
+        ham = mat + mat.conjugate().transpose() + self.ham
+        if deriv == 0:
+            return np.sort(np.linalg.eigvalsh(ham).real)
+
+        ener, psis = np.linalg.eigh(ham)
+        h1 = 1j*(- mat + mat.conjugate().transpose())
+        ph1p = np.dot(psis.conjugate().transpose(), np.dot(h1, psis))
+        velo = np.real(np.diag(ph1p))
+        if deriv == 1:
+            return np.array([ener, velo])
+
+        ediff = ener.reshape(-1, 1) - ener.reshape(1, -1)
+        ediff = np.divide(1, ediff, out=np.zeros_like(ediff), where=ediff != 0)
+        h2 = - (mat + mat.conjugate().transpose())
+        curv = (np.real(np.diag(
+                np.dot(psis.conjugate().transpose(), np.dot(h2, psis)))) +
+                2 * np.sum(ediff * np.abs(ph1p)**2, axis=1))
+        if deriv == 2:
+            return np.array([ener, velo, curv])
+        raise NotImplementedError('deriv= {} not implemented'.format(deriv))
diff --git a/kwant/physics/tests/test_dispersion.py b/kwant/physics/tests/test_dispersion.py
index 414ac17854a8e491c8010900686f938b5f35d5ac..ec08b6ee202b01a24c51e5a7c7e357e7fc97345e 100644
--- a/kwant/physics/tests/test_dispersion.py
+++ b/kwant/physics/tests/test_dispersion.py
@@ -8,10 +8,12 @@
 
 from numpy.testing import assert_array_almost_equal, assert_almost_equal
 from pytest import raises
+from numpy import linspace
 
 import kwant
 from math import pi, cos, sin
 
+
 def test_band_energies(N=5):
     syst = kwant.Builder(kwant.TranslationalSymmetry((-1, 0)))
     lat = kwant.lattice.square()
@@ -26,6 +28,7 @@ def test_band_energies(N=5):
         assert_array_almost_equal(sorted(energies),
                                   sorted([2 - 2 * cos(k), 4 - 2 * cos(k)]))
 
+
 def test_same_as_lead():
     syst = kwant.Builder(kwant.TranslationalSymmetry((-1,)))
     lat = kwant.lattice.chain()
@@ -39,6 +42,7 @@ def test_same_as_lead():
     for momentum in momenta:
         assert_almost_equal(bands(momentum)[0], 0)
 
+
 def test_raise_nonhermitian():
     syst = kwant.Builder(kwant.TranslationalSymmetry((-1,)))
     lat = kwant.lattice.chain()
@@ -46,3 +50,59 @@ def test_raise_nonhermitian():
     syst[lat(0), lat(1)] = complex(cos(0.2), sin(0.2))
     syst = syst.finalized()
     raises(ValueError, kwant.physics.Bands, syst)
+
+
+def test_band_velocities():
+    syst = kwant.Builder(kwant.TranslationalSymmetry((-1, 0)))
+    lat = kwant.lattice.square()
+    syst[lat(0, 0)] = 1
+    syst[lat(0, 1)] = 3
+    syst[lat(1, 0), lat(0, 0)] = -1
+    syst[lat(1, 1), lat(0, 1)] = 2
+    bands = kwant.physics.Bands(syst.finalized())
+    eps = 1E-4
+    for k in linspace(-pi, pi, 200):
+        vel = bands(k, deriv=1)[1]
+        # higher order formula for first derivative to get required accuracy
+        num_vel = (- bands(k+2*eps) + bands(k-2*eps) +
+                   8*(bands(k+eps) - bands(k-eps))) / (12 * eps)
+        assert_array_almost_equal(vel, num_vel)
+
+
+def test_band_velocity_derivative():
+    syst = kwant.Builder(kwant.TranslationalSymmetry((-1, 0)))
+    lat = kwant.lattice.square()
+    syst[lat(0, 0)] = 1
+    syst[lat(0, 1)] = 3
+    syst[lat(1, 0), lat(0, 0)] = -1
+    syst[lat(1, 1), lat(0, 1)] = 2
+    bands = kwant.physics.Bands(syst.finalized())
+    eps = 1E-4
+    eps2 = eps * eps
+    c3 = 1 / 90
+    c2 = - 3 / 20
+    c1 = 3 / 2
+    c0 = - 49 / 18
+    for k in linspace(-pi, pi, 200):
+        dvel = bands(k, deriv=2)[2]
+        # higher order formula for second derivative to get required accuracy
+        num_dvel = (c3 * (bands(k+3*eps) + bands(k-3*eps)) +
+                    c2 * (bands(k+2*eps) + bands(k-2*eps)) +
+                    c1 * (bands(k+eps) + bands(k-eps)) +
+                    c0 * bands(k)) / eps2
+        assert_array_almost_equal(dvel, num_dvel)
+
+
+def test_raise_implemented():
+    syst = kwant.Builder(kwant.TranslationalSymmetry((-1, 0)))
+    lat = kwant.lattice.square()
+    syst[[lat(0, 0), lat(0, 1)]] = 3
+    syst[lat(0, 1), lat(0, 0)] = -1
+    syst[((lat(1, y), lat(0, y)) for y in range(2))] = -1
+    bands = kwant.physics.Bands(syst.finalized())
+    assert bands(1.).shape == (2,)
+    assert bands(1., deriv=0).shape == (2,)
+    assert bands(1., deriv=1).shape == (2, 2)
+    assert bands(1., deriv=2).shape == (3, 2)
+    raises(NotImplementedError, bands, 1., -1)
+    raises(NotImplementedError, bands, 1., 3)