diff --git a/VectoCore/Models/SimulationComponent/IShiftStrategy.cs b/VectoCore/Models/SimulationComponent/IShiftStrategy.cs index 62dc6c54193b56675810d5cf423efba2b4e1e74a..918a1f5a12e8c9d92ba0f915d33df0f83e66118d 100644 --- a/VectoCore/Models/SimulationComponent/IShiftStrategy.cs +++ b/VectoCore/Models/SimulationComponent/IShiftStrategy.cs @@ -11,6 +11,15 @@ namespace TUGraz.VectoCore.Models.SimulationComponent /// <summary> /// Checks if a shift operation is required. /// </summary> + /// <param name="absTime">The abs time.</param> + /// <param name="dt">The dt.</param> + /// <param name="outTorque">The out torque.</param> + /// <param name="outAngularVelocity">The out angular velocity.</param> + /// <param name="inTorque">The in torque.</param> + /// <param name="inAngularVelocity">The in angular velocity.</param> + /// <param name="gear">The current gear.</param> + /// <param name="lastShiftTime">The last shift time.</param> + /// <returns><c>true</c> if a shift is required, <c>false</c> otherwise.</returns> bool ShiftRequired(Second absTime, Second dt, NewtonMeter outTorque, PerSecond outAngularVelocity, NewtonMeter inTorque, PerSecond inAngularVelocity, uint gear, Second lastShiftTime); @@ -20,9 +29,9 @@ namespace TUGraz.VectoCore.Models.SimulationComponent /// <param name="absTime">The abs time.</param> /// <param name="dt">The dt.</param> /// <param name="torque">The torque.</param> - /// <param name="outEngineSpeed">The angular speed.</param> - /// <returns></returns> - uint InitGear(Second absTime, Second dt, NewtonMeter torque, PerSecond outEngineSpeed); + /// <param name="outAngularVelocity">The angular speed.</param> + /// <returns>The initial gear.</returns> + uint InitGear(Second absTime, Second dt, NewtonMeter torque, PerSecond outAngularVelocity); /// <summary> /// Engages a gear. @@ -31,7 +40,7 @@ namespace TUGraz.VectoCore.Models.SimulationComponent /// <param name="dt">The dt.</param> /// <param name="outTorque">The out torque.</param> /// <param name="outEngineSpeed">The out engine speed.</param> - /// <returns></returns> + /// <returns>The gear to take.</returns> uint Engage(Second absTime, Second dt, NewtonMeter outTorque, PerSecond outEngineSpeed); /// <summary> diff --git a/VectoCore/Models/SimulationComponent/Impl/Driver.cs b/VectoCore/Models/SimulationComponent/Impl/Driver.cs index 73c8e68a28b8ca0ba9ee7318b23e337477cd3e86..732d008c3f914825735b988c0c05b088fba2e9a4 100644 --- a/VectoCore/Models/SimulationComponent/Impl/Driver.cs +++ b/VectoCore/Models/SimulationComponent/Impl/Driver.cs @@ -474,7 +474,7 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl debug.Add(new { brakingPower = 0.SI<Watt>(), searchInterval, delta = origDelta, operatingPoint }); - var breakingPower = searchInterval * -origDelta.Sign(); + var brakePower = searchInterval * -origDelta.Sign(); // double the searchInterval until a good interval was found var intervalFactor = 1.0; @@ -482,7 +482,7 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl //ResponseDryRun response; do { operatingPoint = ComputeTimeInterval(operatingPoint.Acceleration, ds); - DataBus.BreakPower = breakingPower; + DataBus.BreakPower = brakePower; var response = (ResponseDryRun) NextComponent.Request(absTime, operatingPoint.SimulationInterval, operatingPoint.Acceleration, gradient, true); @@ -494,7 +494,7 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl return operatingPoint; } - debug.Add(new { breakingPower, searchInterval, delta, operatingPoint }); + debug.Add(new { brakePower, searchInterval, delta, operatingPoint }); // check if a correct searchInterval was found (when the delta changed signs, we stepped through the 0-point) // from then on the searchInterval can be bisected. @@ -504,7 +504,7 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl } searchInterval *= intervalFactor; - breakingPower += searchInterval * -delta.Sign(); + brakePower += searchInterval * -delta.Sign(); } while (retryCount++ < Constants.SimulationSettings.DriverSearchLoopThreshold); LogManager.EnableLogging(); diff --git a/VectoCore/Models/SimulationComponent/Impl/Gearbox.cs b/VectoCore/Models/SimulationComponent/Impl/Gearbox.cs index 08897b6045d0a42835b7ef470a0fb8cada2ec31e..258cbb63c7057b0fbf57ab2d265a89e9cb3ba82b 100644 --- a/VectoCore/Models/SimulationComponent/Impl/Gearbox.cs +++ b/VectoCore/Models/SimulationComponent/Impl/Gearbox.cs @@ -1,5 +1,4 @@ using System.Diagnostics; -using System.Dynamic; using TUGraz.VectoCore.Configuration; using TUGraz.VectoCore.Exceptions; using TUGraz.VectoCore.Models.Connector.Ports; @@ -249,10 +248,6 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl }; } - //if (DataBus.VehicleSpeed.IsEqual(0)) { - // Gear = _strategy.Engage(torque, angularVelocity, Data.SkipGears); - //} - var response = NextComponent.Request(absTime, dt, 0.SI<NewtonMeter>(), null); response.GearboxPowerRequest = outTorque * outAngularVelocity; @@ -268,27 +263,27 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl /// <item><term>else</term><description>Response from NextComponent.</description></item> /// </list> /// </returns> - private IResponse RequestGearEngaged(Second absTime, Second dt, NewtonMeter outTorque, PerSecond outEngineSpeed, + private IResponse RequestGearEngaged(Second absTime, Second dt, NewtonMeter outTorque, PerSecond outAngularVelocity, bool dryRun) { // Set a Gear if no gear was set and engineSpeed is not zero - if (_disengaged && !outEngineSpeed.IsEqual(0)) { + if (_disengaged && !outAngularVelocity.IsEqual(0)) { _disengaged = false; if (DataBus.VehicleStopped) { - Gear = _strategy.InitGear(absTime, dt, outTorque, outEngineSpeed); + Gear = _strategy.InitGear(absTime, dt, outTorque, outAngularVelocity); } else { - Gear = _strategy.Engage(absTime, dt, outTorque, outEngineSpeed); + Gear = _strategy.Engage(absTime, dt, outTorque, outAngularVelocity); } Log.Debug("Gearbox engaged gear {0}", Gear); } - var inEngineSpeed = outEngineSpeed * Data.Gears[Gear].Ratio; - var inTorque = (outEngineSpeed.IsEqual(0)) + var inEngineSpeed = outAngularVelocity * Data.Gears[Gear].Ratio; + var inTorque = (outAngularVelocity.IsEqual(0)) ? outTorque / Data.Gears[Gear].Ratio : Data.Gears[Gear].LossMap.GearboxInTorque(inEngineSpeed, outTorque); - _powerLoss = inTorque * inEngineSpeed - outTorque * outEngineSpeed; + _powerLoss = inTorque * inEngineSpeed - outTorque * outAngularVelocity; if (!inEngineSpeed.IsEqual(0)) { _powerLossInertia = Formulas.InertiaPower(inEngineSpeed, _previousInAngularSpeed, Data.Inertia, dt); @@ -299,32 +294,36 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl if (dryRun) { var dryRunResponse = NextComponent.Request(absTime, dt, inTorque, inEngineSpeed, true); - dryRunResponse.GearboxPowerRequest = outTorque * outEngineSpeed; + dryRunResponse.GearboxPowerRequest = outTorque * outAngularVelocity; return dryRunResponse; } - if (!inEngineSpeed.IsEqual(0)) { - if (_strategy.ShiftRequired(absTime, dt, outTorque, outEngineSpeed, inTorque, inEngineSpeed, Gear, - _shiftTime + Data.TractionInterruption)) { + var shiftAllowed = !inEngineSpeed.IsEqual(0) && !DataBus.VehicleSpeed.IsEqual(0); + + if (shiftAllowed) { + var shiftRequired = _strategy.ShiftRequired(absTime, dt, outTorque, outAngularVelocity, inTorque, inEngineSpeed, + Gear, _shiftTime + Data.TractionInterruption); + + if (shiftRequired) { _shiftTime = absTime + Data.TractionInterruption; Log.Debug("Gearbox is shifting. absTime: {0}, dt: {1}, shiftTime: {2}, out: ({3}, {4}), in: ({5}, {6})", absTime, - dt, _shiftTime, outTorque, outEngineSpeed, inTorque, inEngineSpeed); + dt, _shiftTime, outTorque, outAngularVelocity, inTorque, inEngineSpeed); _disengaged = true; - _strategy.Disengage(absTime, dt, outTorque, outEngineSpeed); + _strategy.Disengage(absTime, dt, outTorque, outAngularVelocity); Log.Info("Gearbox disengaged"); return new ResponseGearShift { Source = this, SimulationInterval = Data.TractionInterruption, - GearboxPowerRequest = outTorque * outEngineSpeed + GearboxPowerRequest = outTorque * outAngularVelocity }; } } var response = NextComponent.Request(absTime, dt, inTorque, inEngineSpeed); - response.GearboxPowerRequest = outTorque * outEngineSpeed; + response.GearboxPowerRequest = outTorque * outAngularVelocity; _previousInAngularSpeed = inEngineSpeed; return response; @@ -345,7 +344,7 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl protected override void DoWriteModalResults(IModalDataWriter writer) { - writer[ModalResultField.Gear] = _disengaged ? 0 : Gear; + writer[ModalResultField.Gear] = _disengaged || DataBus.VehicleStopped ? 0 : Gear; writer[ModalResultField.PlossGB] = _powerLoss; writer[ModalResultField.PaGB] = _powerLossInertia; } diff --git a/VectoCore/Models/SimulationComponent/Impl/ShiftStrategy.cs b/VectoCore/Models/SimulationComponent/Impl/ShiftStrategy.cs index d70dd631ed839f93c6d7abce9ffa0653a64213f2..e206552002811b7c0e319804fa10e4ec2f40c2ed 100644 --- a/VectoCore/Models/SimulationComponent/Impl/ShiftStrategy.cs +++ b/VectoCore/Models/SimulationComponent/Impl/ShiftStrategy.cs @@ -1,5 +1,4 @@ using System; -using TUGraz.VectoCore.Exceptions; using TUGraz.VectoCore.Models.Connector.Ports.Impl; using TUGraz.VectoCore.Models.Simulation.DataBus; using TUGraz.VectoCore.Models.SimulationComponent.Data; @@ -8,9 +7,13 @@ using TUGraz.VectoCore.Utils; namespace TUGraz.VectoCore.Models.SimulationComponent.Impl { + /// <summary> + /// Class ShiftStrategy is a base class for shift strategies. Implements some helper methods for checking the shift curves. + /// </summary> public abstract class ShiftStrategy : IShiftStrategy { protected IDataBus DataBus; + protected GearboxData Data; protected ShiftStrategy(GearboxData data, IDataBus dataBus) @@ -20,17 +23,23 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl } public abstract uint Engage(Second absTime, Second dt, NewtonMeter outTorque, PerSecond outEngineSpeed); + public abstract void Disengage(Second absTime, Second dt, NewtonMeter outTorque, PerSecond outEngineSpeed); public abstract bool ShiftRequired(Second absTime, Second dt, NewtonMeter outTorque, PerSecond outAngularVelocity, NewtonMeter inTorque, PerSecond inAngularSpeed, uint gear, Second lastShiftTime); public abstract uint InitGear(Second absTime, Second dt, NewtonMeter outTorque, PerSecond outEngineSpeed); + public Gearbox Gearbox { get; set; } /// <summary> /// Tests if the operating point is below the down-shift curve (=outside of shift curve). /// </summary> + /// <param name="gear">The gear.</param> + /// <param name="inTorque">The in torque.</param> + /// <param name="inEngineSpeed">The in engine speed.</param> + /// <returns><c>true</c> if the operating point is below the down-shift curv; otherwise, <c>false</c>.</returns> protected virtual bool IsBelowDownShiftCurve(uint gear, NewtonMeter inTorque, PerSecond inEngineSpeed) { if (gear <= 1) { @@ -38,12 +47,20 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl } var downSection = Data.Gears[gear].ShiftPolygon.Downshift.GetSection(entry => entry.AngularSpeed < inEngineSpeed); + if (downSection.Item2.AngularSpeed < inEngineSpeed) { + return false; + } + return IsOnLeftSide(inEngineSpeed, inTorque, downSection.Item1, downSection.Item2); } /// <summary> - /// Tests if the gearbox is above the up-shift curve (=outside of shift curve). + /// Tests if the operating point is above the up-shift curve (=outside of shift curve). /// </summary> + /// <param name="gear">The gear.</param> + /// <param name="inTorque">The in torque.</param> + /// <param name="inEngineSpeed">The in engine speed.</param> + /// <returns><c>true</c> if the operating point is above the up-shift curve; otherwise, <c>false</c>.</returns> protected virtual bool IsAboveUpShiftCurve(uint gear, NewtonMeter inTorque, PerSecond inEngineSpeed) { if (gear >= Data.Gears.Count) { @@ -51,16 +68,24 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl } var upSection = Data.Gears[gear].ShiftPolygon.Upshift.GetSection(entry => entry.AngularSpeed < inEngineSpeed); + + if (upSection.Item2.AngularSpeed < inEngineSpeed) { + return true; + } + return IsOnRightSide(inEngineSpeed, inTorque, upSection.Item1, upSection.Item2); } /// <summary> - /// Tests if current power request is left or right of the shiftpolygon segment + /// Tests if current power request is on the left side of the shiftpolygon segment /// </summary> - /// <remarks> - /// Computes a simplified cross product for the vectors: from-->X, from-->to and checks - /// if the z-component is positive (which means that X was on the right side of from-->to). - /// </remarks> + /// <param name="angularSpeed">The angular speed.</param> + /// <param name="torque">The torque.</param> + /// <param name="from">From.</param> + /// <param name="to">To.</param> + /// <returns><c>true</c> if current power request is on the left side of the shiftpolygon segment; otherwise, <c>false</c>.</returns> + /// <remarks>Computes a simplified cross product for the vectors: from--X, from--to and checks + /// if the z-component is positive (which means that X was on the right side of from--to).</remarks> private static bool IsOnLeftSide(PerSecond angularSpeed, NewtonMeter torque, ShiftPolygon.ShiftPolygonEntry from, ShiftPolygon.ShiftPolygonEntry to) { @@ -71,12 +96,15 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl } /// <summary> - /// Tests if current power request is left or right of the shiftpolygon segment + /// Tests if current power request is on the left side of the shiftpolygon segment /// </summary> - /// <remarks> - /// Computes a simplified cross product for the vectors: from-->X, from-->to and checks - /// if the z-component is negative (which means that X was on the left side of from-->to). - /// </remarks> + /// <param name="angularSpeed">The angular speed.</param> + /// <param name="torque">The torque.</param> + /// <param name="from">From.</param> + /// <param name="to">To.</param> + /// <returns><c>true</c> if current power request is on the left side of the shiftpolygon segment; otherwise, <c>false</c>.</returns> + /// <remarks>Computes a simplified cross product for the vectors: from--X, from--to and checks + /// if the z-component is negative (which means that X was on the left side of from--to).</remarks> private static bool IsOnRightSide(PerSecond angularSpeed, NewtonMeter torque, ShiftPolygon.ShiftPolygonEntry from, ShiftPolygon.ShiftPolygonEntry to) { @@ -87,6 +115,9 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl } } + /// <summary> + /// AMTShiftStrategy implements the AMT Shifting Behaviour. + /// </summary> public class AMTShiftStrategy : ShiftStrategy { /// <summary> @@ -99,111 +130,37 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl PreviousGear = 1; } - private uint GetGear(Second absTime, Second dt, NewtonMeter outTorque, PerSecond outAngularSpeed, bool skipGears, - double torqueReserve) - { - // maxGear ratio must not result in a angularSpeed below idle-speed - var maxGear = (uint)(skipGears ? Data.Gears.Count : Math.Min(PreviousGear + 1, Data.Gears.Count)); - var minGear = skipGears ? 1 : Math.Max(PreviousGear - 1, 1); - - while (outAngularSpeed * Data.Gears[maxGear].Ratio < DataBus.EngineIdleSpeed && maxGear > minGear) { - maxGear--; - } - - // minGear ratio must not result in an angularSpeed above ratedspeed-range * 1.2 - while ((outAngularSpeed * Data.Gears[minGear].Ratio - DataBus.EngineIdleSpeed) / - (DataBus.EngineRatedSpeed - DataBus.EngineIdleSpeed) >= 1.2 && minGear < maxGear) { - minGear++; - } - - // loop only runs from maxGear to minGear+1 because minGear is returned afterwards anyway. - for (var gear = maxGear; gear > minGear; gear--) { - Gearbox.Gear = gear; - var response = (ResponseDryRun)Gearbox.Request(absTime, dt, outTorque, outAngularSpeed, true); - var currentPower = response.EnginePowerRequest; - - var fullLoadPower = currentPower - response.DeltaFullLoad; - var reserve = 1 - (currentPower / fullLoadPower).Cast<Scalar>(); - - var inAngularSpeed = outAngularSpeed * Data.Gears[gear].Ratio; - var inTorque = response.ClutchPowerRequest / inAngularSpeed; - - // if in shift curve and torque reserve is provided: return the current gear - if (!IsBelowDownShiftCurve(gear, inTorque, inAngularSpeed) && - !IsAboveUpShiftCurve(gear, inTorque, inAngularSpeed) && - reserve >= torqueReserve) { - return gear; - } - - // if over the up shift curve: return the previous gear (although it did not provide the required torque reserve) - if (IsAboveUpShiftCurve(gear, inTorque, inAngularSpeed) && gear < maxGear) { - return gear + 1; - } - } - return minGear; - } - - public override uint Engage(Second absTime, Second dt, NewtonMeter outTorque, PerSecond outEngineSpeed) + private bool SpeedTooLowForEngine(uint gear, PerSecond outAngularSpeed) { - return GetGear(absTime, dt, outTorque, outEngineSpeed, Data.SkipGears, Data.TorqueReserve); + return (outAngularSpeed * Data.Gears[NextGear].Ratio).IsSmaller(DataBus.EngineIdleSpeed); } - public override void Disengage(Second absTime, Second dt, NewtonMeter outTorque, PerSecond outEngineSpeed) + // original vecto2.2: (inAngularSpeed - IdleSpeed) / (RatedSpeed - IdleSpeed) >= 1.2 + // = inAngularSpeed - IdleSpeed >= 1.2*(RatedSpeed - IdleSpeed) + // = inAngularSpeed >= 1.2*RatedSpeed - 0.2*IdleSpeed + private bool SpeedTooHighForEngine(uint gear, PerSecond outAngularSpeed) { - PreviousGear = Gearbox.Gear; + return (outAngularSpeed * Data.Gears[NextGear].Ratio).IsGreaterOrEqual(1.2 * DataBus.EngineRatedSpeed - + 0.2 * DataBus.EngineIdleSpeed); } - public override bool ShiftRequired(Second absTime, Second dt, NewtonMeter outTorque, PerSecond outAngularVelocity, - NewtonMeter inTorque, PerSecond inAngularVelocity, uint gear, Second lastShiftTime) - { - if (DataBus.VehicleStopped) { - return false; - } - - var minimumShiftTimePassed = (lastShiftTime + Data.ShiftTime).IsSmallerOrEqual(absTime); - if (!minimumShiftTimePassed) { - return false; - } - - var speedTooLowForEngine = inAngularVelocity < DataBus.EngineIdleSpeed; - var speedToHighForEngine = (inAngularVelocity * Data.Gears[gear].Ratio - DataBus.EngineIdleSpeed) / - (DataBus.EngineRatedSpeed - DataBus.EngineIdleSpeed) >= 1.2; - - // if angularSpeed is too high or too low to operate the engine, a shift is needed, regardless of shiftTime - if (gear > 1 && speedTooLowForEngine || gear < Data.Gears.Count && speedToHighForEngine) { - return true; - } - // todo: simulate traction interruption power request change after shift - // and only shift if simulated power request still fullfills the shift conditions. - - if (IsBelowDownShiftCurve(gear, inTorque, inAngularVelocity) || - IsAboveUpShiftCurve(gear, inTorque, inAngularVelocity)) { - return true; + public override uint Engage(Second absTime, Second dt, NewtonMeter outTorque, PerSecond outAngularVelocity) + { + while (NextGear > 1 && SpeedTooLowForEngine(NextGear, outAngularVelocity)) { + NextGear--; } - - if (Data.EarlyShiftUp && gear < Data.Gears.Count) { - // try if next gear would provide enough torque reserve - var nextGear = gear + 1; - - //todo: is initialize correct? shouldnt it be a dry run request? but gear has to be set in advance - var response = Gearbox.Initialize(nextGear, outTorque, outAngularVelocity); - - var nextAngularVelocity = Data.Gears[nextGear].Ratio * outAngularVelocity; - - if (!IsBelowDownShiftCurve(nextGear, response.ClutchPowerRequest / nextAngularVelocity, nextAngularVelocity)) { - var fullLoadPower = response.EnginePowerRequest - response.DeltaFullLoad; - var reserve = 1 - (response.EnginePowerRequest / fullLoadPower).Cast<Scalar>(); - - if (reserve >= Data.TorqueReserve) { - return true; - } - } + while (NextGear < Data.Gears.Count && SpeedTooHighForEngine(NextGear, outAngularVelocity)) { + NextGear++; } + return NextGear; + } - return false; + public override void Disengage(Second absTime, Second dt, NewtonMeter outTorque, PerSecond outEngineSpeed) + { + PreviousGear = Gearbox.Gear; } public override uint InitGear(Second absTime, Second dt, NewtonMeter outTorque, PerSecond outEngineSpeed) @@ -254,6 +211,98 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl // fallback: return first gear return 1; } + + public override bool ShiftRequired(Second absTime, Second dt, NewtonMeter outTorque, PerSecond outAngularVelocity, + NewtonMeter inTorque, PerSecond inAngularVelocity, uint gear, Second lastShiftTime) + { + // no shift when vehicle stands + if (DataBus.VehicleStopped) { + return false; + } + + // emergency shift to not stall the engine ------------------------ + NextGear = gear; + while (NextGear > 1 && SpeedTooLowForEngine(NextGear, outAngularVelocity)) { + NextGear--; + } + while (NextGear < Data.Gears.Count && SpeedTooHighForEngine(NextGear, outAngularVelocity)) { + NextGear++; + } + if (NextGear != gear) { + return true; + } + + + // normal shift when all requirements are fullfilled ------------------ + var minimumShiftTimePassed = (lastShiftTime + Data.ShiftTime).IsSmaller(absTime); + if (!minimumShiftTimePassed) { + return false; + } + + // down shift + while (IsBelowDownShiftCurve(NextGear, inTorque, inAngularVelocity)) { + NextGear--; + if (!Data.SkipGears) { + break; + } + + var tmpGear = Gearbox.Gear; + Gearbox.Gear = NextGear; + var response = (ResponseDryRun)Gearbox.Request(absTime, dt, outTorque, outAngularVelocity, true); + Gearbox.Gear = tmpGear; + + inAngularVelocity = Data.Gears[NextGear].Ratio * outAngularVelocity; + inTorque = response.ClutchPowerRequest / inAngularVelocity; + } + + if (NextGear != gear) { + return true; + } + + // upshift + while (IsAboveUpShiftCurve(NextGear, inTorque, inAngularVelocity)) { + NextGear++; + if (!Data.SkipGears) { + break; + } + + var tmpGear = Gearbox.Gear; + Gearbox.Gear = NextGear; + var response = (ResponseDryRun)Gearbox.Request(absTime, dt, outTorque, outAngularVelocity, true); + Gearbox.Gear = tmpGear; + + inAngularVelocity = Data.Gears[NextGear].Ratio * outAngularVelocity; + inTorque = response.ClutchPowerRequest / inAngularVelocity; + } + + // early up shift to higher gear --------------------------------------- + if (Data.EarlyShiftUp && NextGear < Data.Gears.Count) { + // try if next gear would provide enough torque reserve + var tryNextGear = NextGear + 1; + var tmpGear = Gearbox.Gear; + Gearbox.Gear = tryNextGear; + var response = (ResponseDryRun)Gearbox.Request(absTime, dt, outTorque, outAngularVelocity, true); + Gearbox.Gear = tmpGear; + + inAngularVelocity = Data.Gears[tryNextGear].Ratio * outAngularVelocity; + inTorque = response.ClutchPowerRequest / inAngularVelocity; + + // if next gear supplied enough power reserve: take it + // otherwise take + if (!IsBelowDownShiftCurve(tryNextGear, inTorque, inAngularVelocity)) { + var fullLoadPower = response.EnginePowerRequest - response.DeltaFullLoad; + var reserve = 1 - (response.EnginePowerRequest / fullLoadPower).Cast<Scalar>(); + + if (reserve >= Data.TorqueReserve) { + NextGear = tryNextGear; + } + } + } + + return (NextGear != gear); + } + + public uint NextGear { get; set; } } //TODO Implement MTShiftStrategy @@ -263,12 +312,12 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl public override uint Engage(Second absTime, Second dt, NewtonMeter outTorque, PerSecond outEngineSpeed) { - throw new System.NotImplementedException(); + throw new NotImplementedException(); } public override void Disengage(Second absTime, Second dt, NewtonMeter outTorque, PerSecond outEngineSpeed) { - throw new System.NotImplementedException(); + throw new NotImplementedException(); } public override bool ShiftRequired(Second absTime, Second dt, NewtonMeter outTorque, PerSecond outAngularVelocity, @@ -278,10 +327,9 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl throw new NotImplementedException(); } - public override uint InitGear(Second absTime, Second dt, NewtonMeter outTorque, PerSecond outEngineSpeed) { - throw new System.NotImplementedException(); + throw new NotImplementedException(); } } @@ -292,12 +340,12 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl public override uint Engage(Second absTime, Second dt, NewtonMeter outTorque, PerSecond outEngineSpeed) { - throw new System.NotImplementedException(); + throw new NotImplementedException(); } public override void Disengage(Second absTime, Second dt, NewtonMeter outTorque, PerSecond outEngineSpeed) { - throw new System.NotImplementedException(); + throw new NotImplementedException(); } public override bool ShiftRequired(Second absTime, Second dt, NewtonMeter outTorque, PerSecond outAngularVelocity, @@ -307,10 +355,9 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl throw new NotImplementedException(); } - public override uint InitGear(Second absTime, Second dt, NewtonMeter outTorque, PerSecond outEngineSpeed) { - throw new System.NotImplementedException(); + throw new NotImplementedException(); } } @@ -319,7 +366,6 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl { public CustomShiftStrategy(GearboxData data, IDataBus dataBus) : base(data, dataBus) {} - public override bool ShiftRequired(Second absTime, Second dt, NewtonMeter outTorque, PerSecond outAngularVelocity, NewtonMeter inTorque, PerSecond inAngularSpeed, uint gear, Second lastShiftTime) diff --git a/VectoCore/Utils/SI.cs b/VectoCore/Utils/SI.cs index b5ef5de8534c7fe21adcac355413d5b6f1d4f608..bef29889a3e2b9bd180f3517704207afdf0096c3 100644 --- a/VectoCore/Utils/SI.cs +++ b/VectoCore/Utils/SI.cs @@ -925,6 +925,7 @@ namespace TUGraz.VectoCore.Utils /// Returns the numerical sign of the SI. /// </summary> /// <returns>-1 if si < 0. 0 if si==0, 1 if si > 0.</returns> + [DebuggerHidden] public int Sign() { return Math.Sign(Val); diff --git a/VectoCoreTest/Integration/Truck40tPowerTrain.cs b/VectoCoreTest/Integration/Truck40tPowerTrain.cs index c0e3963865f2570909e5aca689532b5055a77c87..576ea99097d79b48e0629963c2612d64269e825f 100644 --- a/VectoCoreTest/Integration/Truck40tPowerTrain.cs +++ b/VectoCoreTest/Integration/Truck40tPowerTrain.cs @@ -104,7 +104,7 @@ namespace TUGraz.VectoCore.Tests.Integration TorqueReserve = 0.2, StartTorqueReserve = 0.2, SkipGears = true, - EarlyShiftUp = false, + EarlyShiftUp = true, }; } diff --git a/VectoCoreTest/Utils/GraphWriter.cs b/VectoCoreTest/Utils/GraphWriter.cs index 8fc4f77561e280815330a67abfc17d22caf1c8bf..16200c31aaeaaa7872657cada645b30b2fbfa235 100644 --- a/VectoCoreTest/Utils/GraphWriter.cs +++ b/VectoCoreTest/Utils/GraphWriter.cs @@ -61,7 +61,7 @@ namespace TUGraz.VectoCore.Tests.Utils .Select(v => v.Field<string>(ModalResultField.v_targ.GetName())) .Select(v => string.IsNullOrWhiteSpace(v) ? "0" : v); - values += string.Format("|{0}|{1}", string.Join(",", x), string.Join(",", y3)); + values += string.Format("|{0}|{1}|0|0", string.Join(",", x), string.Join(",", y3)); } values = values.Replace("NaN", "0");