Пример #1
0
        private void RunSimulation(int maxSteps = 10000)
        {
            SimulationSteps.Clear();
            OutputByStage.Clear();
            Output      = new OutputParams();
            OutputOrbit = new OrbitOutput();

            SimulationStep prev    = null;
            SimulationStep current = CreateFirstStep();

            SimulationSteps.Add(current);

            for (int i = 0; i < maxSteps; i++)
            {
                WriteToLog(current.GetLogMessage());
                prev    = current;
                current = RunStep(prev);
                var output = CheckOutput(prev, current);
                if (current.Stage > Launcher.Stages.Count)
                {
                    Output = output;
                    break;
                }

                SimulationSteps.Add(current);
            }

            CalculateOutputOrbit();
            if (PitchProgram.Tmax != Output.T)
            {
                PitchProgram.Tmax = Output.T;
                RunSimulation(maxSteps);
                return;
            }

            OutputByStage.ForEach(os => WriteToLog(os.GetLogMessage()));
            WriteToLog(Output.GetLogMessage());
            WriteToLog(OutputOrbit.GetLogMessage());
        }
Пример #2
0
        private OutputParams CheckOutput(SimulationStep prev, SimulationStep current)
        {
            if (prev == null || prev.Stage == current.Stage)
            {
                return(null);
            }

            var stageOutput = new OutputParams();

            stageOutput.T     = current.T;
            stageOutput.Index = current.Index;
            stageOutput.CV    = current.CV;

            // ?
            stageOutput.Stage = prev.Stage;

            OutputParams prevStageOutput = null;

            if (prev.Stage > 1)
            {
                prevStageOutput     = OutputByStage[prev.StageIndex - 1];
                stageOutput.CVdelta = stageOutput.CV - prevStageOutput.CV;
            }

            stageOutput.V     = current.Velocity.V;
            stageOutput.Vx    = current.Velocity.Vxabs;
            stageOutput.Vy    = current.Velocity.Vy;
            stageOutput.H     = current.Coordinates.Altitude / 1000.0;
            stageOutput.MassT = current.M / 1000.0;
            stageOutput.Pitch = current.Pitch.Thrust;

            OutputByStage.Add(stageOutput);

            // TODO : Stage, CVreserve?

            return(stageOutput);
        }
