Beispiel #1
0
        def iteration(pitch: float):
            def thrust_direction(axis: int, force: float, pr: Projectile):
                if pr.time < 1.2:
                    return spherical_to_planar_coord(axis, force,
                                                     math.radians(pitch), 0)
                if (pr.position.alt > 100000
                        or pr.velocities[Z_INDEX] > 4000) and pr.pitch > 0.2:
                    spherical_to_planar_coord(axis, force, pr.pitch - 0.15,
                                              pr.yaw)
                if pr.pitch < 0.1:
                    spherical_to_planar_coord(axis, force, pr.pitch + 0.12,
                                              pr.yaw)
                return follow_path(axis, force, pr)

            env = Environment(surface_altitude=lambda p: 80)
            thrust = ThrustForce(5000, fuel_flow, 150, 250000, 15,
                                 thrust_direction)
            launcher = Launcher(math.radians(pitch),
                                0,
                                f"{csvdir}{pitch}.csv",
                                f"{kmldir}{pitch}",
                                f"{frcdir}{pitch}.csv",
                                environment=env,
                                thrust=thrust)
            launcher.launch(10000,
                            Position(math.radians(45), math.radians(45), 80))
            stopwatch.lap()
Beispiel #2
0
        def iteration(yaw: int):
            def thrust_direction(axis: int, force: float, pr: Projectile):
                if pr.time < 1.2:
                    return spherical_to_planar_coord(axis, force, math.pi / 4,
                                                     math.radians(yaw))
                if (pr.position.alt > 100000
                        or pr.velocities[Z_INDEX] > 4000) and pr.pitch > 0.2:
                    spherical_to_planar_coord(axis, force, pr.pitch - 0.15,
                                              pr.yaw)
                if pr.pitch < 0.15:
                    spherical_to_planar_coord(axis, force, pr.pitch + 0.17,
                                              pr.yaw)
                return follow_path(axis, force, pr)

            env = Environment(surface_altitude=lambda p: 80)
            thrust = ThrustForce(5000, fuel_flow, 150, 250000, 15,
                                 thrust_direction)
            launcher = Launcher(math.pi / 4,
                                math.radians(yaw),
                                f"{csvdir}{yaw}.csv",
                                f"{kmldir}{yaw}",
                                f"{frcdir}{yaw}.csv",
                                environment=env,
                                thrust=thrust)
            launcher.launch(10000,
                            Position(math.radians(0), math.radians(15), 80))
            # compress("%s%d.csv" % (csvdir, yaw), "%s%d.bz2" % (csvdir, yaw), name_inside_zip="%d.csv" % yaw,
            #         keep_original=False)
            # compress("%s%d.csv" % (frcdir, yaw), "%s%d.bz2" % (frcdir, yaw), name_inside_zip="%d.csv" % yaw,
            #         keep_original=False)
            stopwatch.lap()
Beispiel #3
0
 def __init__(self,
              environment: Environment,
              mass: float,
              initial_velocities: List[float],
              initial_position: Position,
              cross_section=lambda axis, pitch, yaw: 0.25,
              drag_coef=lambda axis, pitch, yaw: 0.1,
              vy_corrective_change_threshold=0.1,
              distance_rolling_window=40,
              forces_writer: ForcesCsvWriter = None):
     if initial_position is None:
         initial_position = Position(44.869389, 20.640221, 0)
     self.initial_mass = mass
     self.velocities = np.array(initial_velocities, "float64")
     self.position = initial_position
     self.cross_section = cross_section
     self.drag_coef = drag_coef
     self.environment = environment
     self.vy_corrective_change_threshold = vy_corrective_change_threshold
     self.forces_writer = forces_writer
     self.crossed_the_pole = False
     self.directions = np.zeros(3)
     self.time = 0
     self.lost_mass = 0
     self.distance_travelled = 0
     self.total_velocity = 0
     self.planar_velocity = 0
     self.pitch = 0
     self.yaw = 0
     self.dt = 0
     self.thrust = []
     self.distance_stats = RollingStatistic(distance_rolling_window)
Beispiel #4
0
 def iteration(latitude: float):
     env = Environment(surface_altitude=lambda p: 80)
     thrust = ThrustForce(5000, fuel_flow, 150, 250000, 15,
                          thrust_direction)
     launcher = Launcher(math.pi / 4,
                         0,
                         f"{csvdir}{latitude}.csv",
                         f"{kmldir}{latitude}",
                         f"{frcdir}{latitude}.csv",
                         environment=env,
                         thrust=thrust)
     launcher.launch(
         10000, Position(math.radians(latitude), math.radians(45), 80))
     stopwatch.lap()
