コード例 #1
0
        public void TODistancePackAiCorrectionTest()
        {
            var para = new TOParameters(
                0.0,
                1000.0,                     // elevation
                210.0,                      // rwy heading
                -1.8,                       // slope
                240.0,                      // wind direction
                10.0,                       // wind speed
                4.0,                        // oat
                1000.0,                     // QHN
                true,                       // surface is wet?
                250.0 * 1000.0,             // weight kg
                0,                          // thrust rating
                AntiIceOption.EngAndWing,
                false,                      // packs on
                0);                         // flaps

            var calc = new TOCalculator(perfTable, para);

            double distanceMeter = calc.TakeoffDistanceMeter();

            Assert.AreEqual(ExpectedDistance2(para),
                            distanceMeter, 1E-7);
        }
コード例 #2
0
        public void WhenRwyIsEnoughButUnableToClimbShouldThrowException()
        {
            var para = new TOParameters(
                4000.0,                // rwy length
                1000.0,                // elevation
                210.0,                 // rwy heading
                -1.8,                  // slope
                240.0,                 // wind direction
                10.0,                  // wind speed
                4.0,                   // oat
                1000.0,                // QHN
                false,                 // surface is wet?
                250.0 * 1000.0,        // weight kg
                0,                     // thrust rating
                AntiIceOption.Off,
                true,                  // packs on
                0);                    // flaps

            var    calc = new TOCalculator(perfTable, para);
            double wt   = calc.ClimbLimitWeightTon();

            // Make it heavier than climb limit weight.
            PropertySetter.Set(para, "WeightKg", wt * 1000.0 + 1.0);

            Assert.Throws <PoorClimbPerformanceException>(() =>
                                                          new TOReportGenerator(perfTable, para).TakeOffReport());
        }
コード例 #3
0
        private static double ExpectedClimbLimit1(TOParameters para)
        {
            var    table    = perfTable.Tables[para.FlapsIndex];
            double pressAlt = PressureAltitudeFt(para.RwyElevationFt, para.QNH);

            return(table.ClimbLimitWt.ClimbLimitWeight(pressAlt, para.OatCelsius));
        }
コード例 #4
0
        public void TODistanceDerateTest()
        {
            var para = new TOParameters(
                0.0,
                1000.0,                // elevation
                210.0,                 // rwy heading
                -1.8,                  // slope
                240.0,                 // wind direction
                10.0,                  // wind speed
                4.0,                   // oat
                1000.0,                // QHN
                false,                 // surface is wet?
                250.0 * 1000.0,        // weight kg
                2,                     // thrust rating
                AntiIceOption.Off,
                true,                  // packs on
                0);                    // flaps

            var calc = new TOCalculator(perfTable, para);

            double distanceMeter = calc.TakeoffDistanceMeter();

            Assert.AreEqual(
                ExpectedDistance1(
                    para,
                    perfTable.Tables[para.FlapsIndex]
                    .AlternateThrustTables[para.ThrustRating - 1]
                    .EquivalentFullThrustWeight(
                        para.WeightKg / 1000.0,
                        AlternateThrustTable.TableType.Dry)),
                distanceMeter, 1E-7);
        }
コード例 #5
0
ファイル: Calculator.cs プロジェクト: zylx0532/QSimPlanner
        /// <summary>
        /// Computes the required takeoff distance.
        /// </summary>
        /// <exception cref="Exception"></exception>
        public static double TakeOffDistanceMeter(AirbusPerfTable t, TOParameters p)
        {
            var tables = GetTables(t, p);

            if (tables.Count == 0)
            {
                throw new Exception("No data for selected flaps");
            }
            var pressAlt      = ConversionTools.PressureAltitudeFt(p.RwyElevationFt, p.QNH);
            var inverseTables = tables.Select(x => GetInverseTable(x, pressAlt, t, p));
            var distancesFt   = inverseTables.Select(x =>
                                                     x.ValueAt(p.WeightKg * 0.001 * Constants.KgLbRatio))
                                .ToArray();

            var d = (distancesFt.Length == 1) ?
                    distancesFt[0] :
                    Interpolate1D.Interpolate(
                tables.Select(x => x.IsaOffset).ToArray(),
                distancesFt,
                IsaOffset(p));

            // The slope and wind correction is not exactly correct according to
            // performance xml file comments. However, the table itsel is probably
            // not that precise anyways.
            return(Constants.FtMeterRatio * (d - SlopeAndWindCorrectionFt(d, t, p)));
        }