Пример #3
0
        private SimulationStep RunStep(SimulationStep prev)
        {
            var step = new SimulationStep();

            step.Index = prev.Index + 1;;

            // =B5+Main!$P$11
            step.T = prev.T + DeltaT;

            // =IF(AZ5+AZ6>0;1;IF(BA5+BA6>0;2;IF(BB5+BB6>0;3;IF(BC5+BC6>0;4;FALSE))))
            step.Stage = prev.FuelMass[prev.StageIndex] > 0 ? prev.Stage : prev.Stage + 1;

            // =I5+N5*Main!$P$11
            step.Coordinates.Altitude = prev.Coordinates.Altitude + prev.Velocity.Vy * DeltaT;

            // = J5 + L5 * Main!$P$11
            step.Coordinates.Distance = prev.Coordinates.Distance + prev.Velocity.Vx * DeltaT;

            // =L5+(V5-Z5)*Main!$P$11
            step.Velocity.Vx = prev.Velocity.Vx + (prev.Acceleration.Ax - prev.Acceleration.Acoriol) * DeltaT;

            // =L6+Main!$M$19
            step.Velocity.Vxabs = step.Velocity.Vx + Spaceport.GetEarthRotationVelocity(Constants.EarthRadius);

            // =N5+(W5+Y5-X5)*Main!$P$11
            step.Velocity.Vy = prev.Velocity.Vy + (prev.Acceleration.Ay + prev.Acceleration.Acentr - prev.Acceleration.G) * DeltaT;

            step.DryMass =
                (from s in Launcher.Stages where s.Number >= step.Stage select s.EmptyMass).Sum() +
                (step.T <= Launcher.FairingJettision ? Launcher.FairingMass : 0.0) +
                Launcher.Payload;

            // =MAX(AZ5-Main!E$15*AO5*Main!$P$11;0)
            step.FuelMass = Launcher.Stages.Select(s => Math.Max(prev.FuelMass[s.Index] - s.FuelConsumption * prev.Throttle[s.Index] * DeltaT, 0.0)).ToArray();

            // =SUM(AY6:BC6)
            step.M = step.DryMass + step.FuelMass.Sum();

            step.Atmosphere.Tc = GetTemperature(step.Coordinates.Altitude);
            step.Atmosphere.Ro = GetDensity(step.Coordinates.Altitude);

            step.Throttle = Launcher.Stages.Select(s => s.GetThrottle(step.Stage, step.T)).ToArray();

            step.ThrustKgf = Launcher.Stages.Select(s =>
                                                    s.FuelConsumption *
                                                    step.Throttle[s.Index] *
                                                    (s.IspVac - (s.IspVac - s.IspAtm) * step.Atmosphere.Ro) *
                                                    Math.Min(step.FuelMass[s.Index], s.FuelConsumption * DeltaT) /
                                                    Math.Max(s.FuelConsumption * DeltaT, 1.0)).ToArray();

            step.ThrustN = Constants.GravityOfEarthStandard * step.ThrustKgf.Sum();

            // =IF(AND(E5=E8;E8>0);(R6/Q6+R5/Q5)/2;R5/Q5)
            // TODO: step.A
            step.A = step.ThrustN / step.M;

            // =T5+Main!$P$11*S5
            step.CV = prev.CV + DeltaT * prev.A;

            step.Acceleration.G       = Constants.GravityOfEarthPolar * Math.Pow(1000.0 * Constants.EarthRadius / (1000.0 * Constants.EarthRadius + step.Coordinates.Altitude), 2.0);
            step.Acceleration.Acentr  = step.Velocity.Vxabs * step.Velocity.Vxabs / (1000.0 * Constants.EarthRadius + step.Coordinates.Altitude);
            step.Acceleration.Acoriol = step.Velocity.Vy * step.Velocity.Vxabs / (1000.0 * Constants.EarthRadius + step.Coordinates.Altitude);

            var currentStage = step.StageIndex < Launcher.Stages.Count ? Launcher.Stages[step.StageIndex] : null;

            step.Aerodynamics.Cx = currentStage?.Cx ?? 0.0;
            step.Aerodynamics.Cy = currentStage?.Cy ?? 0.0;

            // =0,5*Main!Q$9*AC6*O6*O6
            step.Aerodynamics.Q = 0.5 * Constants.AirDensity * step.Atmosphere.Ro * step.Velocity.V * step.Velocity.V;

            step.Control.T = step.T;

            step.Control.ControlInterval.Value1 = 1;

            // =MAX(0; (B5-OFFSET(Main!D$32;0;O5))/(OFFSET(Main!D$32;0;O5+1)-OFFSET(Main!D$32;0;O5)))
            step.Control.ControlInterval.Value2 = Math.Max(0, (step.T - PitchProgram.T0) / (PitchProgram.Tmax - PitchProgram.T0));

            // =180/PI()*ATAN(TAN(PI()/180*OFFSET(Main!$D$34;0;O5))*(1-P5)+TAN(PI()/180*OFFSET(Main!$D$34;0;O5+1))*P5)
            step.Control.ControlLinearTheta = 180.0 / Math.PI * Math.Atan(
                Math.Tan(Math.PI / 180.0 * PitchProgram.Theta0) * (1.0 - step.Control.ControlInterval.Value2) +
                Math.Tan(Math.PI / 180.0 * PitchProgram.ThetaMax) * step.Control.ControlInterval.Value2);

            // = IF(Main!B$41 = "+"; AU5; IF(Main!B$38 = "+"; AO5; IF(Main!B$35 = "+"; Y5; R5)))
            step.Control.ThetaOpt = step.Control.ControlLinearTheta;

            // =IF(Main!$B$38="+";AQ5;E5)
            step.Control.ChiOpt = step.Control.ThetaOpt;

            // =IF(Main!$B$51="+";MIN(90;180/PI()*Main!E$51/Simulation!AF6);90)
            step.Control.QAlpha.AlphaMax = Restrictions.QAlpha != null?Math.Min(90.0, 180.0 / Math.PI *Restrictions.QAlpha.Value / step.Aerodynamics.Q) : 90.0;

            // =180/PI()*ATAN2(Simulation!L6;Simulation!N6)
            step.Control.QAlpha.Nu = 180.0 / Math.PI * Math.Atan2(step.Velocity.Vy, step.Velocity.Vx);

            // = IF(AND(Main!$B$47 = "+"; Main!$B$48 = "+"; B6 < Main!$E$48); Main!$E$47; MAX(-90; M6 - L6))
            step.Control.ThetaMin = Restrictions.LaunchPosition != null && Restrictions.ClearingTower != null && step.T < Restrictions.ClearingTower.Value ?
                                    Restrictions.LaunchPosition.Value : Math.Max(-90.0, step.Control.QAlpha.Nu - step.Control.QAlpha.AlphaMax);

            // =IF(AND(Main!$B$47="+";Main!$B$48="+";B6<Main!$E$48);Main!$E$47;MIN(90;M6+L6))
            step.Control.ThetaMax = Restrictions.LaunchPosition != null && Restrictions.ClearingTower != null && step.T < Restrictions.ClearingTower.Value ?
                                    Restrictions.LaunchPosition.Value : Math.Min(90.0, step.Control.QAlpha.Nu + step.Control.QAlpha.AlphaMax);

            // =IF(Main!$B$49="+";Main!$P$11*Main!$E$49;90)
            var maxTheta = Restrictions.MaxTurn != null ? DeltaT * Restrictions.MaxTurn.Value : 90.0;

            // =MIN(I5+I$3;MAX(I5-I$3;MIN(H6;MAX(G6;E6))))
            step.Control.Theta = Math.Min(
                prev.Control.Theta + maxTheta,
                Math.Max(prev.Control.Theta - maxTheta, Math.Min(step.Control.ThetaMax, Math.Max(step.Control.ThetaMin, step.Control.ThetaOpt))));

            // =MIN(J5+I$3;MAX(J5-I$3;MIN(H6;MAX(G6;F6))))
            step.Control.Chi = Math.Min(
                prev.Control.Chi + maxTheta,
                Math.Max(prev.Control.Chi - maxTheta, Math.Min(step.Control.ThetaMax, Math.Max(step.Control.ThetaMin, step.Control.ThetaOpt))));

            // =IF(E5;Control!I5;0)
            step.Pitch.Thrust = step.Control.Theta;

            // =IF(E5;Control!J5;0)
            step.Pitch.AD = step.Control.Chi;

            // =G6-ATAN2(L6; N6)/PI()*180
            step.Aerodynamics.AOA = step.Pitch.AD - Math.Atan2(step.Velocity.Vy, step.Velocity.Vx) / Math.PI * 180.0;

            // =AF6*AH6*OFFSET(Main!D$24;0;E6)*SIN(AE6/180*PI())
            step.Aerodynamics.Rl = step.Aerodynamics.Q * step.Aerodynamics.Cy * (currentStage?.Sy ?? 0.0) * Math.Sin(step.Aerodynamics.AOA / 180.0 * Math.PI);

            // =AF6*AG6*OFFSET(Main!D$23;0;E6)*COS(AE6/180*PI())
            step.Aerodynamics.Rd = step.Aerodynamics.Q * step.Aerodynamics.Cx * (currentStage?.Sx ?? 0.0) * Math.Cos(step.Aerodynamics.AOA / 180.0 * Math.PI);

            // =-AI5*COS(G5*PI()/180)-AJ5*SIN(G5*PI()/180)
            step.Aerodynamics.Rx = -step.Aerodynamics.Rd * Math.Cos(step.Pitch.AD * Math.PI / 180.0) - step.Aerodynamics.Rl * Math.Sin(step.Pitch.AD * Math.PI / 180.0);

            // -AI5*SIN(G5*PI()/180)+AJ5*COS(G5*PI()/180)
            step.Aerodynamics.Ry = -step.Aerodynamics.Rd * Math.Sin(step.Pitch.AD * Math.PI / 180.0) + step.Aerodynamics.Rl * Math.Cos(step.Pitch.AD * Math.PI / 180.0);

            // =S5*COS(F5*PI()/180)+AK5/Q5
            step.Acceleration.Ax = step.A * Math.Cos(step.Pitch.Thrust * Math.PI / 180.0) + step.Aerodynamics.Rx / step.M;

            // =S5*SIN(F5*PI()/180)+AL5/Q5
            step.Acceleration.Ay = step.A * Math.Sin(step.Pitch.Thrust * Math.PI / 180.0) + step.Aerodynamics.Ry / step.M;

            return(step);
        }
