Professional Documents
Culture Documents
The goal here is to render the most accurate representation of how Starlink will actually look in the night sky, to all the key observers: eyes, cameras,
telescopes
Video flythrough
Tl;dr: Pretend starlink satellites are like stars in orbit around earth, and they reflect sunlight (more at some angles than others)
In [21]: # imports
from PIL import Image
import numpy as np
In [3]: Image.open("./england_42000.png")
Out[3]:
Outline
1. Photometry
Getting a rendered screen brightness of astronomical objects
Simulating Starlink satellites' brightness
Reflectance mapping
Calibrating to best available observed magnitudes
Atmospheric extinction
Earth surface and atmosphere brightness
Calibration to approximate real-world eyes, cameras, telescopes
2. Dynamics
Ephemeris and orbital calculation of satellites
3. Limitations and other notes
4. Sources
1. Photometry
Apparent magnitude 𝑣 𝑚𝑎𝑔 is the standard numerical scale of star brightness established by Hipparchus; a brightness sensitivity scale is calibrated to the
human eye
Absolute magnitude 𝑎𝑏𝑠𝑚𝑎𝑔 is defined as the apparent magnitude of a light source at a distance 10 parsec from the observer
The relationship between magnitude and distance comes from this and is:
𝑎𝑏𝑠𝑚𝑎𝑔 = 𝑣𝑚𝑎𝑔 − 5𝑙𝑜𝑔10 (𝑑𝑝𝑐 ) + 5 = 𝑣𝑚𝑎𝑔 + 5(1 − 𝑙𝑜𝑔10 (𝑑𝑝𝑐 ))
To position objects in space, we use kilometers, not parsecs, so a conversion factor is introduced to convert km to parsec
𝑘𝑚𝑝𝑝 = 30, 856, 775, 812, 800/𝑓𝑟𝑎𝑐𝑘𝑖𝑙𝑜𝑚𝑒𝑡𝑒𝑟𝑠𝑝𝑎𝑟𝑠𝑒𝑐
Then these equations are used to convert between absolute and apparent magnitude
𝑎𝑏𝑠𝑚𝑎𝑔 = 𝑣𝑚𝑎𝑔 + 5(1 − 𝑙𝑜𝑔10 (𝑑𝑝𝑐 )) = 𝑣𝑚𝑎𝑔 + 5(1 − 𝑙𝑜𝑔10 (𝑑𝑘𝑚 /𝑘𝑚𝑝𝑝 ))
𝑣𝑚𝑎𝑔 = 𝑎𝑏𝑠𝑚𝑎𝑔 − 5(1 − 𝑙𝑜𝑔10 (𝑑𝑘𝑚 /𝑘𝑚𝑝𝑝 ))
To convert from magnitudes to pixel brightnesses, we use the relative brightness calculations found here, implemented as follows:
So, B describes how many multiples brighter or dimmer an object is than the reference star Sirius, as seen from Earth.
During orbit raise, Starlink satellites' solar panels are oriented like this:
In [8]: Image.open("orbit_raise.png")
Out[8]:
In [9]: Image.open("final_orbit.png")
Out[9]:
As a brightness mitigation, Starlink have implemented a visor for the satellite, shading the back of the solar panel and bottom of spacecraft.
Before
In [12]: Image.open("without_visorsat.png")
Out[12]:
After
In [13]: Image.open("with_visorsat.png")
Out[13]:
There are SO MANY varying observations of Starlink's apparent magnitude in different conditions. Mallama in Source 1 showed that neither a phase-angle
model nor a flat-panel model provides a good fit to observations.
With that said, these are the best-available estimates of Starlink's magnitude (adjusted to 550km viewing distance) at each phase of deployment (Orbit-raising,
on-station) and each design (Original, DarkSat, VisorSat)
Atmospheric extinction
As the satellites pass into the earth's shadow, the light reaching them also passes through the earth's atmosphere. We simulate this using the atmospheric
scattering simulation technique mentioned here, but modify it to consider the spacecraft as the camera.
This has the effect of coloring the starlink trails red as they pass into earth's shadow, which can be seen in this image (magnitudes inaccurate here)
In [24]: Image.open("exaggerated_extinction.png")
Out[24]:
To get a "good" measure of how bright the satellite is at various camera angles and sun angles, I did the following:
Using Unreal Engine 4.26, I applied realistic materials to a high poly 3D model of the Starlink satellite (pictured above)
I then took 14,400 (120x120) photos of this 3D model at different rotations:
120 angles x in [0-360)° angle between camera direction and spacecraft solar panel
120 angles y in [0-360)° angle between sun direction and spacecraft solar panel
In [23]: show_gif("StarlinkRotations.gif")
Out[23]:
x is the angle between the camera (normalized position relative to spacecraft) and the spacecraft (normalized negative spacecraft position (points to
earth)). Specifically, when in parking orbit configuration:
0 [deg] = camera is looking directly at the top of base plate, down the solar panel, towards earth
90 [deg] = camera is looking directly at the back of the solar panel
180 [deg] = camera is looking directly at the bottom of the base plate
270 [deg] = camera is looking directly at the front of the solar panel
360 [deg] = camera is looking directly at the top of base plate, down the solar panel, towards earth (again)
y is the angle between the spacecraft and the sun.
0 [deg] = sunlight is shining directly onto the front of the solar panel
90 [deg] = sunlight is shining directly onto the bottom of the base plate (antenna face)
180 [deg] = sunlight is shining directly onto the back of the solar panel
270 [deg] = sunlight is shining directly onto the top of the base plate
360 [deg] = sunlight is shining directly onto the front of the solar panel (again)
Now, to create something usable in photometric simulation, I took the norm() (mean square) of all 14,400 images
Example:
Out[12]:
Out[13]:
Then I created albedo/reflectance lookup tables for all designs and phases, where:
Values along the width are x and values along the height are y both map [0, size of image) to [0,360) degrees or [0, 2/𝑝𝑖) radians
The (0,0) point is the top left of the images, and the (120,120) point is bottom right
The brightness of any pixel at (x,y) gives the norm measured at that point (normalized so that all values lie within [0,1], or, [0,255] in the case of 8-bit
uint images
In [28]: Image.open("../../assets/data/starlink/flarefullscale/FinalOrbit_Starlink.tiff")
Out[28]:
In [30]: Image.open("../../assets/data/starlink/flarefullscale/FinalOrbit_Visorsat.tiff")
Out[30]:
In [36]: Image.open("../../assets/data/starlink/flarefullscale/OrbitRaise_Starlink.tiff").resize((120,120))
Out[36]:
In [37]: Image.open("../../assets/data/starlink/flarefullscale/OrbitRaise_Visorsat.tiff").resize((120,120))
Out[37]:
In the first two images, the brightness in the bottom and top right is the solar panel reflecting sunlight. In the second two images (orbit-raise config), that
solar panel changes position, moving to the bottom left and bottom right.
The brightest part of the spacecraft (across all conditions) is the bottom (antennas face).
You can see that Visorsat strongly decreases the brightness of the base plate (antennas face), and (to a lesser degree) the solar panel back
Without accounting for reflectance, a wide-angle ~30sec long exposure in rural England at 02:50 Dec 29 2020 looks like this (all Visorsats)
In [18]: Image.open("extinction_0250am_visorsat.png")
Out[18]:
But using the reflectance lookup as a multiplier on the magnitude of the spacecraft looks like this (all Visorsats)
In [19]: Image.open("reflectance_AND_extinction_0250am_visorsat.png")
Out[19]:
Using only the lookup tables and a reference (absolute) magnitude of -0.95 (hand-tuned), we can get close to observed magnitudes for the 'original' starlink
satellites
Clearly, VisorSat numbers here are way off. But, by hand-calibrating absolute magnitudes to fit observations (tedious, yes!), we get:
By using:
For earth's night light illumination, I am using the NPP-VIIRS data from 2016 (in 6x 16384x8192 32bit tiles (yes, oof!)). The values in that dataset are
nanoWatts/cm2/sr, multiplied by 1e9, so Watts/cm2/sr
I would like (eventually) to match that to the magnitudes established in the Photometry section, but haven't the time to.
Instead, I have visually approximated the brightness by using reference images, like this one:
In [20]: Image.open("ISS_UK.jpg")
Out[20]:
All the graphics programs (earth, starlink sats, etc...) are fed into a 32bit frame buffer, which is where I do tonemapping, gain, and gamma adjustments, and
then that is drawn to the 8bit final screen buffer.
To match the images coming from the program to real world as best as possible, I calibrated the simulation gain, gamma to real-world timelapses I've taken:
In [41]: A = Image.open('../calibration/frame_358.jpg')
A
Out[41]:
In [42]: B = Image.open('../calibration/calibration_frame358_gain_gamma_match4.png')
B
Out[42]:
2. Dynamics
Ephemeris and orbital calculation of satellites
𝑑𝜃 1
𝑑𝑡
=
√
((𝑎𝑙𝑡𝑖𝑡𝑢𝑑𝑒+𝑟𝑒𝑎𝑟𝑡ℎ )∗1,000)3
𝜇
4. Sources
1. Starlink Satellite Brightness Before VisorSat
"The mean of 830 visual magnitudes adjusted to a distance of 550 km (the operational altitude) is 4.63 +/-0.02. The data on DarkSat, the low-albedo
satellite, indicate that it is fainter than the others by 1.6 (=6.23) magnitudes, however, there is considerable uncertainty in this value due to the small
number of observations. Some satellites were observed to flare by 10,000 times their normal brightness"
10,000x normal brightness is -4.0 on the magnitude scale meaning the flare magnitude was about 0.63
All above measurements are NOT visorsats, only STARLINK-1436 onward have visors
Flare observations:
All the above satellites were launched 2020-03-18, about a month prior to observations, so they would be in orbit raising. This is corroborated by "These
satellites were between altitudes 380 and 425 km"[1]
Flaring magnitudes averaged: -5.4375
2. A Flat-Panel Brightness Model for the Starlink Satellites and Measurement of their Absolute Visual Magnitude
On-station observations
During orbit raising, average magnitude 7.98 |Starlink | Date | UTC | 1km Mag.| PA| |--------:|------:|-------:|-----------:|---:| |1522 |2020-Aug-18 | 00:36| 7.23|
68| |1523 |2020-Aug-19 | 17:56| 8.35| 86| |1526 |2020-Aug-18 | 18:25| 7.97| 97| |1534 |2020-Aug-19 | 18:07| 7.86| 99| |1555 |2020-Aug-18 | 00:31| 7.70| 70|
|1576 |2020-Aug-19 | 18:00| 8.38| 90| |1580 |2020-Aug-19 | 18:03| 8.27| 92| |1582 |2020-Aug-18 | 00:34| 7.53| 69| |1584 |2020-Aug-19 | 17:53| 8.31| 83| |1591
|2020-Aug-19 | 18:05| 8.15| 94|
The average of the 47 magnitudes, after adjustment to the standard 1,000 km distance, is 6.89 with a standard deviation of the mean of 0.09.
During orbit-raise
Darksat: 7.46 ± 0.04 at a range of 976.50 km
STARLINK-1113, an estimated Sloan g′ magnitude of 6.59 ± 0.05 at a range of 941.62 km
In [ ]: