#define FLEET
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace PHEMlightdll
{
public class CEP
{
#region Constructor
public CEP(VEHPHEMLightJSON.VEH Vehicle,
List<string> headerLineFCvalues,
List<List<double>> matrixFCvalues,
List<string> headerLinePollutants,
List<List<double>> matrixPollutants,
List<double> idlingFCvalues,
List<double> idlingPollutants)
{
_resistanceF0 = Vehicle.RollingResData.Fr0.Value;
_resistanceF1 = Vehicle.RollingResData.Fr1.Value;
_resistanceF2 = Vehicle.RollingResData.Fr2.Value;
_resistanceF3 = Vehicle.RollingResData.Fr3.Value;
_resistanceF4 = Vehicle.RollingResData.Fr4.Value;
_cWValue = Vehicle.VehicleData.Cw.Value;
_crossSectionalArea = Vehicle.VehicleData.A.Value;
_massVehicle = Vehicle.VehicleData.Mass.Value;
_vehicleLoading = Vehicle.VehicleData.Loading.Value;
_vehicleMassRot = Vehicle.VehicleData.RedMassWheel.Value;
CalcType = Vehicle.VehicleData.CalcType;
switch (CalcType)
{
case "Conv":
RatedPower = Vehicle.EngineData.ICEData.Prated.Value;
_engineRatedSpeed = Vehicle.EngineData.ICEData.nrated.Value;
_engineIdlingSpeed = Vehicle.EngineData.ICEData.Idling.Value;
break;
case "HEV":
// Power von beiden zusammen Rest bezogen auf ICE
RatedPower = Vehicle.EngineData.ICEData.Prated.Value + Vehicle.EngineData.EMData.Prated.Value;
_engineRatedSpeed = Vehicle.EngineData.ICEData.nrated.Value;
_engineIdlingSpeed = Vehicle.EngineData.ICEData.Idling.Value;
break;
case "BEV":
RatedPower = Vehicle.EngineData.EMData.Prated.Value;
_engineRatedSpeed = Vehicle.EngineData.EMData.nrated.Value;
_engineIdlingSpeed = 0;
break;
}
_effectiveWheelDiameter = Vehicle.VehicleData.WheelDiameter.Value;
HeavyVehicle = Vehicle.VehicleData.MassType == Constants.HeavyVehicle;
FuelType = Vehicle.VehicleData.FuelType;
_axleRatio = Vehicle.TransmissionData.AxelRatio.Value;
_auxPower = Vehicle.AuxiliariesData.Pauxnorm.Value;
_pNormV0 = Vehicle.FLDData.P_n_max_v0.Value / 3.6;
_pNormP0 = Vehicle.FLDData.P_n_max_p0.Value;
_pNormV1 = Vehicle.FLDData.P_n_max_v1.Value / 3.6;
_pNormP1 = Vehicle.FLDData.P_n_max_p1.Value;
// Init pollutant identifiers, unit and measures
List<string> FCvaluesIdentifier = new List<string>();
List<List<double>> FCvaluesMeasures = new List<List<double>>();
List<List<double>> normalizedFCvaluesMeasures = new List<List<double>>();
for (int i = 0; i < headerLineFCvalues.Count; i++)
{
FCvaluesIdentifier.Add(headerLineFCvalues[i]);
FCvaluesMeasures.Add(new List<double>());
normalizedFCvaluesMeasures.Add(new List<double>());
}
// Init pollutant identifiers, unit and measures
List<string> pollutantIdentifier = new List<string>();
List<List<double>> pollutantMeasures = new List<List<double>>();
List<List<double>> normalizedPollutantMeasures = new List<List<double>>();
for (int i = 0; i < headerLinePollutants.Count; i++)
{
pollutantIdentifier.Add(headerLinePollutants[i]);
pollutantMeasures.Add(new List<double>());
normalizedPollutantMeasures.Add(new List<double>());
}
// Assigning values for speed rotational table
_speedPatternRotational = new List<double>();
for (int i = 0; i < Vehicle.TransmissionData.Transm["Speed"].Count; i++)
_speedPatternRotational.Add(Vehicle.TransmissionData.Transm["Speed"][i] / 3.6);
_gearTransmissionCurve = Vehicle.TransmissionData.Transm["GearRatio"];
_speedCurveRotational = Vehicle.TransmissionData.Transm["RotMassF"];
// Assigning values for drag table
_nNormTable = Vehicle.FLDData.DragCurve["n_norm"];
_dragNormTable = Vehicle.FLDData.DragCurve["pe_drag_norm"];
// Looping through matrix and assigning values for FC values
_powerPatternFCvalues = new List<double>();
_normalizedPowerPatternFCvalues = new List<double>();
int headerFCCount = headerLineFCvalues.Count;
for (int i = 0; i < matrixFCvalues.Count; i++)
{
for (int j = 0; j < matrixFCvalues[i].Count; j++)
{
if (matrixFCvalues[i].Count != headerFCCount + 1)
return;
if (j == 0)
{
_normalizedPowerPatternFCvalues.Add(matrixFCvalues[i][j]);
_powerPatternFCvalues.Add(matrixFCvalues[i][j] * RatedPower);
}
else
{
FCvaluesMeasures[j - 1].Add(matrixFCvalues[i][j] * RatedPower);
normalizedFCvaluesMeasures[j - 1].Add(matrixFCvalues[i][j]);
}
}
}
_cepCurveFCvalues = new Dictionary<string, List<double>>();
_idlingValueFCvalues = new Dictionary<string, double>();
_normedCepCurveFCvalues = new Dictionary<string, List<double>>();
for (int i = 0; i < headerLineFCvalues.Count; i++)
{
_cepCurveFCvalues.Add(FCvaluesIdentifier[i], FCvaluesMeasures[i]);
_normedCepCurveFCvalues.Add(FCvaluesIdentifier[i], normalizedFCvaluesMeasures[i]);
_idlingValueFCvalues.Add(FCvaluesIdentifier[i], idlingFCvalues[i] * RatedPower);
}
// looping through matrix and assigning values for pollutants
double pollutantMultiplyer = 1;
DrivingPower = NormalizingPower = CalcPower(Constants.NORMALIZING_SPEED, Constants.NORMALIZING_ACCELARATION, 0, (CalcType == "HEV" | CalcType == "BEV"));
if (HeavyVehicle)
{
NormalizingPower = RatedPower;
NormalizingType = eNormalizingType.RatedPower;
pollutantMultiplyer = RatedPower;
}
else
{
NormalizingPower = DrivingPower;
NormalizingType = eNormalizingType.DrivingPower;
}
_powerPatternPollutants = new List<double>();
_normailzedPowerPatternPollutants = new List<double>();
_cepNormalizedCurvePollutants = new Dictionary<string, List<double>>();
int headerCount = headerLinePollutants.Count;
for (int i = 0; i < matrixPollutants.Count; i++)
{
for (int j = 0; j < matrixPollutants[i].Count; j++)
{
if (matrixPollutants[i].Count != headerCount + 1)
return;
if (j == 0)
{
_normailzedPowerPatternPollutants.Add(matrixPollutants[i][j]);
_powerPatternPollutants.Add(matrixPollutants[i][j] * NormalizingPower);
}
else
{
pollutantMeasures[j - 1].Add(matrixPollutants[i][j] * pollutantMultiplyer);
normalizedPollutantMeasures[j - 1].Add(matrixPollutants[i][j]);
}
}
}
_cepCurvePollutants = new Dictionary<string, List<double>>();
_idlingValuesPollutants = new Dictionary<string, double>();
for (int i = 0; i < headerLinePollutants.Count; i++)
{
_cepCurvePollutants.Add(pollutantIdentifier[i], pollutantMeasures[i]);
_cepNormalizedCurvePollutants.Add(pollutantIdentifier[i], normalizedPollutantMeasures[i]);
_idlingValuesPollutants.Add(pollutantIdentifier[i], idlingPollutants[i] * pollutantMultiplyer);
}
_FleetMix = new Dictionary<string, double>();
_FleetMix.Add(Constants.strGasoline, 0);
_FleetMix.Add(Constants.strDiesel, 0);
_FleetMix.Add(Constants.strCNG, 0);
_FleetMix.Add(Constants.strLPG, 0);
}
#endregion
#if FLEET
#region ConstrutorForFleetmix
private CEP(bool heavyVehicle,
double vehicleMass,
double vehicleLoading,
double vehicleMassRot,
double crossArea,
double cWValue,
double f0,
double f1,
double f2,
double f3,
double f4,
double axleRatio,
double auxPower,
double ratedPower,
double engineIdlingSpeed,
double engineRatedSpeed,
double effictiveWheelDiameter,
double pNormV0,
double pNormP0,
double pNormV1,
double pNormP1)
{
_resistanceF0 = f0;
_resistanceF1 = f1;
_resistanceF2 = f2;
_resistanceF3 = f3;
_resistanceF4 = f4;
_cWValue = cWValue;
_crossSectionalArea = crossArea;
_massVehicle = vehicleMass;
_vehicleLoading = vehicleLoading;
_vehicleMassRot = vehicleMassRot;
RatedPower = ratedPower;
_engineIdlingSpeed = engineIdlingSpeed;
_engineRatedSpeed = engineRatedSpeed;
_effectiveWheelDiameter = effictiveWheelDiameter;
_axleRatio = axleRatio;
_auxPower = auxPower;
_pNormV0 = pNormV0;
_pNormP0 = pNormP0;
_pNormV1 = pNormV1;
_pNormP1 = pNormP1;
HeavyVehicle = heavyVehicle;
}
#endregion
#endif
public bool HeavyVehicle { get; }
public string FuelType { get; private set; }
public string CalcType { get; private set; }
#region NormalizingType
public enum eNormalizingType
{
RatedPower,
DrivingPower
}
public eNormalizingType NormalizingType { get; private set; }
#endregion
public double RatedPower { get; set; }
public double NormalizingPower { get; private set; }
public double DrivingPower { get; set; }
#region Private Members
protected double _massVehicle;
protected double _vehicleLoading;
protected double _vehicleMassRot;
protected double _crossSectionalArea;
protected double _cWValue;
protected double _resistanceF0;
protected double _resistanceF1;
protected double _resistanceF2;
protected double _resistanceF3;
protected double _resistanceF4;
protected double _axleRatio;
protected double _auxPower;
protected double _pNormV0;
protected double _pNormP0;
protected double _pNormV1;
protected double _pNormP1;
protected double _engineRatedSpeed;
protected double _engineIdlingSpeed;
protected double _effectiveWheelDiameter;
protected List<double> _speedPatternRotational;
protected List<double> _powerPatternFCvalues;
protected List<double> _normalizedPowerPatternFCvalues;
protected List<double> _normailzedPowerPatternPollutants;
protected List<double> _powerPatternPollutants;
protected Dictionary<string, List<double>> _cepCurveFCvalues;
protected Dictionary<string, List<double>> _normedCepCurveFCvalues;
protected List<double> _gearTransmissionCurve;
protected List<double> _speedCurveRotational;
protected Dictionary<string, List<double>> _cepCurvePollutants;
protected Dictionary<string, List<double>> _cepNormalizedCurvePollutants;
protected Dictionary<string, double> _FleetMix;
protected Dictionary<string, double> _idlingValueFCvalues;
protected Dictionary<string, double> _idlingValuesPollutants;
protected List<double> _nNormTable;
protected List<double> _dragNormTable;
#endregion
#region CalcPower
public double CalcPower(double speed, double acc, double gradient, bool HBEV)
{
//Declaration
double power = 0;
double rotFactor = GetRotationalCoeffecient(speed);
double powerAux = (_auxPower * RatedPower);
//Calculate the power
power += (_massVehicle + _vehicleLoading) * Constants.GRAVITY_CONST * (_resistanceF0 + _resistanceF1 * speed + _resistanceF4 * Math.Pow(speed, 4)) * speed;
power += (_crossSectionalArea * _cWValue * Constants.AIR_DENSITY_CONST / 2) * Math.Pow(speed, 3);
power += (_massVehicle * rotFactor + _vehicleMassRot + _vehicleLoading) * acc * speed;
power += (_massVehicle + _vehicleLoading) * Constants.GRAVITY_CONST * gradient * 0.01 * speed;
power /= 1000;
power /= Constants._DRIVE_TRAIN_EFFICIENCY;
if (!HBEV)
power += powerAux;
//Return result
return power;
}
public double CalcWheelPower(double speed, double acc, double gradient)
{
//Declaration
double power = 0;
double rotFactor = GetRotationalCoeffecient(speed);
//Calculate the power
power += (_massVehicle + _vehicleLoading) * Constants.GRAVITY_CONST * (_resistanceF0 + _resistanceF1 * speed + _resistanceF4 * Math.Pow(speed, 4)) * speed;
power += (_crossSectionalArea * _cWValue * Constants.AIR_DENSITY_CONST / 2) * Math.Pow(speed, 3);
power += (_massVehicle * rotFactor + _vehicleMassRot + _vehicleLoading) * acc * speed;
power += (_massVehicle + _vehicleLoading) * Constants.GRAVITY_CONST * gradient * 0.01 * speed;
power /= 1000;
//Return result
return power;
}
#endregion
#region CalcEngPower
public double CalcEngPower(double power)
{
if (power < _powerPatternFCvalues.First()) return _powerPatternFCvalues.First();
if (power > _powerPatternFCvalues.Last()) return _powerPatternFCvalues.Last();
return power;
}
#endregion
#region GetEmission
public Dictionary<string, double> GetAllEmission(double power, double speed, Helpers VehicleClass, bool SetZero = false)
{
//Declaration
Dictionary<string, double> Emi = new Dictionary<string, double>();
if (!SetZero)
{
//FC values
foreach (string id in _cepCurveFCvalues.Keys)
{
if (id.ToUpper() == "FC_EL" & VehicleClass.pClass == Constants.strBEV)
Emi.Add(id.ToUpper(), GetEmission(id, power, speed, VehicleClass) + _auxPower * RatedPower);
else
Emi.Add(id.ToUpper(), GetEmission(id, power, speed, VehicleClass));
}
//Emission
foreach (string id in _cepCurvePollutants.Keys)
{
if (VehicleClass.pClass != Constants.strBEV)
{
Emi.Add(id.ToUpper(), GetEmission(id, power, speed, VehicleClass));
}
else
{
//If BEV set all emissions to 0
Emi.Add(id.ToUpper(), 0);
}
}
if (!Emi.ContainsKey("CO2"))
{
if (Emi.ContainsKey("FC") & Emi.ContainsKey("CO") & Emi.ContainsKey("HC") & VehicleClass.pClass != Constants.strBEV)
Emi.Add("CO2", GetCO2Emission(Emi["FC"], Emi["CO"], Emi["HC"], VehicleClass));
else
Emi.Add("CO2", 0);
}
}
else
{
foreach (string id in _cepCurveFCvalues.Keys)
{
if (VehicleClass.pClass == "Mix" & id.ToUpper() == "FC_EL")
Emi.Add(id, GetEmission(id, power, speed, VehicleClass));
else
Emi.Add(id.ToUpper(), 0);
}
foreach (string id in _cepCurvePollutants.Keys)
{
Emi.Add(id.ToUpper(), 0);
}
if (!Emi.ContainsKey("CO2")) Emi.Add("CO2", 0);
}
//Return value
return Emi;
}
private double GetEmission(string pollutant, double power, double speed, Helpers VehicleClass)
{
//Declaration
List<double> emissionCurve = new List<double>();
List<double> powerPattern = new List<double>();
// bisection search to find correct position in power pattern
int upperIndex;
int lowerIndex;
if (Math.Abs(speed) <= Constants.ZERO_SPEED_ACCURACY)
{
if (!_cepCurvePollutants.ContainsKey(pollutant) & !_cepCurveFCvalues.ContainsKey(pollutant))
{
VehicleClass.ErrMsg = "Emission pollutant or fuel value " + pollutant + " not found!";
return 0;
}
if (_cepCurveFCvalues.ContainsKey(pollutant))
return _idlingValueFCvalues[pollutant];
else if (_cepCurvePollutants.ContainsKey(pollutant))
return _idlingValuesPollutants[pollutant];
}
if (!_cepCurvePollutants.ContainsKey(pollutant) & !_cepCurveFCvalues.ContainsKey(pollutant))
{
VehicleClass.ErrMsg = "Emission pollutant or fuel value " + pollutant + " not found!";
return 0;
}
if (_cepCurveFCvalues.ContainsKey(pollutant))
{
emissionCurve = _cepCurveFCvalues[pollutant];
powerPattern = _powerPatternFCvalues;
}
else if (_cepCurvePollutants.ContainsKey(pollutant))
{
emissionCurve = _cepCurvePollutants[pollutant];
powerPattern = _powerPatternPollutants;
}
if (emissionCurve.Count == 0)
{
VehicleClass.ErrMsg = "Empty emission curve for " + pollutant + " found!";
return 0;
}
if (emissionCurve.Count == 1)
{
return emissionCurve[0];
}
// in case that the demanded power is smaller than the first entry (smallest) in the power pattern the first is returned (should never happen)
if (power <= powerPattern.First())
{
return emissionCurve[0];
}
// if power bigger than all entries in power pattern return the last (should never happen)
if (power >= powerPattern.Last())
{
return emissionCurve.Last();
}
FindLowerUpperInPattern(out lowerIndex, out upperIndex, powerPattern, power);
return Interpolate(power, powerPattern[lowerIndex], powerPattern[upperIndex], emissionCurve[lowerIndex], emissionCurve[upperIndex]);
}
#endregion
#if FLEET
#region GetNormedEmission
private double GetNormedEmission(string pollutant, double power, double speed, Helpers VehicleClass)
{
//Declaration
List<double> emissionCurve = new List<double>();
List<double> powerPattern = new List<double>();
// bisection search to find correct position in power pattern
int upperIndex;
int lowerIndex;
if (!_cepCurvePollutants.ContainsKey(pollutant) & !_cepCurveFCvalues.ContainsKey(pollutant))
{
VehicleClass.ErrMsg = "Emission pollutant or fuel value " + pollutant + " not found!";
return 0;
}
if (_cepCurveFCvalues.ContainsKey(pollutant))
{
emissionCurve = _normedCepCurveFCvalues[pollutant];
powerPattern = _normalizedPowerPatternFCvalues;
}
else if (_cepCurvePollutants.ContainsKey(pollutant))
{
emissionCurve = _cepNormalizedCurvePollutants[pollutant];
powerPattern = _normailzedPowerPatternPollutants;
}
if (emissionCurve.Count == 0)
{
VehicleClass.ErrMsg = "Empty emission curve for " + pollutant + " found!";
return 0;
}
if (emissionCurve.Count == 1)
{
return emissionCurve[0];
}
// in case that the demanded power is smaller than the first entry (smallest) in the power pattern the first is returned (should never happen)
if (power <= powerPattern.First())
{
return emissionCurve[0];
}
// if power bigger than all entries in power pattern the last is returned (should never happen)
if (power >= powerPattern.Last())
{
return emissionCurve.Last();
}
FindLowerUpperInPattern(out lowerIndex, out upperIndex, powerPattern, power);
return Interpolate(power, powerPattern[lowerIndex], powerPattern[upperIndex], emissionCurve[lowerIndex], emissionCurve[upperIndex]);
}
#endregion
#endif
#region GetCO2Emission
public double GetCO2Emission(double _FC, double _CO, double _HC, Helpers VehicleClass)
{
//Declaration
double fCBr, fCHC, fCCO, fCCO2;
fCBr = 0;
fCHC = 0;
fCCO = 0;
fCCO2 = 0;
if (FuelType != "Mix")
{
if (!GetfcVals(FuelType, ref fCBr, ref fCHC, ref fCCO, ref fCCO2, VehicleClass))
return 0;
}
else
{
if (!CalcfCValMix(ref fCBr, ref fCHC, ref fCCO, ref fCCO2, VehicleClass))
return 0;
}
return (_FC * fCBr - _CO * fCCO - _HC * fCHC) / fCCO2;
}
//Calculate the weighted fuel factor values for Fleetmix
private bool CalcfCValMix(ref double _fCBr, ref double _fCHC, ref double _fCCO, ref double _fCCO2, Helpers VehicleClass)
{
//Declaration
double Sum = 0;
double sumfCBr, sumfCHC, sumfCCO, sumfCCO2;
//Initialise
sumfCBr = 0;
sumfCHC = 0;
sumfCCO = 0;
sumfCCO2 = 0;
//calculate the sum
foreach (string id in _FleetMix.Keys)
{
Sum += _FleetMix[id];
}
//Calculate the weighted fuel factors
if (Sum <= 0)
{
VehicleClass.ErrMsg = "All propolsion types in the fleetshares file are not known!";
return false;
}
else
{
foreach (string id in _FleetMix.Keys)
{
if (!GetfcVals(id, ref _fCBr, ref _fCHC, ref _fCCO, ref _fCCO2, VehicleClass))
{
return false;
}
else
{
sumfCBr += _fCBr * _FleetMix[id] / Sum;
sumfCHC += _fCHC * _FleetMix[id] / Sum;
sumfCCO += _fCCO * _FleetMix[id] / Sum;
sumfCCO2 += _fCCO2 * _FleetMix[id] / Sum;
}
}
}
//Result values
_fCBr = sumfCBr;
_fCHC = sumfCHC;
_fCCO = sumfCCO;
_fCCO2 = sumfCCO2;
return true;
}
// Get the fuel factor values
private bool GetfcVals(string _fuelTypex, ref double _fCBr, ref double _fCHC, ref double _fCCO, ref double _fCCO2, Helpers VehicleClass)
{
_fCHC = 0.866;
_fCCO = 0.429;
_fCCO2 = 0.273;
switch (_fuelTypex)
{
case Constants.strGasoline:
_fCBr = 0.865;
break;
case Constants.strDiesel:
_fCBr = 0.863;
break;
case Constants.strCNG:
_fCBr = 0.693;
_fCHC = 0.803;
break;
case Constants.strLPG:
_fCBr = 0.825;
_fCHC = 0.825;
break;
default:
VehicleClass.ErrMsg = "The propolsion type is not known! (" + FuelType + ")";
return false;
}
return true;
}
#endregion
#region GetDecelCoast
public double GetDecelCoast(double speed, double acc, double gradient)
{
//Declaration
int upperIndex;
int lowerIndex;
if (speed < Constants.SPEED_DCEL_MIN)
{
return speed / Constants.SPEED_DCEL_MIN * GetDecelCoast(Constants.SPEED_DCEL_MIN, acc, gradient);
}
double rotCoeff = GetRotationalCoeffecient(speed);
FindLowerUpperInPattern(out lowerIndex, out upperIndex, _speedPatternRotational, speed);
double iGear = Interpolate(speed,
_speedPatternRotational[lowerIndex],
_speedPatternRotational[upperIndex],
_gearTransmissionCurve[lowerIndex],
_gearTransmissionCurve[upperIndex]);
double iTot = iGear * _axleRatio;
double n = (30 * speed * iTot) / ((_effectiveWheelDiameter / 2) * Math.PI);
double nNorm = (n - _engineIdlingSpeed) / (_engineRatedSpeed - _engineIdlingSpeed);
FindLowerUpperInPattern(out lowerIndex, out upperIndex, _nNormTable, nNorm);
double fMot = 0;
if (speed >= 10e-2)
{
fMot = (-Interpolate(nNorm,
_nNormTable[lowerIndex],
_nNormTable[upperIndex],
_dragNormTable[lowerIndex],
_dragNormTable[upperIndex]) * RatedPower * 1000 / speed) / Constants.DRIVE_TRAIN_EFFICIENCY;
}
double fRoll = (_resistanceF0
+ _resistanceF1 * speed
+ Math.Pow(_resistanceF2 * speed, 2)
+ Math.Pow(_resistanceF3 * speed, 3)
+ Math.Pow(_resistanceF4 * speed, 4)) * (_massVehicle + _vehicleLoading) * Constants.GRAVITY_CONST;
double fAir = _cWValue * _crossSectionalArea * Constants.AIR_DENSITY_CONST * 0.5 * Math.Pow(speed, 2);
double fGrad = (_massVehicle + _vehicleLoading) * Constants.GRAVITY_CONST * gradient / 100;
return -(fMot + fRoll + fAir + fGrad) / ((_massVehicle + _vehicleLoading) * rotCoeff);
}
#endregion
#region GetRotationalCoeffecient
public double GetRotationalCoeffecient(double speed)
{
//Declaration
int upperIndex;
int lowerIndex;
FindLowerUpperInPattern(out lowerIndex, out upperIndex, _speedPatternRotational, speed);
return Interpolate(speed,
_speedPatternRotational[lowerIndex],
_speedPatternRotational[upperIndex],
_speedCurveRotational[lowerIndex],
_speedCurveRotational[upperIndex]);
}
#endregion
#if FLEET
#region GetGearCoeffecient
public double GetGearCoeffecient(double speed)
{
//Declaration
int upperIndex;
int lowerIndex;
FindLowerUpperInPattern(out lowerIndex, out upperIndex, _speedPatternRotational, speed);
return Interpolate(speed,
_speedPatternRotational[lowerIndex],
_speedPatternRotational[upperIndex],
_gearTransmissionCurve[lowerIndex],
_gearTransmissionCurve[upperIndex]);
}
#endregion
#region GetDragCoeffecient
public double GetDragCoeffecient(double nNorm)
{
//Declaration
int upperIndex;
int lowerIndex;
FindLowerUpperInPattern(out lowerIndex, out upperIndex, _nNormTable, nNorm);
return Interpolate(nNorm,
_nNormTable[lowerIndex],
_nNormTable[upperIndex],
_dragNormTable[lowerIndex],
_dragNormTable[upperIndex]);
}
#endregion
#endif
#region FindLowerUpperInPattern
private void FindLowerUpperInPattern(out int lowerIndex, out int upperIndex, List<double> pattern, double value)
{
lowerIndex = 0;
upperIndex = 0;
if (value <= pattern.First())
{
lowerIndex = 0;
upperIndex = 0;
return;
}
if (value >= pattern.Last())
{
lowerIndex = pattern.Count - 1;
upperIndex = pattern.Count - 1;
return;
}
// bisection search to find correct position in power pattern
int middleIndex = (pattern.Count - 1) / 2;
upperIndex = pattern.Count - 1;
lowerIndex = 0;
while (upperIndex - lowerIndex > 1)
{
if (pattern[middleIndex] == value)
{
lowerIndex = middleIndex;
upperIndex = middleIndex;
return;
}
else if (pattern[middleIndex] < value)
{
lowerIndex = middleIndex;
middleIndex = (upperIndex - lowerIndex) / 2 + lowerIndex;
}
else
{
upperIndex = middleIndex;
middleIndex = (upperIndex - lowerIndex) / 2 + lowerIndex;
}
}
if (pattern[lowerIndex] <= value && value < pattern[upperIndex])
{
return;
}
}
#endregion
#region Interpolate
private double Interpolate(double px, double p1, double p2, double e1, double e2)
{
if (p2 == p1)
return e1;
return e1 + (px - p1) / (p2 - p1) * (e2 - e1);
}
#endregion
#region GetMaxAccel
public double GetMaxAccel(double speed, double gradient, bool HBEV)
{
double rotFactor = GetRotationalCoeffecient(speed);
double pMaxForAcc = GetPMaxNorm(speed) * RatedPower - CalcPower(speed, 0, gradient, HBEV);
return (pMaxForAcc * 1000) / ((_massVehicle * rotFactor + _vehicleMassRot + _vehicleLoading) * speed);
}
#endregion
#region GetPMaxNorm
private double GetPMaxNorm(double speed)
{
// Linear function between v0 and v1, constant elsewhere
if (speed <= _pNormV0)
return _pNormP0;
else if (speed >= _pNormV1)
return _pNormP1;
else
{
return Interpolate(speed, _pNormV0, _pNormV1, _pNormP0, _pNormP1);
}
}
#endregion
//--------------------------------------------------------------------------------------------------
// Operators for fleetmix
//--------------------------------------------------------------------------------------------------
#if FLEET
#region AddRangeCeps
public static CEP AddRangeCeps(CEP[] cps, Helpers Helper)
{
#region SingleValues
CEP newCEP = new CEP(cps.Select(p => p.HeavyVehicle ? 1 : 0).Sum() > 0,
cps.Select(p => p._massVehicle).Sum(),
cps.Select(p => p._vehicleLoading).Sum(),
cps.Select(p => p._vehicleMassRot).Sum(),
cps.Select(p => p._crossSectionalArea).Sum(),
cps.Select(p => p._cWValue).Sum(),
cps.Select(p => p._resistanceF0).Sum(),
cps.Select(p => p._resistanceF1).Sum(),
cps.Select(p => p._resistanceF2).Sum(),
cps.Select(p => p._resistanceF3).Sum(),
cps.Select(p => p._resistanceF4).Sum(),
cps.Select(p => p._axleRatio).Sum(),
cps.Select(p => p._auxPower).Sum(),
cps.Select(p => p.RatedPower).Sum(),
cps.Select(p => p._engineIdlingSpeed).Sum(),
cps.Select(p => p._engineRatedSpeed).Sum(),
cps.Select(p => p._effectiveWheelDiameter).Sum(),
cps.Select(p => p._pNormV0).Sum(),
cps.Select(p => p._pNormP0).Sum(),
cps.Select(p => p._pNormV1).Sum(),
cps.Select(p => p._pNormP1).Sum());
#region Fleetmix and Fueltype
if (cps.Select(p => p.FuelType).Min() == cps.Select(p => p.FuelType).Max())
newCEP.FuelType = cps.First().FuelType;
else
newCEP.FuelType = "Mix";
newCEP._FleetMix = new Dictionary<string, double>();
foreach (string id in cps.First()._FleetMix.Keys)
{
newCEP._FleetMix.Add(id, cps.Select(p => p._FleetMix[id]).Sum());
}
#endregion
#endregion
#region SpeedRotationalTable
double minSpeedRotational = cps.Select(p => p._speedPatternRotational.First()).Min();
double maxSpeedRotational = cps.Select(p => p._speedPatternRotational.Last()).Max();
newCEP._speedPatternRotational
= CreatePattern(minSpeedRotational,
maxSpeedRotational,
Constants.SPEED_ROTATIONAL_INCREMENT);
newCEP._speedCurveRotational = new List<double>();
newCEP._gearTransmissionCurve = new List<double>();
for (int i = 0; i < newCEP._speedPatternRotational.Count; i++)
{
newCEP._speedCurveRotational.Add(cps.Select(p => p.GetRotationalCoeffecient(newCEP._speedPatternRotational[i])).Sum());
newCEP._gearTransmissionCurve.Add(cps.Select(p => p.GetGearCoeffecient(newCEP._speedPatternRotational[i])).Sum());
}
#endregion
#region NormalizingPower
newCEP.DrivingPower = newCEP.CalcPower(Constants.NORMALIZING_SPEED, Constants.NORMALIZING_ACCELARATION, 0, (Helper.pClass == Constants.strBEV | Helper.uClass == Constants.strHybrid));
if (newCEP.HeavyVehicle)
{
newCEP.NormalizingPower = newCEP.RatedPower;
newCEP.NormalizingType = eNormalizingType.RatedPower;
}
else
{
newCEP.NormalizingPower = newCEP.DrivingPower;
newCEP.NormalizingType = eNormalizingType.DrivingPower;
}
#endregion
#region FC
double minNormPowerPatternFC = cps.Select(p => p._normalizedPowerPatternFCvalues.First()).Min();
double maxNormPowerPatternFC = cps.Select(p => p._normalizedPowerPatternFCvalues.Last()).Max();
newCEP._normalizedPowerPatternFCvalues
= CreatePattern(minNormPowerPatternFC,
maxNormPowerPatternFC,
Constants.POWER_FC_INCREMENT);
newCEP._cepCurveFCvalues = new Dictionary<string, List<double>>();
newCEP._normedCepCurveFCvalues = new Dictionary<string, List<double>>();
newCEP._powerPatternFCvalues = new List<double>();
foreach (string id in cps.First()._cepCurveFCvalues.Keys)
{
newCEP._cepCurveFCvalues.Add(id, new List<double>());
newCEP._normedCepCurveFCvalues.Add(id, new List<double>());
}
for (int i = 0; i < newCEP._normalizedPowerPatternFCvalues.Count; i++)
{
foreach (string id in newCEP._cepCurveFCvalues.Keys)
{
double newCepVal = cps.Select(p => p.GetNormedEmission(id, newCEP._normalizedPowerPatternFCvalues[i], double.MaxValue, Helper)).Sum();
newCEP._cepCurveFCvalues[id].Add(newCepVal * newCEP.RatedPower);
newCEP._normedCepCurveFCvalues[id].Add(newCepVal);
}
newCEP._powerPatternFCvalues.Add(newCEP._normalizedPowerPatternFCvalues[i] * newCEP.RatedPower);
}
#endregion
#region Pollutants
double minNormPowerPattern = cps.Select(p => p._normailzedPowerPatternPollutants.First()).Min();
double maxNormPowerPattern = cps.Select(p => p._normailzedPowerPatternPollutants.Last()).Max();
newCEP._normailzedPowerPatternPollutants
= CreatePattern(minNormPowerPattern,
maxNormPowerPattern,
Constants.POWER_POLLUTANT_INCREMENT);
newCEP._cepCurvePollutants = new Dictionary<string, List<double>>();
newCEP._cepNormalizedCurvePollutants = new Dictionary<string, List<double>>();
newCEP._powerPatternPollutants = new List<double>();
foreach (string id in cps.First()._cepCurvePollutants.Keys)
{
newCEP._cepCurvePollutants.Add(id, new List<double>());
newCEP._cepNormalizedCurvePollutants.Add(id, new List<double>());
}
for (int i = 0; i < newCEP._normailzedPowerPatternPollutants.Count; i++)
{
foreach (string id in newCEP._cepCurvePollutants.Keys)
{
if (newCEP.NormalizingType == eNormalizingType.RatedPower)
{
double newCepVal = cps.Select(p => p.GetNormedEmission(id, newCEP._normailzedPowerPatternPollutants[i], double.MaxValue, Helper)).Sum();
newCEP._cepCurvePollutants[id].Add(newCepVal * newCEP.RatedPower);
newCEP._cepNormalizedCurvePollutants[id].Add(newCepVal);
}
else
{
newCEP._cepCurvePollutants[id].Add(cps.Select(p => p.GetEmission(id, newCEP._normailzedPowerPatternPollutants[i] * p.NormalizingPower, double.MaxValue, Helper)).Sum());
newCEP._cepNormalizedCurvePollutants[id].Add(cps.Select(p => p.GetNormedEmission(id, newCEP._normailzedPowerPatternPollutants[i], double.MaxValue, Helper)).Sum());
}
}
newCEP._powerPatternPollutants.Add(newCEP._normailzedPowerPatternPollutants[i] * newCEP.NormalizingPower);
}
#endregion
#region IdlingValues
newCEP._idlingValueFCvalues = new Dictionary<string, double>();
newCEP._idlingValuesPollutants = new Dictionary<string, double>();
foreach (string id in cps.First()._idlingValueFCvalues.Keys)
{
newCEP._idlingValueFCvalues.Add(id, cps.Select(p => p._idlingValueFCvalues[id]).Sum());
}
foreach (string id in cps.First()._idlingValuesPollutants.Keys)
{
newCEP._idlingValuesPollutants.Add(id, cps.Select(p => p._idlingValuesPollutants[id]).Sum());
}
#endregion
#region TragTable
double minTragTable = cps.Select(p => p._nNormTable.First()).Min();
double maxTragTable = cps.Select(p => p._nNormTable.Last()).Max();
newCEP._nNormTable
= CreatePattern(minTragTable,
maxTragTable,
Constants.NNORM_INCREMENT);
newCEP._dragNormTable = new List<double>();
for (int i = 0; i < newCEP._nNormTable.Count; i++)
{
newCEP._dragNormTable.Add(cps.Select(p => p.GetDragCoeffecient(newCEP._nNormTable[i])).Sum());
}
#endregion
return newCEP;
}
#endregion
#region Operator *
public static CEP operator *(CEP cp1, double d)
{
#region SingleValues
CEP newCEP = new CEP(cp1.HeavyVehicle,
d * cp1._massVehicle,
d * cp1._vehicleLoading,
d * cp1._vehicleMassRot,
d * cp1._crossSectionalArea,
d * cp1._cWValue,
d * cp1._resistanceF0,
d * cp1._resistanceF1,
d * cp1._resistanceF2,
d * cp1._resistanceF3,
d * cp1._resistanceF4,
d * cp1._axleRatio,
d * cp1._auxPower,
d * cp1.RatedPower,
d * cp1._engineIdlingSpeed,
d * cp1._engineRatedSpeed,
d * cp1._effectiveWheelDiameter,
d * cp1._pNormV0,
d * cp1._pNormP0,
d * cp1._pNormV1,
d * cp1._pNormP1);
#region Fleetmix and Fueltype
newCEP.FuelType = cp1.FuelType;
newCEP._FleetMix = new Dictionary<string, double>();
foreach (string id in cp1._FleetMix.Keys)
{
if (newCEP.FuelType == id)
newCEP._FleetMix.Add(newCEP.FuelType, d);
else
newCEP._FleetMix.Add(id, 0);
}
#endregion
#endregion
#region SpeedRotationalTable
newCEP._speedPatternRotational = new List<double>(cp1._speedPatternRotational);
newCEP._speedCurveRotational = new List<double>(cp1._speedCurveRotational.Select(p => p * d));
newCEP._gearTransmissionCurve = new List<double>(cp1._gearTransmissionCurve.Select(p => p * d));
#endregion
#region NormalizingPower
newCEP.DrivingPower = newCEP.CalcPower(Constants.NORMALIZING_SPEED, Constants.NORMALIZING_ACCELARATION, 0, (cp1.CalcType == "HEV" | cp1.CalcType == "BEV"));
if (newCEP.HeavyVehicle)
{
newCEP.NormalizingPower = newCEP.RatedPower;
newCEP.NormalizingType = eNormalizingType.RatedPower;
}
else
{
newCEP.NormalizingPower = newCEP.DrivingPower;
newCEP.NormalizingType = eNormalizingType.DrivingPower;
}
#endregion
#region FC
newCEP._powerPatternFCvalues = new List<double>(cp1._powerPatternFCvalues.Select(p => p * d));
newCEP._normalizedPowerPatternFCvalues = new List<double>(cp1._normalizedPowerPatternFCvalues);
newCEP._cepCurveFCvalues = new Dictionary<string, List<double>>();
newCEP._normedCepCurveFCvalues = new Dictionary<string, List<double>>();
foreach (string id in cp1._cepCurveFCvalues.Keys)
{
newCEP._cepCurveFCvalues.Add(id, new List<double>(cp1._cepCurveFCvalues[id].Select(p => p * d)));
newCEP._normedCepCurveFCvalues.Add(id, new List<double>(cp1._normedCepCurveFCvalues[id].Select(p => p * d)));
}
#endregion
#region Pollutants
newCEP._powerPatternPollutants = new List<double>(cp1._normailzedPowerPatternPollutants.Select(p => p * newCEP.NormalizingPower));
newCEP._normailzedPowerPatternPollutants = new List<double>(cp1._normailzedPowerPatternPollutants);
newCEP._cepCurvePollutants = new Dictionary<string, List<double>>();
newCEP._cepNormalizedCurvePollutants = new Dictionary<string, List<double>>();
foreach (string id in cp1._cepCurvePollutants.Keys)
{
newCEP._cepCurvePollutants.Add(id, new List<double>(cp1._cepCurvePollutants[id].Select(p => p * d)));
newCEP._cepNormalizedCurvePollutants.Add(id, new List<double>(cp1._cepNormalizedCurvePollutants[id].Select(p => p * d)));
}
#endregion
#region IdlingValues
newCEP._idlingValueFCvalues = new Dictionary<string, double>();
newCEP._idlingValuesPollutants = new Dictionary<string, double>();
foreach (string id in cp1._idlingValueFCvalues.Keys)
{
newCEP._idlingValueFCvalues.Add(id,
cp1._idlingValueFCvalues[id] * d);
}
foreach (string id in cp1._idlingValuesPollutants.Keys)
{
newCEP._idlingValuesPollutants.Add(id,
cp1._idlingValuesPollutants[id] * d);
}
#endregion
#region DragTable
newCEP._nNormTable = new List<double>(cp1._nNormTable);
newCEP._dragNormTable = new List<double>(cp1._dragNormTable.Select(p => p * d));
#endregion
return newCEP;
}
#endregion
#region CreatePattern
static public List<double> CreatePattern(double min, double max, double increment)
{
//Declaration
List<double> pattern = new List<double>();
double actualMin = min;
double actualMax = max;
if (min < 0)
actualMin = Math.Ceiling(min / increment) * increment;
else
actualMin = Math.Floor(min / increment) * increment;
if (max < 0)
actualMax = Math.Floor(max / increment) * increment;
else
actualMax = Math.Ceiling(max / increment) * increment;
double curVal = actualMin;
while (curVal <= actualMax)
{
pattern.Add(curVal);
curVal += increment;
}
return pattern;
}
#endregion
#region CheckClass
public static bool CheckClass(CEP[] cps)
{
return cps.Select(p => p.HeavyVehicle ? 1 : 0).Min() == cps.Select(p => p.HeavyVehicle ? 1 : 0).Max();
}
#endregion
#endif
}
}