1 #define FLEET
2 using System;
3 using System.Collections.Generic;
4 using System.Linq;
5 using System.Text;
6 using System.Threading.Tasks;
7 
8 namespace PHEMlightdll
9 {
10     public class CEP
11     {
12         //--------------------------------------------------------------------------------------------------
13         // Constructors
14         //--------------------------------------------------------------------------------------------------
15 
16         #region Constructor
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, List<double> transmissionGearRatios, double auxPower, double ratedPower, double engineIdlingSpeed, double engineRatedSpeed, double effictiveWheelDiameter, double pNormV0, double pNormP0, double pNormV1, double pNormP1, string vehicelFuelType, List<List<double>> matrixFC, List<string> headerLinePollutants, List<List<double>> matrixPollutants, List<List<double>> matrixSpeedRotational, List<List<double>> normedDragTable, double idlingFC, List<double> idlingPollutants)17         public CEP(bool heavyVehicle,
18                     double vehicleMass,
19                     double vehicleLoading,
20                     double vehicleMassRot,
21                     double crossArea,
22                     double cWValue,
23                     double f0,
24                     double f1,
25                     double f2,
26                     double f3,
27                     double f4,
28                     double axleRatio,
29                     List<double> transmissionGearRatios,
30                     double auxPower,
31                     double ratedPower,
32                     double engineIdlingSpeed,
33                     double engineRatedSpeed,
34                     double effictiveWheelDiameter,
35                     double pNormV0,
36                     double pNormP0,
37                     double pNormV1,
38                     double pNormP1,
39                     string vehicelFuelType,
40                     List<List<double>> matrixFC,
41                     List<string> headerLinePollutants,
42                     List<List<double>> matrixPollutants,
43                     List<List<double>> matrixSpeedRotational,
44                     List<List<double>> normedDragTable,
45                     double idlingFC,
46                     List<double> idlingPollutants)
47         {
48             _resistanceF0 = f0;
49             _resistanceF1 = f1;
50             _resistanceF2 = f2;
51             _resistanceF3 = f3;
52             _resistanceF4 = f4;
53             _cWValue = cWValue;
54             _crossSectionalArea = crossArea;
55             _massVehicle = vehicleMass;
56             _vehicleLoading = vehicleLoading;
57             _vehicleMassRot = vehicleMassRot;
58             _ratedPower = ratedPower;
59             _engineIdlingSpeed = engineIdlingSpeed;
60             _engineRatedSpeed = engineRatedSpeed;
61             _effectiveWheelDiameter = effictiveWheelDiameter;
62             _heavyVehicle = heavyVehicle;
63             _fuelType = vehicelFuelType;
64             _axleRatio = axleRatio;
65             _auxPower = auxPower;
66 
67             _pNormV0 = pNormV0 / 3.6;
68             _pNormP0 = pNormP0;
69             _pNormV1 = pNormV1 / 3.6;
70             _pNormP1 = pNormP1;
71 
72             List<string> pollutantIdentifier = new List<string>();
73             List<List<double>> pollutantMeasures = new List<List<double>>();
74             List<List<double>> normalizedPollutantMeasures = new List<List<double>>();
75 
76             // init pollutant identifiers
77             for (int i = 0; i < headerLinePollutants.Count; i++)
78             {
79                 pollutantIdentifier.Add(headerLinePollutants[i]);
80             }
81 
82             // initialize measures
83             for (int i = 0; i < headerLinePollutants.Count; i++)
84             {
85                 pollutantMeasures.Add(new List<double>());
86                 normalizedPollutantMeasures.Add(new List<double>());
87             }
88 
89             // looping through matrix and assigning values for speed rotational table
90             _speedCurveRotational = new List<double>();
91             _speedPatternRotational = new List<double>();
92             _gearTransmissionCurve = new List<double>();
93             for (int i = 0; i < matrixSpeedRotational.Count; i++)
94             {
95                 if (matrixSpeedRotational[i].Count != 3)
96                     return;
97 
98                 _speedPatternRotational.Add(matrixSpeedRotational[i][0] / 3.6);
99                 _gearTransmissionCurve.Add(matrixSpeedRotational[i][1]);
100                 _speedCurveRotational.Add(matrixSpeedRotational[i][2]);
101             }
102 
103             // looping through matrix and assigning values for drag table
104             _nNormTable = new List<double>();
105             _dragNormTable = new List<double>();
106             for (int i = 0; i < normedDragTable.Count; i++)
107             {
108                 if (normedDragTable[i].Count != 2)
109                     return;
110 
111                 _nNormTable.Add(normedDragTable[i][0]);
112                 _dragNormTable.Add(normedDragTable[i][1]);
113             }
114 
115             // looping through matrix and assigning values for Fuel consumption
116             _cepCurveFC = new List<double>();
117             _normedCepCurveFC = new List<double>();
118             _powerPatternFC = new List<double>();
119             _normalizedPowerPatternFC = new List<double>();
120             for (int i = 0; i < matrixFC.Count; i++)
121             {
122                 if (matrixFC[i].Count != 2)
123                     return;
124 
125                 _powerPatternFC.Add(matrixFC[i][0] * _ratedPower);
126                 _normalizedPowerPatternFC.Add(matrixFC[i][0]);
127                 _cepCurveFC.Add(matrixFC[i][1] * _ratedPower);
128                 _normedCepCurveFC.Add(matrixFC[i][1]);
129 
130             }
131 
132             _powerPatternPollutants = new List<double>();
133 
134             double pollutantMultiplyer = 1;
135 
136             _drivingPower = _normalizingPower = CalcPower(Constants.NORMALIZING_SPEED, Constants.NORMALIZING_ACCELARATION, 0);
137 
138             // looping through matrix and assigning values for pollutants
139             if (heavyVehicle)
140             {
141                 _normalizingPower = _ratedPower;
142                 _normalizingType = NormalizingType.RatedPower;
143                 pollutantMultiplyer = _ratedPower;
144             }
145             else
146             {
147                 _normalizingPower = _drivingPower;
148                 _normalizingType = NormalizingType.DrivingPower;
149             }
150 
151             _normailzedPowerPatternPollutants = new List<double>();
152 
153             _cepNormalizedCurvePollutants = new Dictionary<string, List<double>>();
154 
155             int headerCount = headerLinePollutants.Count;
156             for (int i = 0; i < matrixPollutants.Count; i++)
157             {
158                 for (int j = 0; j < matrixPollutants[i].Count; j++)
159                 {
160                     if (matrixPollutants[i].Count != headerCount + 1)
161                         return;
162 
163                     if (j == 0)
164                     {
165                         _normailzedPowerPatternPollutants.Add(matrixPollutants[i][j]);
166                         _powerPatternPollutants.Add(matrixPollutants[i][j] * NormalizingPower);
167                     }
168                     else
169                     {
170                         pollutantMeasures[j - 1].Add(matrixPollutants[i][j] * pollutantMultiplyer);
171                         normalizedPollutantMeasures[j - 1].Add(matrixPollutants[i][j]);
172                     }
173                 }
174             }
175 
176             _cepCurvePollutants = new Dictionary<string, List<double>>();
177             _idlingValuesPollutants = new Dictionary<string, double>();
178 
179             for (int i = 0; i < headerLinePollutants.Count; i++)
180             {
181                 _cepCurvePollutants.Add(pollutantIdentifier[i], pollutantMeasures[i]);
182                 _cepNormalizedCurvePollutants.Add(pollutantIdentifier[i], normalizedPollutantMeasures[i]);
183                 _idlingValuesPollutants.Add(pollutantIdentifier[i], idlingPollutants[i] * pollutantMultiplyer);
184             }
185 
186             _idlingValueFC = idlingFC * _ratedPower;
187         }
188         #endregion
189 
190         #if FLEET
191         #region ConstrutorForFleetmix
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)192         private CEP(bool heavyVehicle,
193                        double vehicleMass,
194                        double vehicleLoading,
195                        double vehicleMassRot,
196                        double crossArea,
197                        double cWValue,
198                        double f0,
199                        double f1,
200                        double f2,
201                        double f3,
202                        double f4,
203                        double axleRatio,
204                        double auxPower,
205                        double ratedPower,
206                        double engineIdlingSpeed,
207                        double engineRatedSpeed,
208                        double effictiveWheelDiameter,
209                        double pNormV0,
210                        double pNormP0,
211                        double pNormV1,
212                        double pNormP1)
213         {
214             _resistanceF0 = f0;
215             _resistanceF1 = f1;
216             _resistanceF2 = f2;
217             _resistanceF3 = f3;
218             _resistanceF4 = f4;
219             _cWValue = cWValue;
220             _crossSectionalArea = crossArea;
221             _massVehicle = vehicleMass;
222             _vehicleLoading = vehicleLoading;
223             _vehicleMassRot = vehicleMassRot;
224             _ratedPower = ratedPower;
225             _engineIdlingSpeed = engineIdlingSpeed;
226             _engineRatedSpeed = engineRatedSpeed;
227             _effectiveWheelDiameter = effictiveWheelDiameter;
228 
229             _axleRatio = axleRatio;
230             _auxPower = auxPower;
231 
232             _pNormV0 = pNormV0 / 3.6;
233             _pNormP0 = pNormP0;
234             _pNormV1 = pNormV1 / 3.6;
235             _pNormP1 = pNormP1;
236 
237             _heavyVehicle = heavyVehicle;
238 
239         }
240         #endregion
241         #endif
242 
243         //--------------------------------------------------------------------------------------------------
244         // Members
245         //--------------------------------------------------------------------------------------------------
246 
247         #region HeavyVehicle
248         private bool _heavyVehicle;
249         public bool HeavyVehicle
250         {
251             get
252             {
253                 return _heavyVehicle;
254             }
255         }
256         #endregion
257 
258         #region FuelType
259         private string _fuelType;
260         public string FuelType
261         {
262             get
263             {
264                 return _fuelType;
265             }
266         }
267         #endregion
268 
269         #region NormalizingType
270         public enum NormalizingType
271         {
272             RatedPower,
273             DrivingPower
274         }
275         private NormalizingType _normalizingType;
276         public NormalizingType NormalizingTypeX
277         {
278             get
279             {
280                 return _normalizingType;
281             }
282         }
283         #endregion
284 
285         #region RatedPower
286         private double _ratedPower;
287         public double RatedPower
288         {
289             get
290             {
291                 return _ratedPower;
292             }
293             set
294             {
295                 _ratedPower = value;
296             }
297         }
298         #endregion
299 
300         #region NormalizingPower
301         private double _normalizingPower;
302         public double NormalizingPower
303         {
304             get
305             {
306                 return _normalizingPower;
307             }
308         }
309         #endregion
310 
311         #region DrivingPower
312         private double _drivingPower;
313         public double DrivingPower
314         {
315             get
316             {
317                 return _drivingPower;
318             }
319             set
320             {
321                 _drivingPower = value;
322             }
323         }
324 
325         #endregion
326 
327         #region Private Members
328 
329         protected double _massVehicle;
330         protected double _vehicleLoading;
331         protected double _vehicleMassRot;
332         protected double _crossSectionalArea;
333         protected double _cWValue;
334         protected double _resistanceF0;
335         protected double _resistanceF1;
336         protected double _resistanceF2;
337         protected double _resistanceF3;
338         protected double _resistanceF4;
339         protected double _axleRatio;
340         protected double _auxPower;
341         protected double _pNormV0;
342         protected double _pNormP0;
343         protected double _pNormV1;
344         protected double _pNormP1;
345 
346         protected double _engineRatedSpeed;
347         protected double _engineIdlingSpeed;
348         protected double _effectiveWheelDiameter;
349 
350         protected List<double> _speedPatternRotational;
351         protected List<double> _powerPatternFC;
352         protected List<double> _normalizedPowerPatternFC;
353         protected List<double> _normailzedPowerPatternPollutants;
354         protected List<double> _powerPatternPollutants;
355 
356         protected List<double> _cepCurveFC;
357         protected List<double> _normedCepCurveFC;
358         protected List<double> _gearTransmissionCurve;
359         protected List<double> _speedCurveRotational;
360         protected Dictionary<string, List<double>> _cepCurvePollutants;
361         protected Dictionary<string, List<double>> _cepNormalizedCurvePollutants;
362         protected double _idlingValueFC;
363         protected Dictionary<string, double> _idlingValuesPollutants;
364 
365         protected List<double> _nNormTable;
366         protected List<double> _dragNormTable;
367 
368         #endregion
369 
370         //--------------------------------------------------------------------------------------------------
371         // Methods
372         //--------------------------------------------------------------------------------------------------
373 
374         #region CalcPower
CalcPower(double speed, double acc, double gradient)375         public double CalcPower(double speed, double acc, double gradient)
376         {
377             //Declaration
378             double power = 0;
379             double rotFactor = GetRotationalCoeffecient(speed);
380             double powerAux = (_auxPower * _ratedPower);
381 
382             //Calculate the power
383             power += (_massVehicle + _vehicleLoading) * Constants.GRAVITY_CONST * (_resistanceF0 + _resistanceF1 * speed + _resistanceF4 * Math.Pow(speed, 4)) * speed;
384             power += (_crossSectionalArea * _cWValue * Constants.AIR_DENSITY_CONST / 2) * Math.Pow(speed, 3);
385             power += (_massVehicle * rotFactor + _vehicleMassRot + _vehicleLoading) * acc * speed;
386             power += (_massVehicle + _vehicleLoading) * Constants.GRAVITY_CONST * gradient * 0.01 * speed;
387             power /= 1000;
388             power /= Constants._DRIVE_TRAIN_EFFICIENCY;
389             power += powerAux;
390 
391             //Return result
392             return power;
393         }
394         #endregion
395 
396         #region CalcEngPower
CalcEngPower(double power)397         public double CalcEngPower(double power)
398         {
399             if (power < _powerPatternFC.First()) return _powerPatternFC.First();
400             if (power > _powerPatternFC.Last()) return _powerPatternFC.Last();
401 
402             return power;
403         }
404         #endregion
405 
406         #region GetEmission
GetEmission(string pollutant, double power, double speed, Helpers VehicleClass)407         public double GetEmission(string pollutant, double power, double speed, Helpers VehicleClass)
408         {
409             //Declaration
410             List<double> emissionCurve;
411             List<double> powerPattern;
412 
413             // bisection search to find correct position in power pattern
414             int upperIndex;
415             int lowerIndex;
416 
417             if (VehicleClass.tClass != Constants.strBEV)
418             {
419                 if (Math.Abs(speed) <= Constants.ZERO_SPEED_ACCURACY)
420                 {
421                     if (pollutant == "FC")
422                     {
423                         return _idlingValueFC;
424                     }
425                     else
426                     {
427                         if (!_cepCurvePollutants.ContainsKey(pollutant))
428                         {
429                             VehicleClass.ErrMsg = "Emission pollutant " + pollutant + " not found!";
430                             return 0;
431                         }
432 
433                         return _idlingValuesPollutants[pollutant];
434                     }
435                 }
436             }
437 
438             if (pollutant == "FC")
439             {
440                 emissionCurve = _cepCurveFC;
441                 powerPattern = _powerPatternFC;
442             }
443             else
444             {
445                 if (!_cepCurvePollutants.ContainsKey(pollutant))
446                 {
447                     VehicleClass.ErrMsg = "Emission pollutant " + pollutant + " not found!";
448                     return 0;
449                 }
450 
451                 emissionCurve = _cepCurvePollutants[pollutant];
452                 powerPattern = _powerPatternPollutants;
453             }
454 
455             if (emissionCurve.Count == 0)
456             {
457                 VehicleClass.ErrMsg = "Empty emission curve for " + pollutant + " found!";
458                 return 0;
459             }
460             if (emissionCurve.Count == 1)
461             {
462                 return emissionCurve[0];
463             }
464 
465             // in case that the demanded power is smaller than the first entry (smallest) in the power pattern the first is returned (should never happen)
466             if (power <= powerPattern.First())
467             {
468                 return emissionCurve[0];
469             }
470 
471             // if power bigger than all entries in power pattern return the last (should never happen)
472             if (power >= powerPattern.Last())
473             {
474                 return emissionCurve.Last();
475             }
476 
477             FindLowerUpperInPattern(out lowerIndex, out upperIndex, powerPattern, power);
478             return Interpolate(power, powerPattern[lowerIndex], powerPattern[upperIndex], emissionCurve[lowerIndex], emissionCurve[upperIndex]);
479         }
480         #endregion
481 
482         #if FLEET
483         #region GetNormedEmission
GetNormedEmission(string pollutant, double power, double speed, Helpers VehicleClass)484         public double GetNormedEmission(string pollutant, double power, double speed, Helpers VehicleClass)
485         {
486             //Declaration
487             List<double> emissionCurve;
488             List<double> powerPattern;
489 
490             // bisection search to find correct position in power pattern
491             int upperIndex;
492             int lowerIndex;
493 
494             if (pollutant == "FC")
495             {
496                 emissionCurve = _normedCepCurveFC;
497                 powerPattern = _normalizedPowerPatternFC;
498             }
499             else
500             {
501                 if (!_cepCurvePollutants.ContainsKey(pollutant))
502                 {
503                     VehicleClass.ErrMsg = "Emission pollutant " + pollutant + " not found!";
504                     return 0;
505                 }
506                 emissionCurve = _cepNormalizedCurvePollutants[pollutant];
507                 powerPattern = _normailzedPowerPatternPollutants;
508             }
509 
510             if (emissionCurve.Count == 0)
511             {
512                 VehicleClass.ErrMsg = "Empty emission curve for " + pollutant + " found!";
513                 return 0;
514             }
515             if (emissionCurve.Count == 1)
516             {
517                 return emissionCurve[0];
518             }
519             // in case that the demanded power is smaller than the first entry (smallest) in the power pattern the first is returned (should never happen)
520             if (power <= powerPattern.First())
521             {
522                 return emissionCurve[0];
523             }
524 
525             // if power bigger than all entries in power pattern the last is returned (should never happen)
526             if (power >= powerPattern.Last())
527             {
528                 return emissionCurve.Last();
529             }
530 
531             FindLowerUpperInPattern(out lowerIndex, out upperIndex, powerPattern, power);
532             return Interpolate(power, powerPattern[lowerIndex], powerPattern[upperIndex], emissionCurve[lowerIndex], emissionCurve[upperIndex]);
533         }
534         #endregion
535         #endif
536 
537         #region GetCO2Emission
GetCO2Emission(double _FC, double _CO, double _HC, Helpers VehicleClass)538         public double GetCO2Emission(double _FC, double _CO, double _HC, Helpers VehicleClass)
539         {
540             //Declaration
541             double fCBr;
542             double fCHC = 0.866;
543             double fCCO = 0.429;
544             double fCCO2 = 0.273;
545 
546             switch (_fuelType)
547             {
548                 case Constants.strGasoline:
549                     fCBr = 0.865;
550                     break;
551                 case Constants.strDiesel:
552                     fCBr = 0.863;
553                     break;
554                 case Constants.strCNG:
555                     fCBr = 0.693;
556                     fCHC = 0.803;
557                     break;
558                 case Constants.strLPG:
559                     fCBr = 0.825;
560                     fCHC = 0.825;
561                     break;
562                 default:
563                     VehicleClass.ErrMsg = "The propolsion type is not known! (" + _fuelType + ")";
564                     return 0;
565             }
566 
567             return (_FC * fCBr - _CO * fCCO - _HC * fCHC) / fCCO2;
568         }
569         #endregion
570 
571         #region GetDecelCoast
GetDecelCoast(double speed, double acc, double gradient)572         public double GetDecelCoast(double speed, double acc, double gradient)
573         {
574             //Declaration
575             int upperIndex;
576             int lowerIndex;
577 
578             if (speed < Constants.SPEED_DCEL_MIN)
579             {
580                 return speed / Constants.SPEED_DCEL_MIN * GetDecelCoast(Constants.SPEED_DCEL_MIN, acc, gradient);
581             }
582 
583             double rotCoeff = GetRotationalCoeffecient(speed);
584             FindLowerUpperInPattern(out lowerIndex, out upperIndex, _speedPatternRotational, speed);
585             double iGear = Interpolate(speed,
586                                         _speedPatternRotational[lowerIndex],
587                                         _speedPatternRotational[upperIndex],
588                                         _gearTransmissionCurve[lowerIndex],
589                                         _gearTransmissionCurve[upperIndex]);
590 
591             double iTot = iGear * _axleRatio;
592 
593             double n = (30 * speed * iTot) / ((_effectiveWheelDiameter / 2) * Math.PI);
594             double nNorm = (n - _engineIdlingSpeed) / (_engineRatedSpeed - _engineIdlingSpeed);
595 
596             FindLowerUpperInPattern(out lowerIndex, out upperIndex, _nNormTable, nNorm);
597 
598             double fMot = 0;
599 
600             if (speed >= 10e-2)
601             {
602                 fMot = (-Interpolate(nNorm,
603                                           _nNormTable[lowerIndex],
604                                           _nNormTable[upperIndex],
605                                           _dragNormTable[lowerIndex],
606                                           _dragNormTable[upperIndex]) * _ratedPower * 1000 / speed) / 0.9;
607             }
608 
609             double fRoll = (_resistanceF0
610                 + _resistanceF1 * speed
611                 + Math.Pow(_resistanceF2 * speed, 2)
612                 + Math.Pow(_resistanceF3 * speed, 3)
613                 + Math.Pow(_resistanceF4 * speed, 4)) * (_massVehicle + _vehicleLoading) * Constants.GRAVITY_CONST;
614 
615             double fAir = _cWValue * _crossSectionalArea * 1.2 * 0.5 * Math.Pow(speed, 2);
616 
617             double fGrad = (_massVehicle + _vehicleLoading) * Constants.GRAVITY_CONST * gradient / 100;
618 
619             return -(fMot + fRoll + fAir + fGrad) / ((_massVehicle + _vehicleLoading) * rotCoeff);
620         }
621         #endregion
622 
623         #region GetRotationalCoeffecient
GetRotationalCoeffecient(double speed)624         public double GetRotationalCoeffecient(double speed)
625         {
626             //Declaration
627             int upperIndex;
628             int lowerIndex;
629 
630             FindLowerUpperInPattern(out lowerIndex, out upperIndex, _speedPatternRotational, speed);
631             return Interpolate(speed,
632                                         _speedPatternRotational[lowerIndex],
633                                         _speedPatternRotational[upperIndex],
634                                         _speedCurveRotational[lowerIndex],
635                                         _speedCurveRotational[upperIndex]);
636         }
637         #endregion
638 
639         #if FLEET
640         #region GetGearCoeffecient
GetGearCoeffecient(double speed)641         public double GetGearCoeffecient(double speed)
642         {
643             //Declaration
644             int upperIndex;
645             int lowerIndex;
646 
647             FindLowerUpperInPattern(out lowerIndex, out upperIndex, _speedPatternRotational, speed);
648             return Interpolate(speed,
649                                         _speedPatternRotational[lowerIndex],
650                                         _speedPatternRotational[upperIndex],
651                                         _gearTransmissionCurve[lowerIndex],
652                                         _gearTransmissionCurve[upperIndex]);
653         }
654         #endregion
655 
656         #region GetDragCoeffecient
GetDragCoeffecient(double nNorm)657         public double GetDragCoeffecient(double nNorm)
658         {
659             //Declaration
660             int upperIndex;
661             int lowerIndex;
662 
663             FindLowerUpperInPattern(out lowerIndex, out upperIndex, _nNormTable, nNorm);
664             return Interpolate(nNorm,
665                                         _nNormTable[lowerIndex],
666                                         _nNormTable[upperIndex],
667                                         _dragNormTable[lowerIndex],
668                                         _dragNormTable[upperIndex]);
669         }
670         #endregion
671         #endif
672 
673         #region FindLowerUpperInPattern
FindLowerUpperInPattern(out int lowerIndex, out int upperIndex, List<double> pattern, double value)674         private void FindLowerUpperInPattern(out int lowerIndex, out int upperIndex, List<double> pattern, double value)
675         {
676             lowerIndex = 0;
677             upperIndex = 0;
678 
679             if (value <= pattern.First())
680             {
681                 lowerIndex = 0;
682                 upperIndex = 0;
683                 return;
684             }
685 
686             if (value >= pattern.Last())
687             {
688                 lowerIndex = pattern.Count - 1;
689                 upperIndex = pattern.Count - 1;
690                 return;
691             }
692 
693             // bisection search to find correct position in power pattern
694             int middleIndex = (pattern.Count - 1) / 2;
695             upperIndex = pattern.Count - 1;
696             lowerIndex = 0;
697 
698             while (upperIndex - lowerIndex > 1)
699             {
700                 if (pattern[middleIndex] == value)
701                 {
702                     lowerIndex = middleIndex;
703                     upperIndex = middleIndex;
704                     return;
705                 }
706                 else if (pattern[middleIndex] < value)
707                 {
708                     lowerIndex = middleIndex;
709                     middleIndex = (upperIndex - lowerIndex) / 2 + lowerIndex;
710                 }
711                 else
712                 {
713                     upperIndex = middleIndex;
714                     middleIndex = (upperIndex - lowerIndex) / 2 + lowerIndex;
715                 }
716             }
717 
718             if (pattern[lowerIndex] <= value && value < pattern[upperIndex])
719             {
720                 return;
721             }
722         }
723         #endregion
724 
725         #region Interpolate
Interpolate(double px, double p1, double p2, double e1, double e2)726         private double Interpolate(double px, double p1, double p2, double e1, double e2)
727         {
728             if (p2 == p1)
729                 return e1;
730 
731             return e1 + (px - p1) / (p2 - p1) * (e2 - e1);
732         }
733         #endregion
734 
735         #region GetMaxAccel
GetMaxAccel(double speed, double gradient)736         public double GetMaxAccel(double speed, double gradient)
737         {
738             double rotFactor = GetRotationalCoeffecient(speed);
739             double pMaxForAcc = GetPMaxNorm(speed) * _ratedPower - CalcPower(speed, 0, gradient);
740 
741             return (pMaxForAcc * 1000) / ((_massVehicle * rotFactor + _vehicleMassRot + _vehicleLoading) * speed);
742         }
743         #endregion
744 
745         #region GetPMaxNorm
GetPMaxNorm(double speed)746         private double GetPMaxNorm(double speed)
747         {
748             // Linear function between v0 and v1, constant elsewhere
749             if (speed <= _pNormV0)
750                 return _pNormP0;
751             else if (speed >= _pNormV1)
752                 return _pNormP1;
753             else
754             {
755                 return Interpolate(speed, _pNormV0, _pNormV1, _pNormP0, _pNormP1);
756             }
757         }
758         #endregion
759 
760         //--------------------------------------------------------------------------------------------------
761         // Operators for fleetmix
762         //--------------------------------------------------------------------------------------------------
763 
764         #if FLEET
765         #region AddRangeCeps
AddRangeCeps(CEP[] cps, Helpers Helper)766         public static CEP AddRangeCeps(CEP[] cps, Helpers Helper)
767         {
768             #region SingleValues
769             CEP newCEP = new CEP(cps.Select(p => p.HeavyVehicle ? 1 : 0).Sum() > 0,
770                 cps.Select(p => p._massVehicle).Sum(),
771                 cps.Select(p => p._vehicleLoading).Sum(),
772                 cps.Select(p => p._vehicleMassRot).Sum(),
773                 cps.Select(p => p._crossSectionalArea).Sum(),
774                 cps.Select(p => p._cWValue).Sum(),
775                 cps.Select(p => p._resistanceF0).Sum(),
776                 cps.Select(p => p._resistanceF1).Sum(),
777                 cps.Select(p => p._resistanceF2).Sum(),
778                 cps.Select(p => p._resistanceF3).Sum(),
779                 cps.Select(p => p._resistanceF4).Sum(),
780                 cps.Select(p => p._axleRatio).Sum(),
781                 cps.Select(p => p._auxPower).Sum(),
782                 cps.Select(p => p._ratedPower).Sum(),
783                 cps.Select(p => p._engineIdlingSpeed).Sum(),
784                 cps.Select(p => p._engineRatedSpeed).Sum(),
785                 cps.Select(p => p._effectiveWheelDiameter).Sum(),
786                 cps.Select(p => p._pNormV0).Sum(),
787                 cps.Select(p => p._pNormP0).Sum(),
788                 cps.Select(p => p._pNormV1).Sum(),
789                 cps.Select(p => p._pNormP1).Sum());
790 
791             newCEP._fuelType = cps.First().FuelType;
792             #endregion
793 
794             #region SpeedRotationalTable
795             double minSpeedRotational = cps.Select(p => p._speedPatternRotational.First()).Min();
796             double maxSpeedRotational = cps.Select(p => p._speedPatternRotational.Last()).Max();
797 
798             newCEP._speedPatternRotational
799                 = CreatePattern(minSpeedRotational,
800                 maxSpeedRotational,
801                 Constants.SPEED_ROTATIONAL_INCREMENT);
802 
803             newCEP._speedCurveRotational = new List<double>();
804             newCEP._gearTransmissionCurve = new List<double>();
805 
806             for (int i = 0; i < newCEP._speedPatternRotational.Count; i++)
807             {
808                 newCEP._speedCurveRotational.Add(cps.Select(p => p.GetRotationalCoeffecient(newCEP._speedPatternRotational[i])).Sum());
809 
810                 newCEP._gearTransmissionCurve.Add(cps.Select(p => p.GetGearCoeffecient(newCEP._speedPatternRotational[i])).Sum());
811             }
812             #endregion
813 
814             #region NormalizingPower
815             newCEP._drivingPower = newCEP.CalcPower(Constants.NORMALIZING_SPEED, Constants.NORMALIZING_ACCELARATION, 0);
816 
817             if (newCEP._heavyVehicle)
818             {
819                 newCEP._normalizingPower = newCEP._ratedPower;
820                 newCEP._normalizingType = NormalizingType.RatedPower;
821             }
822             else
823             {
824                 newCEP._normalizingPower = newCEP._drivingPower;
825                 newCEP._normalizingType = NormalizingType.DrivingPower;
826             }
827             #endregion
828 
829             #region FC
830             double minNormPowerPatternFC = cps.Select(p => p._normalizedPowerPatternFC.First()).Min();
831             double maxNormPowerPatternFC = cps.Select(p => p._normalizedPowerPatternFC.Last()).Max();
832 
833             newCEP._normalizedPowerPatternFC
834                 = CreatePattern(minNormPowerPatternFC,
835                 maxNormPowerPatternFC,
836                 Constants.POWER_FC_INCREMENT);
837 
838             newCEP._cepCurveFC = new List<double>();
839             newCEP._normedCepCurveFC = new List<double>();
840             newCEP._powerPatternFC = new List<double>();
841 
842             for (int i = 0; i < newCEP._normalizedPowerPatternFC.Count; i++)
843             {
844                 double newCepVal = cps.Select(p => p.GetNormedEmission("FC", newCEP._normalizedPowerPatternFC[i], double.MaxValue, Helper)).Sum();
845                 newCEP._cepCurveFC.Add(newCepVal * newCEP._ratedPower);
846                 newCEP._normedCepCurveFC.Add(newCepVal);
847                 newCEP._powerPatternFC.Add(newCEP._normalizedPowerPatternFC[i] * newCEP._ratedPower);
848             }
849             #endregion
850 
851             #region Pollutants
852             double minNormPowerPattern = cps.Select(p => p._normailzedPowerPatternPollutants.First()).Min();
853             double maxNormPowerPattern = cps.Select(p => p._normailzedPowerPatternPollutants.Last()).Max();
854 
855             newCEP._normailzedPowerPatternPollutants
856                  = CreatePattern(minNormPowerPattern,
857                  maxNormPowerPattern,
858                  Constants.POWER_POLLUTANT_INCREMENT);
859 
860             newCEP._cepCurvePollutants = new Dictionary<string, List<double>>();
861             newCEP._powerPatternPollutants = new List<double>();
862             newCEP._cepNormalizedCurvePollutants = new Dictionary<string, List<double>>();
863 
864             foreach (string id in cps.First()._cepCurvePollutants.Keys)
865             {
866                 newCEP._cepCurvePollutants.Add(id, new List<double>());
867                 newCEP._cepNormalizedCurvePollutants.Add(id, new List<double>());
868             }
869 
870             for (int i = 0; i < newCEP._normailzedPowerPatternPollutants.Count; i++)
871             {
872                 foreach (string id in newCEP._cepCurvePollutants.Keys)
873                 {
874                     if (newCEP.NormalizingTypeX == NormalizingType.RatedPower)
875                     {
876                         double newCepVal = cps.Select(p => p.GetNormedEmission(id, newCEP._normailzedPowerPatternPollutants[i], double.MaxValue, Helper)).Sum();
877                         newCEP._cepCurvePollutants[id].Add(newCepVal * newCEP._ratedPower);
878                         newCEP._cepNormalizedCurvePollutants[id].Add(newCepVal);
879                     }
880                     else
881                     {
882                         newCEP._cepCurvePollutants[id].Add(cps.Select(p => p.GetEmission(id, newCEP._normailzedPowerPatternPollutants[i] * p._normalizingPower, double.MaxValue, Helper)).Sum());
883                         newCEP._cepNormalizedCurvePollutants[id].Add(cps.Select(p => p.GetNormedEmission(id, newCEP._normailzedPowerPatternPollutants[i], double.MaxValue, Helper)).Sum());
884                     }
885                 }
886                 newCEP._powerPatternPollutants.Add(newCEP._normailzedPowerPatternPollutants[i] * newCEP.NormalizingPower);
887             }
888             #endregion
889 
890             #region IdlingValues
891             newCEP._idlingValueFC = cps.Select(p => p._idlingValueFC).Sum();
892             newCEP._idlingValuesPollutants = new Dictionary<string, double>();
893 
894             foreach (string id in cps.First()._idlingValuesPollutants.Keys)
895             {
896                 newCEP._idlingValuesPollutants.Add(id, cps.Select(p => p._idlingValuesPollutants[id]).Sum());
897             }
898             #endregion
899 
900             #region TragTable
901             double minTragTable = cps.Select(p => p._nNormTable.First()).Min();
902             double maxTragTable = cps.Select(p => p._nNormTable.Last()).Max();
903 
904             newCEP._nNormTable
905                 = CreatePattern(minTragTable,
906                 maxTragTable,
907                 Constants.NNORM_INCREMENT);
908 
909             newCEP._dragNormTable = new List<double>();
910 
911             for (int i = 0; i < newCEP._nNormTable.Count; i++)
912             {
913                 newCEP._dragNormTable.Add(cps.Select(p => p.GetDragCoeffecient(newCEP._nNormTable[i])).Sum());
914             }
915             #endregion
916             return newCEP;
917         }
918         #endregion
919 
920         #region Operator *
operator *(CEP cp1, double d)921         public static CEP operator *(CEP cp1, double d)
922         {
923             #region SingleValues
924             CEP newCEP = new CEP(cp1.HeavyVehicle,
925                 d * cp1._massVehicle,
926                 d * cp1._vehicleLoading,
927                 d * cp1._vehicleMassRot,
928                 d * cp1._crossSectionalArea,
929                 d * cp1._cWValue,
930                 d * cp1._resistanceF0,
931                 d * cp1._resistanceF1,
932                 d * cp1._resistanceF2,
933                 d * cp1._resistanceF3,
934                 d * cp1._resistanceF4,
935                 d * cp1._axleRatio,
936                 d * cp1._auxPower,
937                 d * cp1._ratedPower,
938                 d * cp1._engineIdlingSpeed,
939                 d * cp1._engineRatedSpeed,
940                 d * cp1._effectiveWheelDiameter,
941                 d * cp1._pNormV0,
942                 d * cp1._pNormP0,
943                 d * cp1._pNormV1,
944                 d * cp1._pNormP1);
945 
946             newCEP._fuelType = cp1.FuelType;
947             #endregion
948 
949             #region SpeedRotationalTable
950             newCEP._speedPatternRotational = new List<double>(cp1._speedPatternRotational);
951             newCEP._speedCurveRotational = new List<double>(cp1._speedCurveRotational.Select(p => p * d));
952             newCEP._gearTransmissionCurve = new List<double>(cp1._gearTransmissionCurve.Select(p => p * d));
953             #endregion
954 
955             #region NormalizingPower
956             newCEP._drivingPower = newCEP.CalcPower(Constants.NORMALIZING_SPEED, Constants.NORMALIZING_ACCELARATION, 0);
957 
958             if (newCEP._heavyVehicle)
959             {
960                 newCEP._normalizingPower = newCEP._ratedPower;
961                 newCEP._normalizingType = NormalizingType.RatedPower;
962             }
963             else
964             {
965                 newCEP._normalizingPower = newCEP._drivingPower;
966                 newCEP._normalizingType = NormalizingType.DrivingPower;
967             }
968             #endregion
969 
970             #region FC
971             newCEP._powerPatternFC = new List<double>(cp1._powerPatternFC.Select(p => p * d));
972             newCEP._normalizedPowerPatternFC = new List<double>(cp1._normalizedPowerPatternFC);
973             newCEP._cepCurveFC = new List<double>(cp1._cepCurveFC.Select(p => p * d));
974             newCEP._normedCepCurveFC = new List<double>(cp1._normedCepCurveFC.Select(p => p * d));
975             #endregion
976 
977             #region Pollutants
978             newCEP._powerPatternPollutants = new List<double>(cp1._normailzedPowerPatternPollutants.Select(p => p * newCEP._normalizingPower));
979             newCEP._normailzedPowerPatternPollutants = new List<double>(cp1._normailzedPowerPatternPollutants);
980             newCEP._cepCurvePollutants = new Dictionary<string, List<double>>();
981             newCEP._cepNormalizedCurvePollutants = new Dictionary<string, List<double>>();
982 
983             foreach (string id in cp1._cepCurvePollutants.Keys)
984             {
985                 newCEP._cepCurvePollutants.Add(id, new List<double>(cp1._cepCurvePollutants[id].Select(p => p * d)));
986                 newCEP._cepNormalizedCurvePollutants.Add(id, new List<double>(cp1._cepNormalizedCurvePollutants[id].Select(p => p * d)));
987             }
988             #endregion
989 
990             #region IdlingValues
991             newCEP._idlingValueFC = cp1._idlingValueFC * d;
992             newCEP._idlingValuesPollutants = new Dictionary<string, double>();
993 
994             foreach (string id in cp1._idlingValuesPollutants.Keys)
995             {
996                 newCEP._idlingValuesPollutants.Add(id,
997                     cp1._idlingValuesPollutants[id] * d);
998             }
999             #endregion
1000 
1001             #region DragTable
1002             newCEP._nNormTable = new List<double>(cp1._nNormTable);
1003             newCEP._dragNormTable = new List<double>(cp1._dragNormTable.Select(p => p * d));
1004             #endregion
1005             return newCEP;
1006         }
1007         #endregion
1008 
1009         #region CreatePattern
CreatePattern(double min, double max, double increment)1010         static public List<double> CreatePattern(double min, double max, double increment)
1011         {
1012             //Declaration
1013             List<double> pattern = new List<double>();
1014             double actualMin = min;
1015             double actualMax = max;
1016 
1017             if (min < 0)
1018                 actualMin = Math.Ceiling(min / increment) * increment;
1019             else
1020                 actualMin = Math.Floor(min / increment) * increment;
1021 
1022             if (max < 0)
1023                 actualMax = Math.Floor(max / increment) * increment;
1024             else
1025                 actualMax = Math.Ceiling(max / increment) * increment;
1026 
1027             double curVal = actualMin;
1028 
1029             while (curVal <= actualMax)
1030             {
1031                 pattern.Add(curVal);
1032                 curVal += increment;
1033             }
1034             return pattern;
1035         }
1036         #endregion
1037         #endif
1038     }
1039 }
1040