Beispiel #5
0
    def pole_crossing() -> None:
        """
        Start really north. Cross the pole and carry on.
        :return: nothing
        """
        print(f"Running {scenario}")

        def fuel_flow(t: float):
            if t < 1:
                return 600
            if t < 3:
                return 400
            return 100

        def thrust_direction(axis: int, force: float, pr: Projectile):
            if pr.time < 1.2:
                return spherical_to_planar_coord(axis, force, math.pi / 4,
                                                 math.pi / 2)
            if (pr.position.alt > 100000
                    or pr.velocities[Z_INDEX] > 3500) and pr.pitch > 0.2:
                spherical_to_planar_coord(axis, force, pr.pitch - 0.12, pr.yaw)
            if pr.pitch < 0.15:
                spherical_to_planar_coord(axis, force, pr.pitch + 0.17, pr.yaw)
            return follow_path(axis, force, pr)

        if os.path.exists("scenario_data/pole_crossing/"):
            shutil.rmtree("scenario_data/pole_crossing/")
        csvdir, kmldir, frcdir, stopwatch = init_scenario("pole_crossing")
        stopwatch.start()

        env = Environment(surface_altitude=lambda p: 80)
        env.remove_force(CoriolisForce())
        thrust = ThrustForce(4000, fuel_flow, 150, 200000, 12,
                             thrust_direction)
        launcher = Launcher(math.pi / 4,
                            math.pi / 2,
                            f"{csvdir}test.csv",
                            f"{kmldir}test",
                            f"{frcdir}test.csv",
                            environment=env,
                            thrust=thrust,
                            dt=0.1)
        launcher.launch(8000, Position(math.radians(84), math.radians(-15),
                                       80))
        stopwatch.stop()
        env.plot_all_forces(f"{frcdir}test.csv")
Beispiel #6
0
    def test() -> None:
        """
        Test scenario. Default for fiddling around.
        :return: nothing
        """
        print(f"Running {scenario}")

        def fuel_flow(t: float):
            if t < 1:
                return 600
            if t < 3:
                return 300
            return 100

        def thrust_direction(axis: int, force: float, pr: Projectile):
            if pr.time < 1.2:
                return spherical_to_planar_coord(axis, force, 0.9, 0)
            if (pr.position.alt > 100000
                    or pr.velocities[Z_INDEX] > 3500) and pr.pitch > 0.2:
                spherical_to_planar_coord(axis, force, pr.pitch - 0.12, pr.yaw)
            if pr.pitch < 0.15:
                spherical_to_planar_coord(axis, force, pr.pitch + 0.17, pr.yaw)
            return follow_path(axis, force, pr)

        if os.path.exists("scenario_data/test/"):
            shutil.rmtree("scenario_data/test/")
        csvdir, kmldir, frcdir, stopwatch = init_scenario("test")
        stopwatch.start()

        env = Environment(surface_altitude=lambda p: 80)
        thrust = ThrustForce(3500, fuel_flow, 150, 200000, 12,
                             thrust_direction)
        launcher = Launcher(0.9,
                            0,
                            f"{csvdir}test.csv",
                            f"{kmldir}test",
                            f"{frcdir}test.csv",
                            environment=env,
                            thrust=thrust)
        launcher.launch(8000, Position(math.radians(60), math.radians(45), 80))
        stopwatch.stop()
        env.plot_all_forces(f"{frcdir}test.csv")
Beispiel #7
0
    def long_distance() -> None:
        print(f"Running {scenario}")

        def thrust_direction(axis: int, force: float, pr: Projectile):
            if pr.time < 1:
                return spherical_to_planar_coord(axis, force, math.pi / 4,
                                                 math.pi)
            if (pr.position.alt > 100000
                    or pr.velocities[Z_INDEX] > 3500) and pr.pitch > 0.2:
                spherical_to_planar_coord(axis, force, pr.pitch - 0.2, pr.yaw)
            if pr.pitch < 0.15:
                spherical_to_planar_coord(axis, force, pr.pitch + 0.1, pr.yaw)
            return follow_path(axis, force, pr)

        if os.path.exists("scenario_data/long_distance/"):
            shutil.rmtree("scenario_data/long_distance/")
        csvdir, kmldir, frcdir, stopwatch = init_scenario("long_distance")
        stopwatch.start()

        env = Environment(surface_altitude=lambda p: 80)
        thrust = [
            ThrustForce(4000, lambda t: 120, 150, 200000, 12,
                        thrust_direction),
            ThrustForce(1800, lambda t: 150, 150, 200000, 13,
                        thrust_direction),
            ThrustForce(1200, lambda t: 200, 200, 300000, 15,
                        thrust_direction),
            ThrustForce(1200, lambda t: 200, 200, 300000, 15, thrust_direction)
        ]
        launcher = Launcher(math.pi / 4,
                            math.pi,
                            f"{csvdir}data.csv",
                            f"{kmldir}data",
                            f"{frcdir}data.csv",
                            environment=env,
                            thrust=thrust)
        launcher.launch(10000, Position(math.radians(10), math.radians(-10),
                                        80))
        stopwatch.stop()
        env.plot_all_forces(f"{frcdir}data.csv")
