#define FLEET
using System;
using System.IO;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Reflection;
namespace PHEMlightdll
{
public class Start
{
private List<string> _DataPath;
private CEPHandler DataInput;
public Helpers Helper = new Helpers();
//******************* Parameters of Array or Single calculation *******************
//********************************* INPUT ******************************************
//*** DATATYP | UNIT | VARIBLE | Description ***
//List<string> | [-] | DataFiles (VEH, FC, EMI)| Name of file (e.g. "PC_D_EU4" path neede if not in "Default Vehicles") or aggregated name (PC, HDV, BUS, TW) by FleetMix calculation
//List<double> / double | [s] | Time | Time signal
//List<double> / double | [m/s] | Velocity | Velocity signal
//double | [m/s^2]| acc | Acceleration (ONLY NEDDED BY SINGLE CALCULATION)
//List<double> / double | [%] | Gradient | Gradient of the route
//out List<VehicleResult> | [-] | VehicleResultsOrg | Returned result list
//bool | [-] | fleetMix = false | Optional parameter if fleetMix should be calculate
//string | [-] | CommentPref = "c" | Optional parameter for comment prefix
//********************************* OUPUT: VehicleResultsOrg **********************
//*** DATATYP | UNIT | VARIBLE | Description ***
//double | [s] | time | Time
//double | [m/s] | speed | Velocity
//double | [kW] | power | Calculated power at the engine (ICE for conventional and HEV vehicles, electric engine for BEVs) including engine inertia and auxiliaries; not limited for engine fullload and braking limitations
//double | [kW] | P_pos | Positive engine power limited with engine rated power
//double | [-] | pNormRated | Engine power normalised with rated engine power and limited with the power range (fullload and drag) as specified in the characteristic curve for fuel consumption
//double | [-] | pNormDrive | Engine power normalised with "P_drive" and limited with the power range (fullload and drag) as specified in the characteristic curve for emissions
//double | [m/s^2]| acc | Caclulated/given acceleration
//double | [g/h] | fc | Calculated fuel consumption (Different unit for BEV vehicles)
// | [kWh/h]| |
//double | [g/h] | cO2 | Calculated CO2 emissions
//double | [g/h] | NOx | Calculated NOx emissions
//double | [g/h] | HC | Calculated HC emissions
//double | [g/h] | PM | Calculated PM emissions
//double | [g/h] | CO | Calculated CO emissions
#region calculate
//Calculate data from array
public bool CALC_Array(List<string> DataFiles,
List<double> Time,
List<double> Velocity,
List<double> Gradient,
out List<VehicleResult> VehicleResultsOrg,
bool fleetMix = false,
string CommentPref = "c")
{
//Declaration
int i;
double acc;
List<VehicleResult> _VehicleResult = new List<VehicleResult>();
//Initialisation
Helper.ErrMsg = null;
//Borrow
Helper.CommentPrefix = CommentPref;
_DataPath = new List<string>();
//Set path by normal calculation (on given) and set path by fleetmix (on Default Vehicles) calculation
for (i = 0; i < DataFiles.Count; i++)
{
if ((DataFiles[i].LastIndexOf(@"\")) >= 0)
{
_DataPath.Add(DataFiles[i]);
}
else
{
//_DataPath.Add(Assembly.GetExecutingAssembly().Location.Substring(0, Assembly.GetExecutingAssembly().Location.LastIndexOf(@"\")) + @"\Default Vehicles\" + Helper.PHEMDataV);
_DataPath.Add(DataFiles[i + 1].Substring(0, DataFiles[i + 1].LastIndexOf(@"\")));
_DataPath.Add(DataFiles[i + 1].Substring(0, DataFiles[i + 1].LastIndexOf(@"\")));
_DataPath.Add(DataFiles[i + 1].Substring(0, DataFiles[i + 1].LastIndexOf(@"\")));
i += 1;
}
}
//Read the vehicle and emission data
#if FLEET
if (fleetMix)
{
//Set the vehicle class
Helper.gClass = _DataPath[0];
//Generate the class
DataInput = new CEPHandler();
//Read the FleetShares
if (!DataInput.ReadFleetShares(DataFiles[1], Helper))
{
VehicleResultsOrg = null;
return false;
}
//Read the vehicle and emission data
if (!DataInput.GetFleetCEP(_DataPath, DataFiles[0], Helper))
{
VehicleResultsOrg = null;
return false;
}
}
else
#endif
{
//Get vehicle string
if (!Helper.setclass(DataFiles[0]))
{
VehicleResultsOrg = null;
return false;
}
//Generate the class
DataInput = new CEPHandler();
//Read the vehicle and emission data
if (!DataInput.GetCEP(_DataPath, Helper))
{
VehicleResultsOrg = null;
return false;
}
}
//Calculate emissions per second
for (i = 1; i <= Time.Count - 1; i++)
{
//Calculate the acceleration
acc = (Velocity[i] - Velocity[i - 1]) / (Time[i] - Time[i - 1]);
//Calculate and save the data in the List
_VehicleResult.Add(PHEMLight.CreateVehicleStateData(Helper,
DataInput.CEPS[Helper.gClass],
Time[i - 1],
Velocity[i - 1],
acc,
Gradient[i - 1]));
if (Helper.ErrMsg != null)
{
VehicleResultsOrg = null;
return false;
}
}
VehicleResultsOrg = _VehicleResult;
return true;
}
//Calculate single data
public bool CALC_Single(List<string> DataFiles,
double Time,
double Velocity,
double acc,
double Gradient,
out List<VehicleResult> VehicleResultsOrg,
bool fleetMix = false,
string CommentPref = "c")
{
//Declaration
List<VehicleResult> _VehicleResult = new List<VehicleResult>();
VehicleResultsOrg = _VehicleResult;
//Borrow
Helper.CommentPrefix = CommentPref;
_DataPath = new List<string>();
//Set path by normal calculation (on given) and set path by fleetmix (on Fleetshare file) calculation
for (int i = 0; i < DataFiles.Count; i++)
{
if ((DataFiles[i].LastIndexOf(@"\")) >= 0)
{
_DataPath.Add(DataFiles[i]);
}
else
{
//_DataPath.Add(Assembly.GetExecutingAssembly().Location.Substring(0, Assembly.GetExecutingAssembly().Location.LastIndexOf(@"\")) + @"\Default Vehicles\" + Helper.PHEMDataV);
_DataPath.Add(DataFiles[i + 1].Substring(0, DataFiles[i + 1].LastIndexOf(@"\")));
_DataPath.Add(DataFiles[i + 1].Substring(0, DataFiles[i + 1].LastIndexOf(@"\")));
_DataPath.Add(DataFiles[i + 1].Substring(0, DataFiles[i + 1].LastIndexOf(@"\")));
i += 1;
}
}
//Read the vehicle and emission data
#if FLEET
if (fleetMix)
{
//Set the vehicle class
Helper.gClass = "AggClass_" + DataFiles[0];
//Generate the class
DataInput = new CEPHandler();
//Read the FleetShares
if (!DataInput.ReadFleetShares(DataFiles[1], Helper))
{
VehicleResultsOrg = null;
return false;
}
//Read the vehicle and emission data
if (!DataInput.GetFleetCEP(_DataPath, DataFiles[0], Helper))
{
VehicleResultsOrg = null;
return false;
}
}
else
#endif
{
//Get vehicle string
if (!Helper.setclass(DataFiles[0]))
{
VehicleResultsOrg = null;
return false;
}
//Generate the class
DataInput = new CEPHandler();
//Read the vehicle and emission data
if (!DataInput.GetCEP(_DataPath, Helper))
{
VehicleResultsOrg = null;
return false;
}
}
//Calculate and save the data in the List
_VehicleResult.Add(PHEMLight.CreateVehicleStateData(Helper,
DataInput.CEPS[Helper.gClass],
Time,
Velocity,
acc,
Gradient));
VehicleResultsOrg = _VehicleResult;
return true;
}
#endregion
#region ExportData
public bool ExportData(string path, string vehicle, List<VehicleResult> _VehicleResult)
{
if (path == null || vehicle == null || _VehicleResult == null || _VehicleResult.Count == 0) return false;
//Write head
StringBuilder allLines = new StringBuilder();
string lineEnding = "\r\n";
allLines.AppendLine("Vehicletype: ," + vehicle);
allLines.AppendLine("Time, Speed, Gradient, Accelaration, Engine power raw, P_pos, P_norm_rated, P_norm_drive, FC, Electric Power, CO2, NOx, CO, HC, PM");
allLines.AppendLine("[s], [m/s], [%], [m/s^2], [kW], [kW], [-], [-], [g/h], [kWh/h], [g/h], [g/h], [g/h], [g/h], [g/h]");
//Write data
foreach (VehicleResult Result in _VehicleResult)
{
allLines.Append(Result.Time.ToString("0.0000", CultureInfo.InvariantCulture) + ",");
allLines.Append(Result.Speed.ToString("0.0000", CultureInfo.InvariantCulture) + ",");
allLines.Append(Result.Grad.ToString("0.0000", CultureInfo.InvariantCulture) + ",");
allLines.Append(Result.Accelaration.ToString("0.0000", CultureInfo.InvariantCulture) + ",");
allLines.Append(Result.Power.ToString("0.0000", CultureInfo.InvariantCulture) + ",");
allLines.Append(Result.PPos.ToString("0.0000", CultureInfo.InvariantCulture) + ",");
allLines.Append(Result.PNormRated.ToString("0.0000", CultureInfo.InvariantCulture) + ",");
allLines.Append(Result.PNormDrive.ToString("0.0000", CultureInfo.InvariantCulture) + ",");
allLines.Append(Result.EmissionData.FC.ToString("0.0000", CultureInfo.InvariantCulture) + ",");
allLines.Append(Result.EmissionData.FCel.ToString("0.0000", CultureInfo.InvariantCulture) + ",");
allLines.Append(Result.EmissionData.CO2.ToString("0.0000", CultureInfo.InvariantCulture) + ",");
allLines.Append(Result.EmissionData.NOx.ToString("0.0000", CultureInfo.InvariantCulture) + ",");
allLines.Append(Result.EmissionData.CO.ToString("0.0000", CultureInfo.InvariantCulture) + ",");
allLines.Append(Result.EmissionData.HC.ToString("0.0000", CultureInfo.InvariantCulture) + ",");
allLines.Append(Result.EmissionData.PM.ToString("0.0000", CultureInfo.InvariantCulture) + lineEnding);
}
// Write the string to a file.
if (path.IndexOf(".", 0) < 0)
{
path = path + ".sta";
}
try
{
StreamWriter file = new StreamWriter(path);
file.WriteLine(allLines);
file.Close();
return true;
}
catch (Exception ex)
{
return false;
}
}
public bool ExportSumData(string path, string vehicle, string cycle, VehicleResult _VehicleResult)
{
if (path == null || vehicle == null || cycle == null || _VehicleResult == null) return false;
StringBuilder allLines = new StringBuilder();
if (path.IndexOf(".", 0) < 0)
{
path = path + ".erg";
}
if (!File.Exists(path))
{
//Write head
allLines.AppendLine("PHEMLight Results");
allLines.AppendLine("");
allLines.AppendLine("Vehicle, Cycle, Time, Speed, Gradient, Accelaration, Engine power raw, P_pos, P_norm_rated, P_norm_drive, FC, Electric Power, CO2, NOx, CO, HC, PM");
allLines.AppendLine("[-], [-], [s], [km/h], [%], [m/s^2], [kW], [kW], [-], [-], [g/km], [kWh/km], [g/km], [g/km], [g/km], [g/km], [g/km]");
}
//Write data
allLines.Append(vehicle + ",");
allLines.Append(cycle + ",");
allLines.Append(_VehicleResult.Time.ToString("0.0000", CultureInfo.InvariantCulture) + ",");
allLines.Append(_VehicleResult.Speed.ToString("0.0000", CultureInfo.InvariantCulture) + ",");
allLines.Append(_VehicleResult.Grad.ToString("0.0000", CultureInfo.InvariantCulture) + ",");
allLines.Append(_VehicleResult.Accelaration.ToString("0.0000", CultureInfo.InvariantCulture) + ",");
allLines.Append(_VehicleResult.Power.ToString("0.0000", CultureInfo.InvariantCulture) + ",");
allLines.Append(_VehicleResult.PPos.ToString("0.0000", CultureInfo.InvariantCulture) + ",");
allLines.Append(_VehicleResult.PNormRated.ToString("0.0000", CultureInfo.InvariantCulture) + ",");
allLines.Append(_VehicleResult.PNormDrive.ToString("0.0000", CultureInfo.InvariantCulture) + ",");
allLines.Append(_VehicleResult.EmissionData.FC.ToString("0.0000", CultureInfo.InvariantCulture) + ",");
allLines.Append(_VehicleResult.EmissionData.FCel.ToString("0.0000", CultureInfo.InvariantCulture) + ",");
allLines.Append(_VehicleResult.EmissionData.CO2.ToString("0.0000", CultureInfo.InvariantCulture) + ",");
allLines.Append(_VehicleResult.EmissionData.NOx.ToString("0.0000", CultureInfo.InvariantCulture) + ",");
allLines.Append(_VehicleResult.EmissionData.CO.ToString("0.0000", CultureInfo.InvariantCulture) + ",");
allLines.Append(_VehicleResult.EmissionData.HC.ToString("0.0000", CultureInfo.InvariantCulture) + ",");
allLines.Append(_VehicleResult.EmissionData.PM.ToString("0.0000", CultureInfo.InvariantCulture));
// Write the string to a file.
try
{
StreamWriter file = new StreamWriter(path, true);
file.WriteLine(allLines);
file.Close();
return true;
}
catch (Exception ex)
{
return false;
}
}
public VehicleResult GenerateSumData(List<VehicleResult> _VehicleResult)
{
//Declaration
double sum_time = 0;
double sum_speed = 0;
double sum_grad = 0;
double sum_power = 0;
double sum_pPos = 0;
double sum_pNormRated = 0;
double sum_pNormDrive = 0;
double sum_acc = 0;
double sum_fc = 0;
double sum_fcel = 0;
double sum_cO2 = 0;
double sum_nOx = 0;
double sum_hC = 0;
double sum_pM = 0;
double sum_cO = 0;
if (_VehicleResult == null || _VehicleResult.Count == 0) return new VehicleResult(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
//Write data
foreach (VehicleResult Result in _VehicleResult)
{
sum_speed += Result.Speed * 3.6;
sum_power += Result.Power;
if (Result.PPos > 0) { sum_pPos += Result.PPos; }
sum_grad += Result.Grad;
sum_pNormRated += Result.PNormRated;
sum_pNormDrive += Result.PNormDrive;
sum_acc += Result.Accelaration;
sum_fcel += Result.EmissionData.FCel;
sum_fc += Result.EmissionData.FC;
sum_cO2 += Result.EmissionData.CO2;
sum_nOx += Result.EmissionData.NOx;
sum_hC += Result.EmissionData.HC;
sum_pM += Result.EmissionData.PM;
sum_cO += Result.EmissionData.CO;
}
//Build average
sum_time = _VehicleResult[_VehicleResult.Count - 1].Time - _VehicleResult[0].Time;
sum_power /= _VehicleResult.Count;
sum_pPos /= _VehicleResult.Count;
sum_grad /= _VehicleResult.Count;
sum_pNormRated /= _VehicleResult.Count;
sum_pNormDrive /= _VehicleResult.Count;
sum_acc /= _VehicleResult.Count;
if (sum_speed > 0)
{
sum_fc /= sum_speed;
sum_fcel /= sum_speed;
sum_cO2 /= sum_speed;
sum_nOx /= sum_speed;
sum_hC /= sum_speed;
sum_pM /= sum_speed;
sum_cO /= sum_speed;
}
else
{
sum_fc = 0;
sum_fcel = 0;
sum_cO2 = 0;
sum_nOx = 0;
sum_hC = 0;
sum_pM = 0;
sum_cO = 0;
}
sum_speed /= _VehicleResult.Count;
return new VehicleResult(sum_time,
sum_speed,
sum_grad,
sum_power,
sum_pPos,
sum_pNormRated,
sum_pNormDrive,
sum_acc,
sum_fc,
sum_fcel,
sum_cO2,
sum_nOx,
sum_hC,
sum_pM,
sum_cO);
}
#endregion
}
//Calculation
class PHEMLight
{
#region CreateVehicleStateData
static public VehicleResult CreateVehicleStateData(Helpers Helper,
CEP currCep,
double time,
double inputSpeed,
double inputAcc,
double Gradient = 0)
{
//Declaration
double speed = Math.Max(inputSpeed, 0);
double acc;
double P_pos;
//Speed/Acceleration limitation
if (speed == 0)
acc = 0;
else
acc = Math.Min(inputAcc, currCep.GetMaxAccel(speed, Gradient));
//Calculate the power
double power = currCep.CalcPower(speed, acc, Gradient);
double P_eng = currCep.CalcEngPower(power);
//Power limitation
if (P_eng >= 0)
P_pos = power;
else
P_pos = 0;
//Calculate the result values (BEV)
if (Helper.tClass == Constants.strBEV)
{
return new VehicleResult(time,
speed,
Gradient,
power,
P_pos,
P_eng / currCep.RatedPower,
P_eng / currCep.DrivingPower,
acc,
0,
currCep.GetEmission("FC", power, speed, Helper),
0,
0,
0,
0,
0);
}
//Calculate the decel costing
double decelCoast = currCep.GetDecelCoast(speed, acc, Gradient);
//Calculate the result values (Zero emissions by costing, Idling emissions by v <= 0.5m/s²)
if (acc >= decelCoast || speed <= Constants.ZERO_SPEED_ACCURACY)
{
return new VehicleResult(time,
speed,
Gradient,
power,
P_pos,
P_eng / currCep.RatedPower,
P_eng / currCep.DrivingPower,
acc,
currCep.GetEmission("FC", power, speed, Helper),
0,
currCep.GetCO2Emission(currCep.GetEmission("FC", power, speed, Helper), currCep.GetEmission("CO", power, speed, Helper), currCep.GetEmission("HC", power, speed, Helper), Helper),
currCep.GetEmission("NOx", power, speed, Helper),
currCep.GetEmission("HC", power, speed, Helper),
currCep.GetEmission("PM", power, speed, Helper),
currCep.GetEmission("CO", power, speed, Helper));
}
else
{
return new VehicleResult(time,
speed,
Gradient,
power,
P_pos,
power / currCep.RatedPower,
power / currCep.DrivingPower,
acc,
0,
0,
0,
0,
0,
0,
0);
}
}
#endregion
}
}