コード例 #6
0
ファイル: Calculator.cs プロジェクト: zylx0532/QSimPlanner
        // Use the length of first argument instead of the one in Parameters.
        private static double SlopeAndWindCorrectionFt(double lengthFt,
                                                       AirbusPerfTable t, TOParameters p)
        {
            var windCorrectedFt = lengthFt + WindCorrectionFt(lengthFt, t, p);

            return(windCorrectedFt - lengthFt + SlopeCorrectionFt(t, p, windCorrectedFt));
        }
コード例 #7
0
        public void ClimbLimitWtTest()
        {
            var para = new TOParameters(
                2500.0,                // rwy length
                1000.0,                // elevation
                210.0,                 // rwy heading
                -1.8,                  // slope
                240.0,                 // wind direction
                10.0,                  // wind speed
                4.0,                   // oat
                1000.0,                // QHN
                false,                 // surface is wet?
                250.0 * 1000.0,        // weight kg
                2,                     // thrust rating
                AntiIceOption.Off,
                false,                 // packs on
                0);                    // flaps

            var calc = new TOCalculator(perfTable, para);

            double distanceMeter = calc.ClimbLimitWeightTon();

            double wtWithPackCorrection = ExpectedClimbLimit1(para) + 1.7;

            double expectedLimitWt = perfTable.Tables[para.FlapsIndex]
                                     .AlternateThrustTables[para.ThrustRating - 1]
                                     .CorrectedLimitWeight(wtWithPackCorrection, AlternateThrustTable.TableType.Climb);

            Assert.AreEqual(expectedLimitWt, distanceMeter, 1E-7);
        }
コード例 #8
0
ファイル: Calculator.cs プロジェクト: zylx0532/QSimPlanner
        /// <summary>
        /// Error can be None, NoDataForSelectedFlaps, or RunwayTooShort.
        /// </summary>
        /// <exception cref="RunwayTooShortException"></exception>
        /// <exception cref="Exception"></exception>
        public static TOReport TakeOffReport(AirbusPerfTable t, TOParameters p,
                                             double tempIncrement = 1.0)
        {
            var d       = TakeOffDistanceMeter(t, p);
            var primary = new TOReportRow(p.OatCelsius, d, p.RwyLengthMeter - d);

            if (primary.RwyRemainingMeter < 0)
            {
                throw new RunwayTooShortException();
            }

            var    rows   = new List <TOReportRow>();
            double maxOat = 67;

            for (double oat = p.OatCelsius + tempIncrement; oat <= maxOat; oat += tempIncrement)
            {
                try
                {
                    var q = p.CloneWithOat(oat);
                    d = TakeOffDistanceMeter(t, q);
                    var remaining = q.RwyLengthMeter - d;
                    if (remaining < 0)
                    {
                        break;
                    }
                    rows.Add(new TOReportRow(oat, d, remaining));
                }
                catch { }
            }

            return(new TOReport(primary, rows));
        }
コード例 #9
0
ファイル: Calculator.cs プロジェクト: zylx0532/QSimPlanner
 private static double WetCorrection1000LB(double lengthFt,
                                           AirbusPerfTable t, TOParameters p)
 {
     if (!p.SurfaceWet)
     {
         return(0.0);
     }
     return(t.WetCorrectionTable.ValueAt(lengthFt));
 }
