obd-0.2.0.0: src/System/Hardware/ELM327/Car/MAP.hs
{-# LANGUAGE NoImplicitPrelude #-}
-- | A car that uses the intake manifold absolute pressure (MAP) to
-- calculate fuel consumption.
module System.Hardware.ELM327.Car.MAP (
MAPProperties(..)
, defaultProperties
, mapCar
) where
import Control.Lens ((^. ), (.~))
import Control.Monad.IO.Class (MonadIO)
import Numeric.Units.Dimensional.Prelude
import System.Hardware.ELM327.Connection (ConT)
import System.Hardware.ELM327.Car (CarT, Car, defaultCar)
import qualified System.Hardware.ELM327.Car as Car
-- | Some fixed values needed to implement a MAP car.
data MAPProperties = MAPProperties { volumetricEfficiency :: Dimensionless Double
, engineDisplacement :: Volume Double
, airFuelRatio :: Dimensionless Double
, fuelMassDensity :: MassDensity Double }
-- | The default MAP properties
defaultProperties :: MAPProperties
defaultProperties = MAPProperties { volumetricEfficiency = 0.75 *~ one -- consumer engine
, engineDisplacement = 1198 *~ cubic (centi meter) -- 1.2l
, airFuelRatio = 14.7 *~ one -- chemically ideal
, fuelMassDensity = 750 *~ (kilo gram / cubic meter) -- EUROSUPER 95
}
-- | Create a car that uses the intake manifold absolute pressure (MAP)
-- to calculate fuel consumption.
mapCar :: MonadIO m => MAPProperties -> Car (ConT m)
mapCar p = (\c -> (Car.massAirFlowRate .~ massAirFlowRate' p c) c) .
(\c -> (Car.engineFuelRate .~ engineFuelRate' p c) c) $
defaultCar
-- | Calculate MAF from RPM, MAP and IAT
--
-- See https://web.archive.org/web/20160323073219/http://www.lightner.net/obd2guru/IMAP_AFcalc.html
massAirFlowRate' :: Monad m => MAPProperties -> Car m -> CarT m (MassFlow Double)
massAirFlowRate' p c = do
rpm <- c ^. Car.engineRPM
map' <- c ^. Car.intakeManifoldAbsolutePressure
iat <- c ^. Car.intakeAirTemperature
let imap = rpm * map' / iat / (2 *~ one)
let voleff = volumetricEfficiency p
let displ = engineDisplacement p
let mm = 28.97 *~ (gram / mole)
let r = 8.314 *~ (joule / kelvin / mole)
return $ imap * voleff * displ * mm / r
-- | Calculate the engine fuel rate from MAF
engineFuelRate' :: Monad m => MAPProperties -> Car m -> CarT m (VolumeFlow Double)
engineFuelRate' p c = do
maf <- c ^. Car.massAirFlowRate
return $ maf / airFuelRatio p / fuelMassDensity p