An amateur astronomer colleague of mine, Mátyás SZŰCS, got me inspired to look into exoplanets — once again. I already had a close encounter with distant solar systems, while looking into the Kepler measurements as published on the planethunters org website, going through some 4k stars of interest, of the some 160k that Kepler observed during its first mission.
I’ve never done observations of this kind before, maybe I never will. But I wanted to see what it is I could expect. I put together a naive simulation and then looked up some professional material to check for those into such stuff.
So I went for a rather naive approach here, went for numeric simulations in… well, PHP… with a color (rgb) selective limb darkening and planets with no atmosphere. The stars are simple, spherical, no polar brightening and no flattening, as with say Vega.
The interesting thing is the sharp drop between the first and second contacts and then the steady drop till the maximum — see below.
The set I generated: blue-white-red stars with color-selective limb darkening, several planetary diameters relative to the host star, and from transits through the center to those barely grazing. All the „planets” move across the „star” from left to right. An important aspect to observe is that the limb darkening is more severe for the blue end of the spectrum.
The diagram below the snapshot shows the shape of the light curve, at 100% being the unobstructed star, and the minimum representing the planet placed right onto the center of the stellar disk, regardless of the vertical offset being observed. The numbers on the left indicate the percentage of the star’s luminosity available at the extremes, and the green dot draws the light curve between the two extremes. The source code, meant to be run in a localhost apache installation, is below.
Some of the generated pictures I put below, smaller set and the source code to generate all can be downloaded here:

The simulated Sun, Jupiter, Venus and Earth. More or less to scale regarding both the speed and the relative sizes
Regarding the transit of Venus, my naive approach compared to real life transits
Below is a picture of a Venus transit to scale, when viewed (left) from an insterstellar distance, and (right) from Earth in 2012 (but without the sunspots some of us remember). And a picture of the transit, as I recorded it in 2012.
Note some differences: it was early in the morning, and in between rains and clouds, at least some of the hue of the Sun may be due to that; the different limb darkening ratio; the amateur equipment used, ie a point and shoot camera with a baader solar filter.
Source Code
Second version of the code, that generated the Jupiter-Earth-Venus transit
<?php set_time_limit (60*60); function drawStarWithPlanetsAndReturnIntensity( $star_info, $planets_info, &$include_graph, $filename ){ if (!isset($GLOBALS["__star_cache"])){ $GLOBALS["__star_cache"] = array(); } if (is_array($filename)){ $filename = getfilepath($star_info, $planets_info, true, $filename["index"]); } if ($filename === "auto"){ $filename = getfilepath($star_info, $planets_info, true); } $margin = $star_info["radius_px"] / 4; $xs = $star_info["radius_px"]*2 + $margin+$margin; $ys = $xs; if ($include_graph !== null){ $ys = $ys * 3/2; } $o = $star_info["radius_px"] + $margin; $i = imagecreatetruecolor($xs, $ys); $key = "star".md5(serialize($star_info)); if (isset($GLOBALS["__star_cache"][$key])){ imagecopy($i, $GLOBALS["__star_cache"][$key], 0, 0, 0, 0, imagesx($i), imagesy($i)); }else{ imagefilledrectangle($i, 0,0, imagesx($i), imagesy($i), 0); $GLOBALS["__star_cache"][$key] = imagecreatetruecolor($xs, $ys); imagefilledrectangle($GLOBALS["__star_cache"][$key], 0,0, imagesx($GLOBALS["__star_cache"][$key]), imagesy($GLOBALS["__star_cache"][$key]), 0); for ($r=0; $r < $star_info["radius_px"]-2; $r++){ $i_0 = 255; $bgr = array(0.95, 0.8, 0.56); foreach ($bgr as &$c){ $u = $c; $i_r = $i_0 * (1 - $u * (1 - sqrt(($star_info["radius_px"]*$star_info["radius_px"] - $r*$r) / ($star_info["radius_px"]*$star_info["radius_px"])))); $c = $i_r; } $si = 1+abs($star_info["color_index"]); $kount = 2;$mult = 1; $kmu = $si - 6; if ($kmu >= 0){ $kount += $kmu; $mult += $kmu; } if ($star_info["color_index"] < 0){ // blue $bgr[2] = $bgr[2]/$si; $bgr[1] = (($bgr[1]/$si)*$mult + $bgr[1])/$kount; } if ($star_info["color_index"] > 0){ // red $bgr[0] = $bgr[0]/$si; $bgr[1] = (($bgr[1]/$si)*$mult + $bgr[1])/$kount; } foreach ($bgr as &$c2){ $c2 = floor($c2); }; $col = imagecolorallocate($i, $bgr[2], $bgr[1], $bgr[0]); foreach (array(-1, 1) as $x){ foreach (array(-1, 1) as $y){ imageellipse ($i, $o+$x, $o+$y, $r*2 , $r*2, $col); } } } imagecopy($GLOBALS["__star_cache"][$key], $i, 0, 0, 0, 0, imagesx($i), imagesy($i)); } $planets_total_area = 0; $planet_color = imagecolorallocate($i, 0, 0, 0); $planet_circle = imagecolorallocate($i, 125, 55, 0); foreach ($planets_info as $planet){ $r = $star_info["radius_px"] * $planet["radius__in_stellar_radii"]; $planets_total_area += M_PI * $r * $r; if ($r > 0){ imagefilledellipse ($i, $o + $star_info["radius_px"]*$planet["offset_from_center_x__in_stellar_radii"], $o + $star_info["radius_px"]*$planet["offset_from_center_y__in_stellar_radii"], $r * 2, $r * 2, $planet_color ); } } $planets_approx_radius_px = sqrt($planets_total_area / M_PI); $planets_approx_radius___in_stellar_radii = $planets_approx_radius_px / $star_info["radius_px"]; // now get the intensity $um = 0; $lum = 0; for ($x=0; $x<imagesx($i); $x++){ //imagesx, to not include any graph for ($y=0; $y<imagesx($i); $y++){ $rgb = imagecolorat($i, $x, $y); $r = ($rgb >> 16) & 0xFF; $g = ($rgb >> 8) & 0xFF; $b = $rgb & 0xFF; $lum += $r+$g*2 +$b; }; } foreach ($planets_info as $planet){ $r = $star_info["radius_px"] * $planet["radius__in_stellar_radii"]; //if the planet is outside the star if ($r > 0){ $d = pow(($star_info["radius_px"]*$planet["offset_from_center_x__in_stellar_radii"]), 2) + pow($star_info["radius_px"]*$planet["offset_from_center_y__in_stellar_radii"], 2); $d = sqrt($d); if ($d > $star_info["radius_px"] + $r){ imageellipse($i, $o + $star_info["radius_px"]*$planet["offset_from_center_x__in_stellar_radii"], $o + $star_info["radius_px"]*$planet["offset_from_center_y__in_stellar_radii"], $r * 2, $r * 2, $planet_circle ); } } } if ($include_graph !== null ){ $null = NULL; $xtr = 0; if (!isset($include_graph["min_lum"])){ $planet_in_the_middle = array( "radius__in_stellar_radii" => $planets_approx_radius___in_stellar_radii, "offset_from_center_x__in_stellar_radii" => 0, "offset_from_center_y__in_stellar_radii" => 0 ); $summa_planet = array($planet_in_the_middle); $include_graph["min_lum"] = drawStarWithPlanetsAndReturnIntensity( $star_info, $summa_planet, $null, "?", ); $xtr++; } if (!isset($include_graph["max_lum"])){ $no_planet = array(); $include_graph["max_lum"] = drawStarWithPlanetsAndReturnIntensity( $star_info, $no_planet, $null, "?", ); $xtr++; } if ($xtr == 2){ // die(); } $window_height = $ys - $xs; $window_width = $xs; $window_margin = round($xs / 10); $window_height -= 2*$window_margin; $window_width -= 2*$window_margin; $col = imagecolorallocate($i, 0, 255, 0); $white = imagecolorallocate($i, 255, 255, 255); //var_dump($include_graph); imagestring ($i, 1, 0, $ys-$window_margin - $window_height, "100%", $white); imagestring ($i, 1, 0, $ys-$window_margin, (round(($include_graph["min_lum"] / $include_graph["max_lum"])*10000)/100) . "%", $white); imageline ($i, $window_margin, $ys - $window_margin, $window_margin+$window_width, $ys-$window_margin, $white); imageline ($i, $window_margin, $ys - $window_margin, $window_margin, $ys-$window_margin-$window_height, $white); $px = $window_margin + $window_width/2 + ($include_graph["xpos"] / $include_graph["xhalfsize"]) * $window_width/2; $py = $ys - $window_margin - ($lum - $include_graph["min_lum"])/($include_graph["max_lum"] - $include_graph["min_lum"])*$window_height; //echo $px.' '.$py; $include_graph["points"][] = array($px, $py); $prev = false; foreach ($include_graph["points"] as $pix){ if ($prev === false){ imagesetpixel($i,$pix[0], $pix[1], $col); }else{ imageline($i, $prev[0], $prev[1], $pix[0], $pix[1], $col); } $prev = $pix; } } if ($filename != "?"){ imagejpeg($i, $filename, 95); }; imagedestroy($i); return $lum; } //============================================================================== function getfilepath($star_info, $planets_info, $create_folder = false, $index = false){ $sepa = "__"; $r = $star_info["radius_px"]; while (strlen($r < 5)){ $r = '0'.$r; } $folder = array(); $folder[] = "starrad_".$r."px".$sepa; $col = abs($star_info["color_index"]); if ($star_info["color_index"] > 0){ $col .= "r"; } if ($star_info["color_index"] < 0){ $col .= "b"; } if ($star_info["color_index"] == 0){ $col .= "w"; } while (strlen($col) < 5){ $col = '0'.$col; } $folder[] = "starcolorindex_".$col; $folder[] = "md5_".md5(serialize($folder)); $filepath = array(); if ($index!==false){ while (strlen($index) < 5){ $index = '0'.$index; } $filepath[] = $index; } $filepath = array_merge($filepath, $folder); if (count($planets_info) > 1){ //filename too long $filepath[] = md5(serialize($planets_info)); }else{ $planetCounter = 0; foreach ($planets_info as $planet){ $p = "planet".$planetCounter.$sepa."r_"; $siz = $planet["radius__in_stellar_radii"] * $star_info["radius_px"]; while (strlen($siz) < 5){ $siz = "0".$siz; } $p .= $siz.'px'; $filepath[] = $p; foreach (array("x", "y") as $xy){ $p = "coff".$xy."_"; $siz = $star_info["radius_px"]*$planet["offset_from_center_".$xy."__in_stellar_radii"]; $asiz = round(abs($siz)); while (strlen($asiz) < 5){ $asiz = "0".$asiz; } $p .= ($siz < 0 ? "m" : "p").$asiz.'px'; $filepath[] = $p; } $planetCounter++; } } $folder = implode($sepa, $folder); $filepath = implode($sepa, $filepath); if ($create_folder){ @mkdir($folder); } return $folder.'/'.$filepath.'.jpg'; } //============================================================================== function createEmptyGraph(){ return array( "points" => array(), "xpos" => 0, "xhalfsize" => 1 ); } //============================================================================== function planets_xoffsetextreme_for_star($planet, $star_info){ $spm = 1; if (isset($planet["speed_multiplier"])){ $spm = $planet["speed_multiplier"]; //die("kocka".$spm); } $px = ($star_info["radius_px"] * $planet["radius__in_stellar_radii"] * 1.3 * $spm) + $star_info["radius_px"]; $sr = $px / $star_info["radius_px"]; return array( "xoff__in_px" => $px, "xoff__in_stellar_radii" => $sr ); } //============================================================================== $star_info = array( "radius_px" => 305, "color_index" => -1 ); $planets_info = array(); $planets_info[] = array( "name" => "Venus", "radius__in_stellar_radii" => 0.01, "initial_offset_from_center_x__in_stellar_radii" => -7.2, "offset_from_center_x__in_stellar_radii" => 0.8, "offset_from_center_y__in_stellar_radii" => 0.1, "speed_multiplier" => 14 ); $planets_info[] = array( "name" => "Earth", "radius__in_stellar_radii" => 0.01, "initial_offset_from_center_x__in_stellar_radii" => -5.5, "offset_from_center_x__in_stellar_radii" => 0.8, "offset_from_center_y__in_stellar_radii" => 0.25, "speed_multiplier" => 11 ); $planets_info[] = array( "name" => "Jupiter", "radius__in_stellar_radii" => 0.1, "offset_from_center_x__in_stellar_radii" => -0.3, "offset_from_center_y__in_stellar_radii" => 0.3, "speed_multiplier" => 1 ); $include_graph = createEmptyGraph(); $planet_hastener_factor = 2; $planet_unit_speed_factor = 5; $planets_unit_speed = ($planet_unit_speed_factor / $star_info["radius_px"]) / 5; $needed_half_steps = 0; foreach ($planets_info as &$p){ $k = planets_xoffsetextreme_for_star($p, $star_info); $k = $k["xoff__in_stellar_radii"]; $p["offset_from_center_x__in_stellar_radii"] = -1 * $k; $nhs = (abs($p["offset_from_center_x__in_stellar_radii"]) / $planets_unit_speed) / $p["speed_multiplier"]; $needed_half_steps = max($needed_half_steps, $nhs); if (isset($p["initial_offset_from_center_x__in_stellar_radii"])){ $p["offset_from_center_x__in_stellar_radii"] += $p["initial_offset_from_center_x__in_stellar_radii"]; } }; $include_graph["xhalfsize"] = $needed_half_steps; $steps = $include_graph["xhalfsize"]*2; $null = NULL; for ($step = 0; $step<min(400, $steps); $step++){ $include_graph["xpos"] = $step - $include_graph["xhalfsize"]; drawStarWithPlanetsAndReturnIntensity($star_info, $planets_info, $null, array( "index" => $step, "filename" => "auto" )); foreach ($planets_info as &$planet){ $planet["offset_from_center_x__in_stellar_radii"] += $planet["speed_multiplier"]*$planets_unit_speed*$planet_hastener_factor; } } ?>
First version of the code
<?php set_time_limit (60*60); function drawStarWithPlanetAndReturnIntensity( $star_radius, $planet_per_star_radius, $planet_offset_x__stellar_radii, $planet_offset_y__stellar_radii, &$include_graph, $filename, $star_color_index = 0 ){ $margin = $star_radius / 4; $xs = $star_radius*2+$margin+$margin; $ys = $xs; if ($include_graph !== null){ $ys = $ys * 3/2; } $i = imagecreatetruecolor($xs, $ys); imagefilledrectangle($i, 0,0, imagesx($i), imagesy($i), 0); $o = $star_radius + $margin; for ($r=0; $r < $star_radius-2; $r++){ $i_0 = 255; $bgr = array(0.95, 0.8, 0.56); foreach ($bgr as &$c){ $u = $c; $i_r = $i_0 * (1 - $u * (1 - sqrt(($star_radius*$star_radius - $r*$r) / ($star_radius*$star_radius)))); $c = $i_r; } $si = 1+abs($star_color_index); if ($star_color_index < 0){ // blue $bgr[2] = $bgr[2]/$si; $bgr[1] = (($bgr[1]/$si) + $bgr[1])/2; } if ($star_color_index > 0){ // red $bgr[0] = $bgr[0]/$si; $bgr[1] = (($bgr[1]/$si) + $bgr[1])/2; } foreach ($bgr as &$c2){ $c2 = floor($c2); }; $col = imagecolorallocate($i, $bgr[2], $bgr[1], $bgr[0]); foreach (array(-1, 1) as $x){ foreach (array(-1, 1) as $y){ imageellipse ($i, $o+$x, $o+$y, $r*2 , $r*2, $col); } } } imagefilledellipse ($i, $o + $star_radius*$planet_offset_x__stellar_radii, $o + $star_radius*$planet_offset_y__stellar_radii, $star_radius * $planet_per_star_radius * 2, $star_radius * $planet_per_star_radius * 2, 0 ); // now get the intensity $um = 0; $lum = 0; for ($x=0; $x<imagesx($i); $x++){ //imagesx, to not include any graph for ($y=0; $y<imagesx($i); $y++){ $rgb = imagecolorat($i, $x, $y); $r = ($rgb >> 16) & 0xFF; $g = ($rgb >> 8) & 0xFF; $b = $rgb & 0xFF; $lum += $r+$g*2 +$b; }; } if ($include_graph !== null ){ $null = NULL; $xtr = 0; if (!isset($include_graph["min_lum"])){ $include_graph["min_lum"] = drawStarWithPlanetAndReturnIntensity( $star_radius, $planet_per_star_radius, 0, 0, $null, "?", $star_color_index ); $xtr++; } if (!isset($include_graph["max_lum"])){ $include_graph["max_lum"] = drawStarWithPlanetAndReturnIntensity( $star_radius, $planet_per_star_radius, 10, 10, $null, "?", $star_color_index ); $xtr++; } if ($xtr == 2){ // die(); } $window_height = $ys - $xs; $window_width = $xs; $window_margin = round($xs / 10); $window_height -= 2*$window_margin; $window_width -= 2*$window_margin; $col = imagecolorallocate($i, 0, 255, 0); $white = imagecolorallocate($i, 255, 255, 255); //var_dump($include_graph); imagestring ($i, 1, 0, $ys-$window_margin - $window_height, "100%", $white); imagestring ($i, 1, 0, $ys-$window_margin, (round(($include_graph["min_lum"] / $include_graph["max_lum"])*10000)/100) . "%", $white); imageline ($i, $window_margin, $ys - $window_margin, $window_margin+$window_width, $ys-$window_margin, $white); imageline ($i, $window_margin, $ys - $window_margin, $window_margin, $ys-$window_margin-$window_height, $white); $px = $window_margin + $window_width/2 + ($include_graph["xpos"] / $include_graph["xhalfsize"]) * $window_width/2; $py = $ys - $window_margin - ($lum - $include_graph["min_lum"])/($include_graph["max_lum"] - $include_graph["min_lum"])*$window_height; //echo $px.' '.$py; $include_graph["points"][] = array($px, $py); $prev = false; foreach ($include_graph["points"] as $pix){ if ($prev === false){ imagesetpixel($i,$pix[0], $pix[1], $col); }else{ imageline($i, $prev[0], $prev[1], $pix[0], $pix[1], $col); } $prev = $pix; } } if ($filename != "?"){ imagejpeg($i, $filename, 95); }; imagedestroy($i); return $lum; } //============================================================================== if (!isset($_GET["thread"])){ $planetary_radii = array(1, 0.5, 0.25, 0.1, 0.05, 0.01); foreach ($planetary_radii as $p){ echo '<iframe src="?thread='.$p.'"></iframe>'; } die(); }else{ $planetary_radii = array(floatval($_GET["thread"])); } $star_radius_pixel = 200; $star_color_indices = array(-5, -1, 0, 1, 5); $planetary_offsets = array(0, 0.3, 0.5, 0.8, 1); $dist = 100; $dist_step = 1; foreach ($planetary_radii as $planet_rad){ foreach ($star_color_indices as $star_color_index){ foreach ($planetary_offsets as $y_off){ $extreme = $dist + $planet_rad*$dist*3; $setname = "starrad_".$star_radius_pixel.'__starcol_'.$star_color_index.'__planetrad_'.($star_radius_pixel * $planet_rad).'__yoff_'.($y_off * $star_radius_pixel).''; $graph = array( "xpos" => 0, "xhalfsize" => $extreme, "points" => array() ); mkdir($setname); for ($x = -$extreme; $x<=$extreme; $x += $dist_step){ $x1 = $x+$extreme; //$y = 0; while (strlen($x1) < 4){ $x1 = '0'.$x1; } $filename = $setname . "/out_".$x1.".jpg"; $graph["xpos"] = $x; $lum = drawStarWithPlanetAndReturnIntensity( $star_radius_pixel, $planet_rad, $x/$dist, $y_off, $graph, $filename, $star_color_index ); rename($filename, str_replace('.jpg', '_'.$lum.'.jpg', $filename)); //die(); } } } } //echo '<img src="out.jpg?'.mt_rand().'">'; ?>
Professional stuff:
https://www.cfa.harvard.edu/~avanderb/tutorial/tutorial.html
https://exoctk.stsci.edu/limb_darkening
http://adsabs.harvard.edu/full/1990A%26A…230..412C
https://exoplanetarchive.ipac.caltech.edu/cgi-bin/TblView/nph-tblView?app=ExoTbls&config=PS
https://github.com/hpparvi/ldtk
https://hatnet.org





