private void RecalculateAndScaleCurves(object sender, RoutedEventArgs e) { double maxPower, maxTorque; if (!FlexibleParser.TryParseDouble(PowerInput.Text, out maxPower) || !FlexibleParser.TryParseDouble(TorqueInput.Text, out maxTorque)) { NonfatalError.Notify(ToolsStrings.Common_CannotDo_Title, AppStrings.CarSpecs_SpecifyPowerAndTorqueFirst); return; } var data = Car.AcdData; if (data == null) { NonfatalError.Notify(ToolsStrings.Common_CannotDo_Title, "Data is damaged"); return; } Lut torque; try { torque = TorquePhysicUtils.LoadCarTorque(data); } catch (Exception ex) { NonfatalError.Notify(ToolsStrings.Common_CannotDo_Title, ex); return; } torque.ScaleToSelf(maxTorque); TorqueGraph = new GraphData(torque); torque.TransformSelf(x => x.X * x.Y); torque.ScaleToSelf(maxPower); PowerGraph = new GraphData(torque); }
protected override ContentRepairSuggestion GetObsoletableAspect(CarObject car, DataWrapper data) { // doesn’t work with KERS if (!data.GetIniFile("ers.ini").IsEmptyOrDamaged() || !data.GetIniFile("ctrl_ers_0.ini").IsEmptyOrDamaged()) { return(null); } if ((car.SpecsBhp?.IndexOf("*", StringComparison.Ordinal) ?? 0) != -1 || (car.SpecsBhp?.IndexOf("whp", StringComparison.OrdinalIgnoreCase) ?? 0) != -1 || (car.SpecsTorque?.IndexOf("*", StringComparison.Ordinal) ?? 0) != -1 || !FlexibleParser.TryParseDouble(car.SpecsTorque, out var maxUiTorque)) { return(null); } Lut torque; try { torque = TorquePhysicUtils.LoadCarTorque(data); } catch (Exception e) { Logging.Warning(e); return(null); } var loss = 1d - torque.MaxY / maxUiTorque; if (loss > 0.01) { return(null); } var actual = loss.Abs() < 0.002 ? "same" : loss > 0 ? $"{loss * 100:F1}% smaller" : $"{-loss * 100:F1}% bigger"; return(new CommonErrorSuggestion("Suspiciously low transmission power loss", $"Usually, in UI torque & power are taken from crankshaft, but data should contain torque at wheels, which is about 10–20% smaller. " + $"Here, although, it’s {actual}. It might be a mistake.\n\nIf you want to specify power at the wheels in UI, add “*”.", (p, c) => FixAsync(car, p, c)) { AffectsData = false, ShowProgressDialog = false, FixCaption = "Fix UI" }.AlternateFix("Add “*”", (progress, token) => { if (FlexibleParser.TryParseDouble(car.SpecsBhp, out var uiBhp)) { car.SpecsBhp = SelectedAcObjectViewModel.SpecsFormat(AppStrings.CarSpecs_PowerAtWheels_FormatTooltip, uiBhp.ToString(@"F0", CultureInfo.InvariantCulture)); } if (FlexibleParser.TryParseDouble(car.SpecsTorque, out var uiTorque)) { car.SpecsTorque = SelectedAcObjectViewModel.SpecsFormat(AppStrings.CarSpecs_Torque_FormatTooltip, uiTorque.ToString(@"F0", CultureInfo.InvariantCulture)) + "*"; } return Task.FromResult(true); }, false)); }
protected override Task <bool> FixAsync(CarObject car, IProgress <AsyncProgressEntry> progress = null, CancellationToken cancellation = default(CancellationToken)) { progress?.Report(AsyncProgressEntry.FromStringIndetermitate("Fixing car…")); var data = car.AcdData; if (data == null || data.IsEmpty) { return(Task.FromResult(false)); } Lut torque, power; try { torque = TorquePhysicUtils.LoadCarTorque(data); power = TorquePhysicUtils.TorqueToPower(torque); } catch (Exception e) { Logging.Error(e); return(Task.FromResult(false)); } var multipler = ActionExtension.InvokeInMainThread(() => { var dlg = new CarTransmissionLossSelector(car, torque.MaxY, power.MaxY); dlg.ShowDialog(); return(dlg.IsResultOk ? dlg.Multipler : (double?)null); }); if (!multipler.HasValue) { return(Task.FromResult(false)); } torque.TransformSelf(x => x.Y * multipler.Value); power.TransformSelf(x => x.Y * multipler.Value); if (car.SpecsTorqueCurve != null) { var torqueUi = new Lut(car.SpecsTorqueCurve.Points); torqueUi.TransformSelf(x => x.Y * multipler.Value); car.SpecsTorqueCurve = new GraphData(torqueUi); } if (car.SpecsPowerCurve != null) { var powerUi = new Lut(car.SpecsPowerCurve.Points); powerUi.TransformSelf(x => x.Y * multipler.Value); car.SpecsPowerCurve = new GraphData(powerUi); } car.SpecsTorque = SelectedAcObjectViewModel.SpecsFormat(AppStrings.CarSpecs_Torque_FormatTooltip, torque.MaxY.ToString(@"F0", CultureInfo.InvariantCulture)) + (multipler.Value == 1d ? "*" : ""); car.SpecsBhp = SelectedAcObjectViewModel.SpecsFormat(multipler.Value == 1d ? AppStrings.CarSpecs_PowerAtWheels_FormatTooltip : AppStrings.CarSpecs_Power_FormatTooltip, power.MaxY.ToString(@"F0", CultureInfo.InvariantCulture)); return(Task.FromResult(true)); }
public void NegativePoint() { var data = new DataDirectoryWrapper(Path.Combine(TestDir, "physics", "negative_point")); var powerLutPointsOnly = TorquePhysicUtils.LoadCarTorque(data); Assert.AreEqual(100, powerLutPointsOnly.InterpolateLinear(-100d), 0.1); Assert.AreEqual(100d, powerLutPointsOnly.InterpolateLinear(0d), 0.1); Assert.AreEqual(200d, powerLutPointsOnly.InterpolateLinear(5000d), 0.1); }
public void TurboTest() { var data = new DataDirectoryWrapper(Path.Combine(TestDir, "physics", "turbo_test")); var torque = TorquePhysicUtils.LoadCarTorque(data); Assert.AreEqual(100d, torque.InterpolateLinear(0d), 0.1); Assert.AreEqual(125d, torque.InterpolateLinear(1500d), 0.1); Assert.AreEqual(150d, torque.InterpolateLinear(3000d), 0.1); Assert.AreEqual(150d, torque.InterpolateLinear(4000d), 0.1); Assert.AreEqual(150d, torque.InterpolateLinear(5000d), 0.1); }
private void RecalculateCurves(object sender, RoutedEventArgs e) { var o = Car; var data = o.AcdData; if (data == null) { NonfatalError.Notify(ToolsStrings.Common_CannotDo_Title, "Data is damaged"); return; } Lut torque, power; try { torque = TorquePhysicUtils.LoadCarTorque(data); power = TorquePhysicUtils.TorqueToPower(torque); } catch (Exception ex) { NonfatalError.Notify(ToolsStrings.Common_CannotDo_Title, ex); return; } var dlg = new CarTransmissionLossSelector(o, torque.MaxY, power.MaxY); dlg.ShowDialog(); if (!dlg.IsResultOk) { return; } torque.TransformSelf(x => x.Y * dlg.Multipler); power.TransformSelf(x => x.Y * dlg.Multipler); o.SpecsTorqueCurve = new GraphData(torque); o.SpecsPowerCurve = new GraphData(power); if (ShowMessage(AppStrings.CarSpecs_CopyNewPowerAndTorque, AppStrings.Common_OneMoreThing, MessageBoxButton.YesNo, "copyNewPowerAndTorque") == MessageBoxResult.Yes) { // MaxY values were updated while creating new GraphData instances above var postfix = dlg.Multipler == 1d ? "*" : ""; TorqueInput.Text = Format(AppStrings.CarSpecs_Torque_FormatTooltip, torque.MaxY.ToString(@"F0", CultureInfo.InvariantCulture)) + postfix; PowerInput.Text = Format(AppStrings.CarSpecs_Power_FormatTooltip, power.MaxY.ToString(@"F0", CultureInfo.InvariantCulture)) + postfix; } }
public void InterpolationMode() { var data = new DataDirectoryWrapper(Path.Combine(TestDir, "physics", "two_points")); var powerLutPointsOnly = TorquePhysicUtils.LoadCarTorque(data, false, 0); Assert.AreEqual(100d, powerLutPointsOnly.InterpolateLinear(0d), 0.1); Assert.AreEqual(125d, powerLutPointsOnly.InterpolateLinear(1250d), 0.1); Assert.AreEqual(150d, powerLutPointsOnly.InterpolateLinear(2500d), 0.1); Assert.AreEqual(200d, powerLutPointsOnly.InterpolateLinear(5000d), 0.1); var detailedMode = TorquePhysicUtils.LoadCarTorque(data, false); Assert.AreEqual(100d, detailedMode.InterpolateLinear(0d), 0.1); Assert.AreEqual(109.8d, detailedMode.InterpolateLinear(1250d), 0.1); Assert.AreEqual(139.2d, detailedMode.InterpolateLinear(2500d), 0.1); Assert.AreEqual(164.2, detailedMode.InterpolateLinear(3200d), 0.1); Assert.AreEqual(200d, detailedMode.InterpolateLinear(4000d), 0.1); Assert.AreEqual(200d, detailedMode.InterpolateLinear(5000d), 0.1); }
public void ConsiderLimiterMode() { var data = new DataDirectoryWrapper(Path.Combine(TestDir, "physics", "two_points")); var notConsider = TorquePhysicUtils.LoadCarTorque(data, false, 0); Assert.AreEqual(160, notConsider.InterpolateLinear(3000d), 0.1); Assert.AreEqual(200d, notConsider.InterpolateLinear(5000d), 0.1); var consider = TorquePhysicUtils.LoadCarTorque(data, true, 0); Assert.AreEqual(156.3d, consider.InterpolateLinear(3000d), 0.1); Assert.AreEqual(156.3d, consider.InterpolateLinear(5000d), 0.1); var notConsiderDetailed = TorquePhysicUtils.LoadCarTorque(data, false); Assert.AreEqual(156.3d, notConsiderDetailed.InterpolateLinear(3000d), 0.1); Assert.AreEqual(200d, notConsiderDetailed.InterpolateLinear(5000d), 0.1); var considerDetailed = TorquePhysicUtils.LoadCarTorque(data); Assert.AreEqual(156.3d, considerDetailed.InterpolateLinear(3000d), 0.1); Assert.AreEqual(156.3d, considerDetailed.InterpolateLinear(5000d), 0.1); }