{
"hash": "d6a1c683f62906efe534b69ddf3408bf",
"result": {
"engine": "jupyter",
"markdown": "---\ntitle: \"ISS Eclipse Determination\"\ndescription: |\n Calculate sunlight exposure for orbiting spacecraft like the ISS. This Julia project demonstrates how to determine eclipse times, considering umbra, penumbra, and full sunlight. Visualizations and code included. Learn about orbital mechanics and mission design considerations.\ndate: 2021-05-01\ndate-modified: 2024-02-292\ncategories:\n - Julia\n - Astrodynamics\n - Code\n - Aerospace\n - Notes\n - Space\n - Math\ncreative_commons: CC BY\nimage: preview.png\nimage-alt: A diagram illustrating the umbra and penumbra regions cast by a celestial body. A circular body is shown with light rays from a spacecraft creating a conical shadow region labeled \"Umbra\". The lighter, partially shaded regions surrounding the umbra are labeled \"Penumbra\".\nformat:\n html:\n code-tools: true\n code-fold: false\njupyter: julia-1.10\nfreeze: auto\n---\n\n\nDetermining the eclipses a satellite will encounter is a major driving factor when designing a mission in space. Thermal and power budgets have to be made with the fact that a satellite will periodically be in the complete darkness of space where it will receive no solar radiation to power the solar panels and keep the spacecraft from freezing.\n\n## What is an Eclipse\n\n{fig-alt=\"A diagram of an eclipse. The sun is shown as a large yellow circle on the left. A smaller blue circle labeled \"Body\" is to the right of the sun. A spacecraft is shown above the body. The umbra and penumbra are labeled.\"}\n\nThe above image is a simple representation of what an eclipse is. First, you'll notice the Umbra is complete darkness, then the Penumbra, which is a shadow of varying darkness, and then the rest of the orbit is in full sunlight. For this example, I will be using the ISS, which has a very low orbit, so the Penumbra isn't much of a problem. However, you can tell by looking at the diagram that higher altitude orbits would spend more time in the Penumbra. \n\n{fig-alt=\"A diagram expanding on the last figure, but with distances marked for the radii of the sun and body, and the distance between the body and spacecraft.\"}\n\nHere is a more detailed view of the eclipse that will make it easier to explain what is going on. There are 2 Position vectors, and 2 radius that need to be known for simple eclipse determination. More advanced cases where the atmosphere of the body your orbiting can significantly affect the Umbra and Penumbra, and other bodies could also potentially block the Sun. However, we will keep it simple for this example since they have minimal effect on the ISS’s orbit. Rsun
and Rbody
are the radius of the Sun and Body (In this case Earth), respectively. r_sun_body
is a vector from the center of the Sun to the center of the target body. For this example I will only be using one vector, but for more rigorous eclipse determination it is important to calculate the ephemeris at least once a day since it does significantly change over the course of a year. The reason that I am ignoring it at the moment is because there is currently no good way to calculate [Ephemerides](https://ssd.jpl.nasa.gov/?ephemerides) in Julia but the package is being worked on so I may revisit this and do a more rigorous analysis in the future. r_body_sc
is a position vector from the center of the body being orbited, to the center of our spacecraft. \n\n## The Code\n\n::: {#7ffb4d4c .cell execution_count=1}\n``` {.julia .cell-code code-fold=\"true\" code-summary=\"Imports\"}\nusing Unitful\nusing LinearAlgebra\nusing SatelliteToolbox\nusing Plots\nusing Colors\ntheme(:ggplot2)\n```\n:::\n\n\nTo get the orbit for the ISS, I used a [Two-Line Element](https://en.wikipedia.org/wiki/Two-line_element_set) which is a data format for explaining orbits. The US Joint Space Operations Center makes these widely available, but https://live.ariss.org/tle/ makes the TLE for the ISS way more accessible [@ariss]. The Julia Package [SatelliteToolbox.jl](https://github.com/JuliaSpace/SatelliteToolbox.jl) makes it super easy to turn a TLE into an orbit that can be propagated. Simply putting the TLE in a string and using the `tle` string macro like below, we now have access to the information to start making our ISS orbit. \n\n::: {#db0b446f .cell execution_count=2}\n``` {.julia .cell-code}\nISS = tle\"\"\"\nISS (ZARYA)\n1 25544U 98067A 21103.84943184 .00000176 00000-0 11381-4 0 9990\n2 25544 51.6434 300.9481 0002858 223.8443 263.8789 15.48881793278621\n\"\"\"\n```\n\n::: {.cell-output .cell-output-display execution_count=3}\n\n::: {.ansi-escaped-output}\n```{=html}\n
TLE:\n Name : ISS (ZARYA)\n Satellite number : 25544\n International designator : 98067A\n Epoch (Year / Day) : 21 / 103.84943184 (2021-04-13T20:23:10.911)\n Element set number : 999\n Eccentricity : 0.00028580\n Inclination : 51.64340000 deg\n RAAN : 300.94810000 deg\n Argument of perigee : 223.84430000 deg\n Mean anomaly : 263.87890000 deg\n Mean motion (n) : 15.48881793 revs / day\n Revolution number : 27862\n B* : 1.1381e-05 1 / er\n ṅ / 2 : 1.76e-06 rev / day²\n n̈ / 6 : 0 rev / day³\n```\n:::\n\n:::\n:::\n\n\nNow that we have the TLE, we can pass that into SatelliteToolbox's orbit propagator. Before propagating the orbit, we need to have a range of time steps to pass into the propagator. The TLE gives the mean motion, n, which is the revolutions per day, so using that, we can calculate the amount of time required for one orbit, which is all that we're worried about for this analysis. The propagator returns a tuple containing the Orbital elements, a position vector with units meters, and a velocity vector with units meters per second. For this analysis were only worried about the position vector. \n\n::: {#c63813d4 .cell execution_count=3}\n``` {.julia .cell-code}\nISS.mean_motion\n```\n\n::: {.cell-output .cell-output-display execution_count=4}\n```\n15.48881793\n```\n:::\n:::\n\n\n::: {#bd13a742 .cell execution_count=4}\n``` {.julia .cell-code}\norbit = Propagators.init(Val(:SGP4), ISS);\ntime = 0:0.1:((24/ISS.mean_motion).*60*60);\npropagated = Propagators.propagate!.(orbit, time);\nr = first.(propagated); # Get distance from propagator\n```\n:::\n\n\nWe just need to use the radii and vectors discussed earlier to determine if the ISS is in the penumbra or umbra. This is a lot of trigonometry and vector math that I won't bore anyone with. However, using the diagrams above and following the code in the sunlight function, you should follow what's happening. For a rigorous discussion, check out [@vallado]. \n\n::: {#b50273ec .cell execution_count=5}\n``` {.julia .cell-code}\nfunction sunlight(Rbody, r_sun_body, r_body_sc)\n Rsun = 695_700u\"km\"\n\n hu = Rbody * norm(r_sun_body) / (Rsun - Rbody)\n\n θe = acos((r_sun_body ⋅ r_body_sc) / (norm(r_sun_body) * norm(r_body_sc)))\n\n θu = atan(Rbody / hu)\n du = hu * sin(θu) / sin(θe + θu)\n\n θp = π - atan(norm(r_sun_body) / (Rsun + Rbody))\n dp = Rbody * sin(θp) / cos(θe - θp)\n\n S = 1\n if (θe < π / 2) && (norm(r_body_sc) < du)\n S = 0\n end\n if (θe < π / 2) && ((du < norm(r_body_sc)) && (norm(r_body_sc) < dp))\n S = (norm(r_body_sc .|> u\"km\") - du) / (dp - du) |> ustrip\n end\n\n return S\nend\n```\n\n::: {.cell-output .cell-output-display execution_count=6}\n```\nsunlight (generic function with 1 method)\n```\n:::\n:::\n\n\nThen we can pass all the values we've gathered into the function we just made. \n\n::: {#eaa5595d .cell execution_count=6}\n``` {.julia .cell-code}\nS = r .|> R -> sunlight(6371u\"km\", [0.5370, 1.2606, 0.5466] .* 1e8u\"km\", R .* u\"m\");\n```\n:::\n\n\n## Plotting the Results\n\nThe `sunlight` function returns values from 0 to 1, 0 being complete darkness, 1 being complete sunlight, and anything between being the fraction of light being received. Again since the ISS has a very low orbit, the amount of time spent in the penumbra is almost insignificant. \n\n::: {#f97a6fa0 .cell alt-text='A graph titled \"ISS Sunlight Over a Day\" showing the percentage of sunlight the ISS receives over a 24-hour period. The x-axis represents time in hours, and the y-axis represents sunlight percentage. The graph shows a period of near-total sunlight followed by a period of darkness, and the cycle repeats.' execution_count=7}\n``` {.julia .cell-code code-fold=\"true\"}\n# Get fancy with the line color. \nlight_range = range(colorant\"black\", stop=colorant\"orange\", length=101);\nlight_colors = [light_range[unique(round(Int, 1 + s * 100))][1] for s in S];\n\nplot(\n LinRange(0, 24, length(S)),\n S .* 100,\n linewidth=5,\n legend=false,\n color=light_colors,\n);\n\nxlabel!(\"Time (hr)\");\nylabel!(\"Sunlight (%)\");\ntitle!(\"ISS Sunlight Over a Day\")\n```\n\n::: {.cell-output .cell-output-display execution_count=8}\n```{=html}\n\n\n```\n\nISS Sunlight\n:::\n:::\n\n\nLooking at the plot, the vertical transition from 0% to 100% makes it pretty clear that the time in the penumbra is limited. Still, almost counterintuitively, it also looks like the ISS gets more sunlight than it does darkness. So, using the raw sunlight data, we can calculate precisely how much time is spent in each region. \n\nTime in Sun:\n\n::: {#855eaf03 .cell execution_count=8}\n``` {.julia .cell-code}\nsun = length(S[S.==1]) / length(S) * 100\n```\n\n::: {.cell-output .cell-output-display execution_count=9}\n```\n62.04757721886597\n```\n:::\n:::\n\n\nTime in Darkness:\n\n::: {#89899587 .cell execution_count=9}\n``` {.julia .cell-code}\numbra = length(S[S.==0]) / length(S) * 100\n```\n\n::: {.cell-output .cell-output-display execution_count=10}\n```\n37.627951167918546\n```\n:::\n:::\n\n\nTime in Penumbra:\n\n::: {#0c9ef7cd .cell execution_count=10}\n``` {.julia .cell-code}\npenumbra = 100 - umbra - sun\n```\n\n::: {.cell-output .cell-output-display execution_count=11}\n```\n0.32447161321548634\n```\n:::\n:::\n\n\nThis means that even with the ISS's low orbit, it still gets sunlight ~62% of the time and spends almost no time in the penumbra. This would vary a few percent depending on the time of year, but in a circular orbit like the ISS, the amount of sunlight would remain pretty constant. There are other orbits like a polar orbit, lunar orbit, or highly elliptic earth orbits that can have their time in the sunlight vary widely by the time of year. \n\n", "supporting": [ "index_files" ], "filters": [], "includes": { "include-in-header": [ "\n\n\n" ] } } }