コード例 #10
0
ファイル: Calculator.cs プロジェクト: zylx0532/QSimPlanner
        private static double WindCorrectionFt(double lengthFt,
                                               AirbusPerfTable t, TOParameters p)
        {
            var headwind = p.WindSpeedKnots *
                           Math.Cos(ToRadian(p.RwyHeading - p.WindHeading));

            return((headwind >= 0 ?
                    t.HeadwindCorrectionTable.ValueAt(lengthFt) :
                    t.TailwindCorrectionTable.ValueAt(lengthFt)) * headwind);
        }
コード例 #11
0
ファイル: Calculator.cs プロジェクト: zylx0532/QSimPlanner
        private static double SlopeCorrectionFt(AirbusPerfTable t, TOParameters p,
                                                double windCorrectedLengthFt)
        {
            var len = windCorrectedLengthFt;
            var s   = p.RwySlopePercent;

            return((s >= 0 ?
                    t.UphillCorrectionTable.ValueAt(len) :
                    t.DownHillCorrectionTable.ValueAt(len)) * -s);
        }
コード例 #12
0
ファイル: Calculator.cs プロジェクト: zylx0532/QSimPlanner
        // The table is for limit weight. This method constructs a table of
        // takeoff distance. (x: weight 1000 LB, f: runway length ft)
        // Wet runway and bleed air corrections are applied here.
        private static Table1D GetInverseTable(TableDataNode n, double pressAlt,
                                               AirbusPerfTable t, TOParameters p)
        {
            var table  = n.Table;
            var len    = table.y;
            var weight = len.Select(i =>
                                    table.ValueAt(pressAlt, i) - WetAndBleedAirCorrection1000LB(i, t, p));

            return(new Table1D(weight.ToArray(), len.ToArray()));
        }
コード例 #13
0
        private static double ExpectedLimitWt1(TOParameters para)
        {
            var    table    = perfTable.Tables[para.FlapsIndex];
            double pressAlt = PressureAltitudeFt(para.RwyElevationFt, para.QNH);
            double windSpd  = para.WindSpeed *
                              Math.Cos(ToRadian(para.WindHeading - para.RwyHeading));

            double slopeCorrectedLength = table.SlopeCorrDry.CorrectedLength(
                para.RwyLengthMeter, para.RwySlope);

            double windCorrectedLength = table.WindCorrDry.CorrectedLength(
                slopeCorrectedLength, windSpd);

            return(table.WeightTableDry.FieldLimitWeight(
                       pressAlt, windCorrectedLength, para.OatCelsius));
        }
コード例 #14
0
ファイル: Calculator.cs プロジェクト: zylx0532/QSimPlanner
 private static double BleedAirCorrection1000LB(AirbusPerfTable t, TOParameters p)
 {
     if (p.PacksOn)
     {
         return(t.PacksOnCorrection);
     }
     if (p.AntiIce == AntiIceOption.EngAndWing)
     {
         return(t.AllAICorrection);
     }
     if (p.AntiIce == AntiIceOption.Engine)
     {
         return(t.EngineAICorrection);
     }
     return(0.0);
 }
コード例 #15
0
        // Returns whether continue to calculate.
        private bool CheckWeight(TOParameters para)
        {
            if (para.WeightKg > ac.MaxTOWtKg || para.WeightKg < ac.OewKg)
            {
                var result = parentControl.ShowDialog(
                    "Takeoff weight is not within valid range. Continue to calculate?",
                    MsgBoxIcon.Warning,
                    "",
                    DefaultButton.Button2,
                    "Yes", "No");

                return(result == MsgBoxResult.Button1);
            }

            return(true);
        }
コード例 #16
0
        private static double ExpectedDistance1(TOParameters para, double wtTon)
        {
            double headWind = para.WindSpeed *
                              Math.Cos(ToRadian(para.WindHeading - para.RwyHeading));

            double pressAlt = PressureAltitudeFt(para.RwyElevationFt, para.QNH);
            var    table    = perfTable.Tables[para.FlapsIndex];

            double correctedLength = table.WeightTableDry.CorrectedLengthRequired(
                pressAlt, para.OatCelsius, wtTon);

            double slopeCorrectedLength = table.WindCorrDry.SlopeCorrectedLength(
                headWind, correctedLength);

            return(table.SlopeCorrDry.FieldLengthRequired(
                       para.RwySlope, slopeCorrectedLength));
        }