Beispiel #8
0
    def update_velocities(self, old_lat: np.float128, old_lon: np.float128,
                          radius: float, distance_m: float) -> None:
        """
        Update velocities: take a look at the old position, current position, how much it has changed and calculate the
        speed based on that. Effectively moves the local tangent plane. z-speed is not modified as it's unaffected by
        moving of the tangent plane.
        :param old_lat: previous latitude
        :param old_lon: previous longitude
        :param radius: earth radius + altitude
        :param distance_m: distance travelled (could be calculated inside the function, but no need atm)
        :return: nothing; updates the projectile's state
        """
        old_vy = self.velocities[Y_INDEX]
        self.velocities[Y_INDEX] = (radius * (self.position.lat - old_lat)
                                    ) / self.dt  # usual case for correcting Vy
        # our first and largest problem is detecting whether we've crossed the pole. I don't know a nice way for this,
        # so we use the ugly way: statistics and prayers.
        # ideally, change_radio should be 0 (meaning Vy won't be corrected)
        if old_vy != 0:
            change_ratio = fabs(self.velocities[Y_INDEX] / old_vy - 1)
        else:
            change_ratio = fabs(self.velocities[Y_INDEX])
        if change_ratio > self.vy_corrective_change_threshold:  # oops, we've modified Vy too much
            actual_distance = haversine(self.position,
                                        Position(old_lat, old_lon, 0), radius)
            if self.crossed_the_pole:  # if we've crossed the pole recently, we definitely don't want to do it again
                print(
                    f"Warning! V_y has too extreme oscillations: {change_ratio}"
                )
            elif actual_distance < self.distance_stats.mean and self.distance_stats.is_outlier(
                    actual_distance):
                # if we've travelled significantly less than usual (i.e. in y direction), assume we've crossed the pole
                # conceptually simple, practically not-really-definable, but surprisingly effective
                print(f"Crossing the pole: change ratio is {change_ratio}f")
                # so now that we've crossed the pole, we want to reverse Vx and Vy and change longitude so we continue
                # flying 'straight'. We're basically throwing away this iteration and using the data from the previous.
                self.crossed_the_pole = True  # this will prevent crossing the pole again if we're still too close
                self.position.lon = divmod((old_lon + pi),
                                           (2 * pi))[1] - 2 * pi
                self.yaw = self.yaw - pi % (sgn(self.yaw - pi) * 2 * pi)
                self.velocities[X_INDEX] = spherical_to_planar_coord(
                    X_INDEX, self.total_velocity, self.pitch, self.yaw)
                self.velocities[Y_INDEX] = spherical_to_planar_coord(
                    Y_INDEX, self.total_velocity, self.pitch, self.yaw)
                return  # don't update X velocity!
            elif actual_distance < self.distance_stats.mean:
                # Vy changed a lot, but we're far away from the pole; can happen in e.g. polar circle even if we're not
                # flying over the pole itself.
                print(
                    f"Warning: Vy has extreme correction, but we're far from poles: {change_ratio}"
                )
        if self.crossed_the_pole:
            self.crossed_the_pole = False
            self.velocities[
                Y_INDEX] = old_vy  # don't correct speed if we've just skipped the pole
            return

        self.distance_stats.update(
            distance_m)  # we need to keep track of what's the 'usual' movement
        # from now on, we take care of updating Vx
        lon_radius = radius * cos(self.position.lat)
        if lon_radius == 0:
            # not much we can do if we're exactly at the pole, just use the last good number, it'll be close enough
            lon_radius = radius * cos(old_lat)
        if fabs(self.position.lon -
                old_lon) < pi:  # usual case for correcting Vx
            self.velocities[X_INDEX] = (
                lon_radius * (self.position.lon - old_lon)) / self.dt
        else:  # crossing the antimeridian: we haven't really moved for 2pi, so substract (or add) that
            self.velocities[X_INDEX] = (
                lon_radius *
                (self.position.lon - old_lon +
                 2 * pi * sgn(old_lon - self.position.lon))) / self.dt