diff --git a/VectoCore/VectoCore/Models/SimulationComponent/Impl/ATShiftStrategy.cs b/VectoCore/VectoCore/Models/SimulationComponent/Impl/ATShiftStrategy.cs index 0005cf834f32fd9b91c5cfb88e564dada548a6c9..8dc7f87172e511f5772122b0c4b6cb277b356c26 100644 --- a/VectoCore/VectoCore/Models/SimulationComponent/Impl/ATShiftStrategy.cs +++ b/VectoCore/VectoCore/Models/SimulationComponent/Impl/ATShiftStrategy.cs @@ -29,6 +29,7 @@ * Martin Rexeis, rexeis@ivt.tugraz.at, IVT, Graz University of Technology */ +using System; using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; using System.Linq; @@ -51,7 +52,7 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl public class ATShiftStrategy : BaseShiftStrategy { protected ATGearbox _gearbox; - private readonly NextGearState _nextGear = new NextGearState(); + protected readonly NextGearState _nextGear = new NextGearState(); public override IGearbox Gearbox { diff --git a/VectoCore/VectoCore/Models/SimulationComponent/Impl/ATShiftStrategyOptimized.cs b/VectoCore/VectoCore/Models/SimulationComponent/Impl/ATShiftStrategyOptimized.cs index 0d877ce404ee6913e262614c02c61edcb072c16e..96884608e17442d0982883b24fe338df5f0d2c91 100644 --- a/VectoCore/VectoCore/Models/SimulationComponent/Impl/ATShiftStrategyOptimized.cs +++ b/VectoCore/VectoCore/Models/SimulationComponent/Impl/ATShiftStrategyOptimized.cs @@ -1,6 +1,8 @@ using System; using System.Collections.Generic; +using System.Diagnostics; using System.Linq; +using Ninject.Extensions.NamedScope; using TUGraz.VectoCommon.Exceptions; using TUGraz.VectoCommon.InputData; using TUGraz.VectoCommon.Models; @@ -27,6 +29,7 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl private SimplePowertrainContainer TestContainer; private ATGearbox TestContainerGbx; + protected readonly List<GearshiftPosition> GearList; public new static string Name { @@ -61,7 +64,25 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl } catch (Exception ) { } } - + if (shiftStrategyParameters.AllowedGearRangeFC > 2 || shiftStrategyParameters.AllowedGearRangeFC < 1) { + Log.Warn("Gear-range for FC-based gearshift must be either 1 or 2!"); + shiftStrategyParameters.AllowedGearRangeFC = shiftStrategyParameters.AllowedGearRangeFC.LimitTo(1, 2); + } + + + GearList = new List<GearshiftPosition>(); + foreach (var gear in runData.GearboxData.Gears) { + if (runData.GearboxData.Type.AutomaticTransmission()) { + if (gear.Value.HasTorqueConverter) { + GearList.Add(new GearshiftPosition(gear.Key, false)); + } + if (gear.Value.HasLockedGear) { + GearList.Add(new GearshiftPosition(gear.Key, true)); + } + } else { + GearList.Add(new GearshiftPosition(gear.Key)); + } + } } #region Overrides of ATShiftStrategy @@ -70,84 +91,157 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl Second absTime, Second dt, NewtonMeter outTorque, PerSecond outAngularVelocity, NewtonMeter origInTorque, PerSecond origInAngularVelocity, uint currentGear, Second lastShiftTime) { - var tryNextGear = _gearbox.TorqueConverterLocked ? currentGear + 1 : currentGear; - if (!(ModelData.Gears[tryNextGear].Ratio <= shiftStrategyParameters.RatioEarlyDownshiftFC)) { - return null; - } + var minFcGear = new GearshiftPosition(currentGear, _gearbox.TorqueConverterLocked); + var minFc = double.MaxValue; + KilogramPerSecond fcCurrent = null; + + var current = new GearshiftPosition(currentGear, _gearbox.TorqueConverterLocked); + var currentIdx = GearList.IndexOf(current); + + for (var i = 1; i <= shiftStrategyParameters.AllowedGearRangeFC; i++) { + + if (currentIdx + i >= GearList.Count) { + // no further gear + continue; + } + + var next = GearList[currentIdx + i]; + if (current.TorqueConverterLocked != next.TorqueConverterLocked && current.Gear != next.Gear) { + // upshift from C to L with skipping gear not allowed + continue; + } + + if (!(ModelData.Gears[next.Gear].Ratio < shiftStrategyParameters.RatioEarlyUpshiftFC)) { + continue; + } + + + var response = RequestDryRunWithGear(absTime, dt, outTorque, outAngularVelocity, next); - var response = RequestDryRunWithGear(absTime, dt, outTorque, outAngularVelocity, tryNextGear, true); + var inAngularVelocity = ModelData.Gears[next.Gear].Ratio * outAngularVelocity; + var inTorque = response.EnginePowerRequest / inAngularVelocity; - var inAngularVelocity = ModelData.Gears[tryNextGear].Ratio * outAngularVelocity; - var inTorque = response.EnginePowerRequest / inAngularVelocity; + // if next gear supplied enough power reserve: take it + // otherwise take + if (ModelData.Gears[next.Gear].ShiftPolygon.IsBelowDownshiftCurve(inTorque, inAngularVelocity)) { + continue; + } - // if next gear supplied enough power reserve: take it - // otherwise take - if (!ModelData.Gears[tryNextGear].ShiftPolygon.IsBelowDownshiftCurve(inTorque, inAngularVelocity)) { var fullLoadPower = response.EnginePowerRequest - response.DeltaFullLoad; var reserve = 1 - response.EnginePowerRequest / fullLoadPower; - var responseCurrent = RequestDryRunWithGear(absTime, dt, outTorque, outAngularVelocity, currentGear, _gearbox.TorqueConverterLocked); - var fcCurrent = fcMap.GetFuelConsumption( - responseCurrent.EngineTorqueDemand.LimitTo( - fld[currentGear].DragLoadStationaryTorque(responseCurrent.EngineSpeed), - fld[currentGear].FullLoadStationaryTorque(responseCurrent.EngineSpeed)) - , responseCurrent.EngineSpeed); + if (fcCurrent == null) { + var responseCurrent = RequestDryRunWithGear( + absTime, dt, outTorque, outAngularVelocity, current); + fcCurrent = fcMap.GetFuelConsumption( + responseCurrent.EngineTorqueDemand.LimitTo( + fld[currentGear].DragLoadStationaryTorque(responseCurrent.EngineSpeed), + fld[currentGear].FullLoadStationaryTorque(responseCurrent.EngineSpeed)) + , responseCurrent.EngineSpeed).Value; + } var fcNext = fcMap.GetFuelConsumption( response.EngineTorqueDemand.LimitTo( - fld[tryNextGear].DragLoadStationaryTorque(response.EngineSpeed), - fld[tryNextGear].FullLoadStationaryTorque(response.EngineSpeed)), response.EngineSpeed); + fld[next.Gear].DragLoadStationaryTorque(response.EngineSpeed), + fld[next.Gear].FullLoadStationaryTorque(response.EngineSpeed)), response.EngineSpeed).Value; - if (reserve >= ModelData.TorqueReserve && fcNext.Value.IsSmaller(fcCurrent.Value * shiftStrategyParameters.RatingFactorCurrentGear)) { - Upshift(absTime, currentGear); - return true; + if (reserve < ModelData.TorqueReserve || + !fcNext.IsSmaller(fcCurrent * shiftStrategyParameters.RatingFactorCurrentGear) || !fcNext.IsSmaller(minFc)) { + continue; } + + minFc = fcNext.Value(); + minFcGear = next; } - return null; + + if (!minFcGear.Equals(current)) { + ShiftGear(absTime, current, minFcGear); + return true; + } + + return null; } + + protected override bool? CheckEarlyDownshift( Second absTime, Second dt, NewtonMeter outTorque, PerSecond outAngularVelocity, NewtonMeter origInTorque, PerSecond origInAngularVelocity, uint currentGear, Second lastShiftTime) { - var tryNextGear = _gearbox.TorqueConverterLocked && currentGear == 1 ? currentGear : currentGear - 1; - var tryNextTc = currentGear == 1 && _gearbox.TorqueConverterLocked ? false : true; - if (!(ModelData.Gears[tryNextGear].Ratio < shiftStrategyParameters.RatioEarlyUpshiftFC)) { - return null; - } + var minFcGear = new GearshiftPosition(currentGear, _gearbox.TorqueConverterLocked); + var minFc = double.MaxValue; + KilogramPerSecond fcCurrent = null; - var response = RequestDryRunWithGear(absTime, dt, outTorque, outAngularVelocity, tryNextGear, tryNextTc); + var current = new GearshiftPosition(currentGear, _gearbox.TorqueConverterLocked); + var currentIdx = GearList.IndexOf(current); - var inAngularVelocity = ModelData.Gears[tryNextGear].Ratio * outAngularVelocity; - var inTorque = response.EnginePowerRequest / inAngularVelocity; + for (var i = 1; i <= shiftStrategyParameters.AllowedGearRangeFC; i++) { - if (!IsAboveUpShiftCurve(tryNextGear, inTorque, inAngularVelocity, tryNextTc)) { - var responseCurrent = RequestDryRunWithGear(absTime, dt, outTorque, outAngularVelocity, currentGear, _gearbox.TorqueConverterLocked); - var fcCurrent = fcMap.GetFuelConsumption( - responseCurrent.EngineTorqueDemand.LimitTo( - fld[currentGear].DragLoadStationaryTorque(responseCurrent.EngineSpeed), - fld[currentGear].FullLoadStationaryTorque(responseCurrent.EngineSpeed)) - , responseCurrent.EngineSpeed); - var fcNext = fcMap.GetFuelConsumption( - response.EngineTorqueDemand.LimitTo( - fld[tryNextGear].DragLoadStationaryTorque(response.EngineSpeed), - fld[tryNextGear].FullLoadStationaryTorque(response.EngineSpeed)), response.EngineSpeed); + if (currentIdx - i < 0) { + // no further gear + continue; + } + + var next = GearList[currentIdx - i]; + if (current.TorqueConverterLocked != next.TorqueConverterLocked && current.Gear != next.Gear) { + // downshift from C to L with skipping gear not allowed + continue; + } + + if (!(ModelData.Gears[next.Gear].Ratio < shiftStrategyParameters.RatioEarlyDownshiftFC)) { + continue; + } + + var response = RequestDryRunWithGear(absTime, dt, outTorque, outAngularVelocity, next); + + var inAngularVelocity = ModelData.Gears[next.Gear].Ratio * outAngularVelocity; + var inTorque = response.EnginePowerRequest / inAngularVelocity; + + if (!IsAboveUpShiftCurve(next.Gear, inTorque, inAngularVelocity, next.TorqueConverterLocked.Value)) { - if (fcNext.Value.IsSmaller(fcCurrent.Value * shiftStrategyParameters.RatingFactorCurrentGear)) { - Downshift(absTime, currentGear); - return true; + if (fcCurrent == null) { + var responseCurrent = RequestDryRunWithGear(absTime, dt, outTorque, outAngularVelocity, current); + fcCurrent = fcMap.GetFuelConsumption( + responseCurrent.EngineTorqueDemand.LimitTo( + fld[currentGear].DragLoadStationaryTorque(responseCurrent.EngineSpeed), + fld[currentGear].FullLoadStationaryTorque(responseCurrent.EngineSpeed)) + , responseCurrent.EngineSpeed).Value; + } + var fcNext = fcMap.GetFuelConsumption( + response.EngineTorqueDemand.LimitTo( + fld[next.Gear].DragLoadStationaryTorque(response.EngineSpeed), + fld[next.Gear].FullLoadStationaryTorque(response.EngineSpeed)), response.EngineSpeed).Value; + + if (fcNext.IsSmaller(fcCurrent * shiftStrategyParameters.RatingFactorCurrentGear) && fcNext.IsSmaller(minFc)) { + minFcGear = next; + minFc = fcNext.Value(); + + } } } + if (!current.Equals(minFcGear)) { + ShiftGear(absTime, current, minFcGear); + return true; + } + return null; } + protected virtual void ShiftGear(Second absTime, GearshiftPosition currentGear, GearshiftPosition nextGear) + { + if (currentGear.TorqueConverterLocked != nextGear.TorqueConverterLocked && currentGear.Gear != nextGear.Gear) { + throw new VectoException("skipping gear from converter to locked not allowed! {0} -> {1}", currentGear.Name, nextGear.Name); + } + _nextGear.SetState(absTime, disengaged: false, gear: nextGear.Gear, tcLocked: nextGear.TorqueConverterLocked.Value); + } + #endregion - protected ResponseDryRun RequestDryRunWithGear(Second absTime, Second dt, NewtonMeter outTorque, PerSecond outAngularVelocity, uint tryNextGear, bool tcLocked) + protected ResponseDryRun RequestDryRunWithGear(Second absTime, Second dt, NewtonMeter outTorque, PerSecond outAngularVelocity, GearshiftPosition gear) { TestContainerGbx.Disengaged = false; - TestContainerGbx.Gear = tryNextGear; - TestContainerGbx.TorqueConverterLocked = tcLocked; + TestContainerGbx.Gear = gear.Gear; + TestContainerGbx.TorqueConverterLocked = gear.TorqueConverterLocked.Value; TestContainer.GearboxOutPort.Initialize(outTorque, outAngularVelocity); var response = (ResponseDryRun)TestContainer.GearboxOutPort.Request( @@ -182,4 +276,41 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl #endregion } + + [DebuggerDisplay("{Name}")] + public class GearshiftPosition + { + public uint Gear { get; } + public bool? TorqueConverterLocked { get; } + + public GearshiftPosition(uint gear, bool? torqueConverterLocked = null) + { + Gear = gear; + TorqueConverterLocked = torqueConverterLocked; + } + + public string Name + { + get { + return string.Format( + "{0}{1}", Gear, + Gear == 0 ? "" : (TorqueConverterLocked.HasValue ? (TorqueConverterLocked.Value ? "L" : "C") : "")); + } + } + + public override bool Equals(object x) + { + var other = x as GearshiftPosition; + if (other == null) + return false; + + return other.Gear == Gear && other.TorqueConverterLocked == TorqueConverterLocked; + } + + public override int GetHashCode() + { + return Name.GetHashCode(); + } + + } } diff --git a/VectoCore/VectoCoreTest/VectoCoreTest.csproj b/VectoCore/VectoCoreTest/VectoCoreTest.csproj index 5937c18ba757693310478e46146d192eca20f0ce..da2939b4585174aba82b319587bb2a2299ae28db 100644 --- a/VectoCore/VectoCoreTest/VectoCoreTest.csproj +++ b/VectoCore/VectoCoreTest/VectoCoreTest.csproj @@ -379,6 +379,9 @@ <None Include="TestData\Integration\ShiftStrategyV2\Class5_Tractor_4x2\Class5_Tractor.vveh"> <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> </None> + <None Include="TestData\Integration\ShiftStrategyV2\Class5_Tractor_4x2\Class5_Tractor_ENG_FC.vecto"> + <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> + </None> <None Include="TestData\Integration\ShiftStrategyV2\Class5_Tractor_4x2\Class5_Tractor_ENG_TCU.vecto"> <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> </None> @@ -2018,6 +2021,123 @@ <None Include="TestData\Integration\FullPowerTrain\unlimited.vacc"> <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> </None> + <None Include="TestData\Integration\ShiftStrategyV2\FC-Based_AT_TUG\5_ms2.vacc"> + <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> + </None> + <None Include="TestData\Integration\ShiftStrategyV2\FC-Based_AT_TUG\AccelerationReserveLookup.csv"> + <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> + </None> + <None Include="TestData\Integration\ShiftStrategyV2\FC-Based_AT_TUG\Acc_TUG.vacc"> + <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> + </None> + <None Include="TestData\Integration\ShiftStrategyV2\FC-Based_AT_TUG\Acc_ZF.vacc"> + <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> + </None> + <None Include="TestData\Integration\ShiftStrategyV2\FC-Based_AT_TUG\HeavyUrban.vdri"> + <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> + </None> + <None Include="TestData\Integration\ShiftStrategyV2\FC-Based_AT_TUG\Interurban.vdri"> + <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> + </None> + <None Include="TestData\Integration\ShiftStrategyV2\FC-Based_AT_TUG\MB_Citaro_G_MP156_HUB_UB_SUB.vveh"> + <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> + </None> + <None Include="TestData\Integration\ShiftStrategyV2\FC-Based_AT_TUG\MB_Citaro_G_MP156_IUB.vveh"> + <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> + </None> + <None Include="TestData\Integration\ShiftStrategyV2\FC-Based_AT_TUG\MB_Citaro_G_MP156_Sort.vveh"> + <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> + </None> + <None Include="TestData\Integration\ShiftStrategyV2\FC-Based_AT_TUG\MB_Citaro_G_MP156_ZF_HUB_UB_SUB.vecto"> + <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> + </None> + <None Include="TestData\Integration\ShiftStrategyV2\FC-Based_AT_TUG\MB_Citaro_G_MP156_ZF_IUB.vecto"> + <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> + </None> + <None Include="TestData\Integration\ShiftStrategyV2\FC-Based_AT_TUG\MB_Citaro_G_MP156_ZF_Sort.vecto"> + <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> + </None> + <None Include="TestData\Integration\ShiftStrategyV2\FC-Based_AT_TUG\OM470EU6_265kW_1700Nm_MP156_Engine.veng"> + <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> + </None> + <None Include="TestData\Integration\ShiftStrategyV2\FC-Based_AT_TUG\OM470EU6_265kW_1700Nm_MP156_Fullload.vfld"> + <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> + </None> + <None Include="TestData\Integration\ShiftStrategyV2\FC-Based_AT_TUG\OM470EU6_MP156_FCmap_komplett.vmap"> + <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> + </None> + <None Include="TestData\Integration\ShiftStrategyV2\FC-Based_AT_TUG\PredictionTimeLookup.csv"> + <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> + </None> + <None Include="TestData\Integration\ShiftStrategyV2\FC-Based_AT_TUG\ShareEngineSpeedHigh.csv"> + <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> + </None> + <None Include="TestData\Integration\ShiftStrategyV2\FC-Based_AT_TUG\ShareIdleLow.csv"> + <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> + </None> + <None Include="TestData\Integration\ShiftStrategyV2\FC-Based_AT_TUG\ShareTq99L.csv"> + <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> + </None> + <None Include="TestData\Integration\ShiftStrategyV2\FC-Based_AT_TUG\ShiftParameters.vtcu"> + <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> + </None> + <None Include="TestData\Integration\ShiftStrategyV2\FC-Based_AT_TUG\Shift_tc.vgbs"> + <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> + </None> + <None Include="TestData\Integration\ShiftStrategyV2\FC-Based_AT_TUG\Shift_V2_gear 1.vgbs"> + <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> + </None> + <None Include="TestData\Integration\ShiftStrategyV2\FC-Based_AT_TUG\Shift_V2_gear 2.vgbs"> + <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> + </None> + <None Include="TestData\Integration\ShiftStrategyV2\FC-Based_AT_TUG\Shift_V2_gear 3.vgbs"> + <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> + </None> + <None Include="TestData\Integration\ShiftStrategyV2\FC-Based_AT_TUG\Shift_V2_gear 4.vgbs"> + <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> + </None> + <None Include="TestData\Integration\ShiftStrategyV2\FC-Based_AT_TUG\Shift_V2_gear 5.vgbs"> + <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> + </None> + <None Include="TestData\Integration\ShiftStrategyV2\FC-Based_AT_TUG\SORT1_target_speed.vdri"> + <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> + </None> + <None Include="TestData\Integration\ShiftStrategyV2\FC-Based_AT_TUG\SORT2_target_speed.vdri"> + <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> + </None> + <None Include="TestData\Integration\ShiftStrategyV2\FC-Based_AT_TUG\SORT3_target_speed.vdri"> + <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> + </None> + <None Include="TestData\Integration\ShiftStrategyV2\FC-Based_AT_TUG\Suburban.vdri"> + <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> + </None> + <None Include="TestData\Integration\ShiftStrategyV2\FC-Based_AT_TUG\Urban.vdri"> + <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> + </None> + <None Include="TestData\Integration\ShiftStrategyV2\FC-Based_AT_TUG\ZF_1.vtlm"> + <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> + </None> + <None Include="TestData\Integration\ShiftStrategyV2\FC-Based_AT_TUG\ZF_2.vtlm"> + <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> + </None> + <None Include="TestData\Integration\ShiftStrategyV2\FC-Based_AT_TUG\ZF_3.vtlm"> + <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> + </None> + <None Include="TestData\Integration\ShiftStrategyV2\FC-Based_AT_TUG\ZF_4.vtlm"> + <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> + </None> + <None Include="TestData\Integration\ShiftStrategyV2\FC-Based_AT_TUG\ZF_5.vtlm"> + <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> + </None> + <None Include="TestData\Integration\ShiftStrategyV2\FC-Based_AT_TUG\ZF_6.vtlm"> + <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> + </None> + <None Include="TestData\Integration\ShiftStrategyV2\FC-Based_AT_TUG\ZF_EcoLife_1700_SN2837.vgbx"> + <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> + </None> + <None Include="TestData\Integration\ShiftStrategyV2\FC-Based_AT_TUG\ZF_EcoLife_1700_SN2837.vtcc"> + <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> + </None> <None Include="TestData\Integration\TotalMassExceededInMU\325kW.vfld"> <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> </None>