Пример #4
0
        private SimulationStep CreateFirstStep()
        {
            var step = new SimulationStep()
            {
                Index = 0,
                T     = 0,
                Stage = 1
            };

            step.Coordinates.Altitude = Spaceport.Altitude;
            step.Coordinates.Distance = 0.0;
            step.Velocity.Vx          = Spaceport.Velocity * Math.Cos(Math.PI / 180.0 * Spaceport.Angle);
            step.Velocity.Vxabs       = step.Velocity.Vx + Spaceport.GetEarthRotationVelocity(Constants.EarthRadius);
            step.Velocity.Vy          = Spaceport.Velocity * Math.Sin(Math.PI / 180.0 * Spaceport.Angle);
            step.DryMass  = Launcher.Stages.Sum(s => s.EmptyMass) + Launcher.FairingMass + Launcher.Payload;
            step.FuelMass = Launcher.Stages.Select(s => s.FullMass - s.EmptyMass).ToArray();
            step.M        = step.DryMass + step.FuelMass.Sum();

            step.Atmosphere.Tc = GetTemperature(step.Coordinates.Altitude);
            step.Atmosphere.Ro = GetDensity(step.Coordinates.Altitude);

            step.Throttle = Launcher.Stages.Select(s => s.GetThrottle(step.Stage, step.T)).ToArray();

            step.ThrustKgf = Launcher.Stages.Select(s =>
                                                    s.FuelConsumption *
                                                    step.Throttle[s.Index] *
                                                    (s.IspVac - (s.IspVac - s.IspAtm) * step.Atmosphere.Ro) *
                                                    Math.Min(step.FuelMass[s.Index], s.FuelConsumption * DeltaT) /
                                                    Math.Max(s.FuelConsumption * DeltaT, 1.0)).ToArray();

            step.ThrustN = Constants.GravityOfEarthStandard * step.ThrustKgf.Sum();

            // =IF(AND(E5=E8;E8>0);(R6/Q6+R5/Q5)/2;R5/Q5)
            // TODO: step.A
            step.A = step.ThrustN / step.M;

            step.CV = 0.0;

            step.Acceleration.G       = Constants.GravityOfEarthPolar * Math.Pow(1000.0 * Constants.EarthRadius / (1000.0 * Constants.EarthRadius + step.Coordinates.Altitude), 2.0);
            step.Acceleration.Acentr  = step.Velocity.Vxabs * step.Velocity.Vxabs / (1000.0 * Constants.EarthRadius + step.Coordinates.Altitude);
            step.Acceleration.Acoriol = step.Velocity.Vy * step.Velocity.Vxabs / (1000.0 * Constants.EarthRadius + step.Coordinates.Altitude);

            step.Aerodynamics.AOA = 0.0;
            step.Aerodynamics.Q   = 0.5 * Constants.AirDensity * step.Atmosphere.Ro * step.Velocity.V * step.Velocity.V;

            var firstStage = Launcher.Stages.First();

            step.Aerodynamics.Cx = firstStage.Cx;
            step.Aerodynamics.Cy = firstStage.Cy;
            step.Aerodynamics.Rl = step.Aerodynamics.Q * step.Aerodynamics.Cy * firstStage.Sy * Math.Sin(step.Aerodynamics.AOA / 180.0 * Math.PI);

            step.Control.T = 0;

            step.Control.ControlInterval.Value1 = 1;

            // =MAX(0; (B5-OFFSET(Main!D$32;0;O5))/(OFFSET(Main!D$32;0;O5+1)-OFFSET(Main!D$32;0;O5)))
            step.Control.ControlInterval.Value2 = Math.Max(0, (step.T - PitchProgram.T0) / (PitchProgram.Tmax - PitchProgram.T0));

            // =180/PI()*ATAN(TAN(PI()/180*OFFSET(Main!$D$34;0;O5))*(1-P5)+TAN(PI()/180*OFFSET(Main!$D$34;0;O5+1))*P5)
            step.Control.ControlLinearTheta = 180.0 / Math.PI * Math.Atan(
                Math.Tan(Math.PI / 180.0 * PitchProgram.Theta0) * (1.0 - step.Control.ControlInterval.Value2) +
                Math.Tan(Math.PI / 180.0 * PitchProgram.ThetaMax) * step.Control.ControlInterval.Value2);

            // = IF(Main!B$41 = "+"; AU5; IF(Main!B$38 = "+"; AO5; IF(Main!B$35 = "+"; Y5; R5)))
            step.Control.ThetaOpt = step.Control.ControlLinearTheta;

            // =IF(Main!$B$38="+";AQ5;E5)
            step.Control.ChiOpt = step.Control.ThetaOpt;

            step.Control.QAlpha.AlphaMax = 90.0;
            step.Control.QAlpha.Nu       = 90.0;

            // =IF(AND(Main!$B$47="+");Main!$E$47;MAX(-90;M5-L5))
            step.Control.ThetaMin = Restrictions.LaunchPosition != null ? Restrictions.LaunchPosition.Value : Math.Max(-90.0, step.Control.QAlpha.Nu - step.Control.QAlpha.AlphaMax);

            // =IF(AND(Main!$B$47="+");Main!$E$47;MIN(90;M5+L5))
            step.Control.ThetaMax = Restrictions.LaunchPosition != null ? Restrictions.LaunchPosition.Value : Math.Max(-90.0, step.Control.QAlpha.Nu + step.Control.QAlpha.AlphaMax);

            step.Control.Theta = Math.Max(step.Control.ThetaMax, Math.Min(step.Control.ThetaMin, step.Control.ThetaOpt));
            step.Control.Chi   = Math.Max(step.Control.ThetaMax, Math.Min(step.Control.ThetaMin, step.Control.ChiOpt));

            // =IF(E5;Control!I5;0)
            step.Pitch.Thrust = step.Control.Theta;

            // =IF(E5;Control!J5;0)
            step.Pitch.AD = step.Control.Chi;

            // =S5*COS(F5*PI()/180)+AK5/Q5
            step.Acceleration.Ax = step.A * Math.Cos(step.Pitch.Thrust * Math.PI / 180.0) + step.Aerodynamics.Rx / step.M;

            // =S5*SIN(F5*PI()/180)+AL5/Q5
            step.Acceleration.Ay = step.A * Math.Sin(step.Pitch.Thrust * Math.PI / 180.0) + step.Aerodynamics.Ry / step.M;

            // TODO : first step Rd
            // =AF5*AG5*Control!AF5*COS(AE5/180*PI())
            // step.Aerodynamics.Rd = 0.0;

            // =-AI5*COS(G5*PI()/180)-AJ5*SIN(G5*PI()/180)
            step.Aerodynamics.Rx = -step.Aerodynamics.Rd * Math.Cos(step.Pitch.AD * Math.PI / 180.0) - step.Aerodynamics.Rl * Math.Sin(step.Pitch.AD * Math.PI / 180.0);

            // -AI5*SIN(G5*PI()/180)+AJ5*COS(G5*PI()/180)
            step.Aerodynamics.Ry = -step.Aerodynamics.Rd * Math.Sin(step.Pitch.AD * Math.PI / 180.0) + step.Aerodynamics.Rl * Math.Cos(step.Pitch.AD * Math.PI / 180.0);

            return(step);
        }