コード例 #17
0
        private static void AssertRwyRemaining(TOReport report,
                                               TOCalculator calc,
                                               TOParameters para)
        {
            var    primary           = report.PrimaryResult;
            double expectedRemaining = para.RwyLengthMeter -
                                       calc.TakeoffDistanceMeter(primary.OatCelsius);

            Assert.AreEqual(expectedRemaining, primary.RwyRemainingMeter, 0.5);

            foreach (var i in report.AssumedTemp)
            {
                expectedRemaining = para.RwyLengthMeter -
                                    calc.TakeoffDistanceMeter(i.OatCelsius);

                Assert.AreEqual(expectedRemaining, i.RwyRemainingMeter, 0.5);
            }
        }
コード例 #18
0
 public static TOParameters CloneWithOat(this TOParameters p, double oatCelcius)
 {
     return(new TOParameters(
                p.RwyLengthMeter,
                p.RwyElevationFt,
                p.RwyHeading,
                p.RwySlopePercent,
                p.WindHeading,
                p.WindSpeedKnots,
                oatCelcius,
                p.QNH,
                p.SurfaceWet,
                p.WeightKg,
                p.ThrustRating,
                p.AntiIce,
                p.PacksOn,
                p.FlapsIndex));
 }
コード例 #19
0
ファイル: TOPerfControl.cs プロジェクト: zylx0532/QSimPlanner
        // Returns whether continue to calculate.
        private bool CheckWeight(TOParameters para)
        {
            var(a, _) = FindTable.Find(tables, aircrafts, regComboBox.Text);
            var ac = a.Config;

            if (para.WeightKg > ac.MaxTOWtKg || para.WeightKg < ac.OewKg)
            {
                var result = this.ShowDialog(
                    "Takeoff weight is not within valid range. Continue to calculate?",
                    MsgBoxIcon.Warning,
                    "",
                    DefaultButton.Button2,
                    "Yes", "No");

                return(result == MsgBoxResult.Button1);
            }

            return(true);
        }
コード例 #20
0
        private static double ExpectedDistance2(TOParameters para)
        {
            double headWind = para.WindSpeedKnots *
                              Math.Cos(ToRadian(para.WindHeading - para.RwyHeading));

            double pressAlt = PressureAltitudeFt(para.RwyElevationFt, para.QNH);
            double wtTon    = (para.WeightKg + 2200.0 - 500.0) / 1000.0;

            var table = perfTable.Tables[para.FlapsIndex];

            double correctedLength = table.WeightTableWet.CorrectedLengthRequired(
                pressAlt, para.OatCelsius, wtTon);

            double slopeCorrectedLength = table.WindCorrWet.SlopeCorrectedLength(
                headWind, correctedLength);

            return(table.SlopeCorrWet.FieldLengthRequired(
                       para.RwySlopePercent, slopeCorrectedLength));
        }
コード例 #21
0
        public void WhenRwyIsTooShortShouldThrowException()
        {
            var para = new TOParameters(
                0.0,                   // rwy length
                1000.0,                // elevation
                210.0,                 // rwy heading
                -1.8,                  // slope
                240.0,                 // wind direction
                10.0,                  // wind speed
                4.0,                   // oat
                1000.0,                // QHN
                false,                 // surface is wet?
                250.0 * 1000.0,        // weight kg
                0,                     // thrust rating
                AntiIceOption.Off,
                true,                  // packs on
                0);                    // flaps

            Assert.Throws <RunwayTooShortException>(() =>
                                                    new TOReportGenerator(perfTable, para).TakeOffReport());
        }
