<gh_stars>0
#!/usr/bin/env python3
import unittest
import numpy as np

from cereal import log
import cereal.messaging as messaging
from selfdrive.config import Conversions as CV
from selfdrive.controls.lib.lead_mpc_lib.lead_mpc import RW, LeadMpc


class FakePubMaster():
  def send(self, s, data):
    assert data


def run_following_distance_simulation(v_lead, t_end=200.0):
  dt = 0.2
  t = 0.

  x_lead = 200.0

  x_ego = 0.0
  v_ego = v_lead
  a_ego = 0.0

  mpc = LeadMpc(0)

  first = True
  while t < t_end:

    # Setup CarState
    CS = messaging.new_message('carState')
    CS.carState.vEgo = float(v_ego)
    CS.carState.aEgo = float(a_ego)

    # Setup model packet
    radarstate = messaging.new_message('radarState')
    lead = log.RadarState.LeadData.new_message()
    lead.modelProb = .75
    lead.dRel = x_lead - x_ego
    lead.vLead = v_lead
    lead.aLeadK = 0.0
    lead.status = True
    radarstate.radarState.leadOne = lead

    # Run MPC
    mpc.set_cur_state(v_ego, a_ego)
    if first:  # Make sure MPC is converged on first timestep
      for _ in range(20):
        mpc.update(CS.carState, radarstate.radarState, 0)
    mpc.update(CS.carState, radarstate.radarState, 0)

    # Choose slowest of two solutions
    v_ego, a_ego = float(mpc.v_solution[5]), float(mpc.a_solution[5])

    # Update state
    x_lead += v_lead * dt
    x_ego += v_ego * dt
    t += dt
    first = False

  return x_lead - x_ego


class TestFollowingDistance(unittest.TestCase):
  def test_following_distanc(self):
    for speed_mph in np.linspace(10, 100, num=10):
      v_lead = float(speed_mph * CV.MPH_TO_MS)

      simulation_steady_state = run_following_distance_simulation(v_lead)
      correct_steady_state = RW(v_lead, v_lead) + 4.0

      self.assertAlmostEqual(simulation_steady_state, correct_steady_state, delta=.2)


if __name__ == "__main__":
  unittest.main()
