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