コード例 #22
0
ファイル: Calculator.cs プロジェクト: zylx0532/QSimPlanner
        // Returns best matching tables, returning list can have:
        // 0 element if no matching flaps, or
        // 1 element if only 1 table matches the flaps setting, or
        // 2 elements if more than 1 table match the flaps, these two tables are
        // the ones most suitable for ISA offset interpolation.
        private static List <TableDataNode> GetTables(AirbusPerfTable t, TOParameters p)
        {
            var allFlaps = t.AvailableFlaps().ToList();

            if (p.FlapsIndex >= allFlaps.Count)
            {
                return(new List <TableDataNode>());
            }
            var flaps     = allFlaps.ElementAt(p.FlapsIndex);
            var sameFlaps = t.Tables.Where(x => x.Flaps == flaps).ToList();

            if (sameFlaps.Count == 1)
            {
                return(sameFlaps);
            }
            var ordered    = sameFlaps.OrderBy(x => x.IsaOffset).ToList();
            var isaOffset  = IsaOffset(p);
            var skip       = ordered.Where(x => isaOffset > x.IsaOffset).Count() - 1;
            var actualSkip = Numbers.LimitToRange(skip, 0, ordered.Count - 2);

            return(ordered.Skip(actualSkip).Take(2).ToList());
        }
コード例 #23
0
        public void TakeOffReportTest()
        {
            var para = new TOParameters(
                4000.0,                // rwy length
                1000.0,                // elevation
                210.0,                 // rwy heading
                -1.8,                  // slope
                240.0,                 // wind direction
                10.0,                  // wind speed
                4.0,                   // oat
                1000.0,                // QHN
                false,                 // surface is wet?
                250.0 * 1000.0,        // weight kg
                0,                     // thrust rating
                AntiIceOption.Off,
                true,                  // packs on
                0);                    // flaps

            var report = new TOReportGenerator(perfTable, para).TakeOffReport();
            var calc   = new TOCalculator(perfTable, para);

            AssertReport(report, calc, para);
        }
コード例 #24
0
        private static void AssertReport(TOReport report,
                                         TOCalculator calc,
                                         TOParameters para)
        {
            // Rwy remaining
            AssertRwyRemaining(report, calc, para);

            // Primary result.
            var primary = report.PrimaryResult;

            Assert.AreEqual(para.OatCelsius, primary.OatCelsius, 0.5);

            double expectedDis = calc.TakeoffDistanceMeter(primary.OatCelsius);

            Assert.AreEqual(expectedDis, primary.RwyRequiredMeter, 0.5);

            // Assumed temperatures
            foreach (var i in report.AssumedTemp)
            {
                expectedDis = calc.TakeoffDistanceMeter(i.OatCelsius);
                Assert.AreEqual(expectedDis, i.RwyRequiredMeter, 0.5);
            }
        }
コード例 #25
0
ファイル: Calculator.cs プロジェクト: zylx0532/QSimPlanner
 private static double WetAndBleedAirCorrection1000LB(double lengthFt,
                                                      AirbusPerfTable t, TOParameters p) =>
 WetCorrection1000LB(lengthFt, t, p) + BleedAirCorrection1000LB(t, p);
コード例 #26
0
 public TOReport GetReport(TOParameters p, double tempIncrementCelsius)
 {
     return(Calculator.TakeOffReport(PerfTable, p, tempIncrementCelsius));
 }
コード例 #27
0
ファイル: Calculator.cs プロジェクト: zylx0532/QSimPlanner
 private static double IsaOffset(TOParameters p) =>
 p.OatCelsius - ConversionTools.IsaTemp(p.RwyElevationFt);
コード例 #28
0
 private static double ExpectedDistance1(TOParameters para)
 {
     return(ExpectedDistance1(para, para.WeightKg / 1000.0));
 }
コード例 #29
0
 public TOReport GetReport(TOParameters p, double tempIncrementCelsius)
 {
     return(new TOReportGenerator(PerfTable, p).TakeOffReport(tempIncrementCelsius));
 }