block by renecnielsen ed325ac4517a554c7d62

Satellite Debris Fields

Full Screen

Debris field of the Iridium 33 and Kosmos 2251 satellites which were involved in the first accidental hypervelocity collision in 2009.

Point of collision

Point of collision

20 minutes after collision

20 minutes

50 minutes after collision

50 minutes

Orbital data collected 2015-08-28 14:09:03 PDT

forked from syntagmatic‘s block: Satellite Debris Fields

index.html

<!DOCTYPE html>
<meta charset="utf-8">
<style>
canvas {
  position: absolute;
}
#overlay {
  position: absolute;
  font: bold 12px sans-serif;
  top: 580px;
  left: 20px;
  color: #333;
}
</style>
<body>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.5/d3.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3-geo-projection/0.2.9/d3.geo.projection.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/topojson/1.6.19/topojson.min.js"></script>
<script src="satellite.js"></script>
<script>

var width = 960,
    height = 600;

var radius = height / 2 - 5,
    scale = radius,
    velocity = .02;

var projection = d3.geo.stereographic()
    .scale(260)
    .translate([width / 2, height / 2])
    .rotate([20,0,60])
    .precision(.1);

var graticule = d3.geo.graticule()
  .step([5,5]);

var canvas = d3.select("body").append("canvas")
    .attr("width", width)
    .attr("height", height);

var canvas2 = d3.select("body").append("canvas")
    .attr("width", width)
    .attr("height", height);

var canvas3 = d3.select("body").append("canvas")
    .attr("width", width)
    .attr("height", height);

var overlay = d3.select("body").append("div")
    .attr("id", "overlay");

var color = d3.scale.ordinal()
  .range(["#e41a1c","#377eb8","#4daf4a","#984ea3","#ff7f00","#ffff33","#a65628","#f781bf","#999999"]);

var context = canvas.node().getContext("2d");
var context2 = canvas2.node().getContext("2d");
var context3 = canvas3.node().getContext("2d");

var path = d3.geo.path()
    .projection(projection)
    .context(context);

var timeFormat = d3.time.format("%H:%M %Y-%m-%d");

d3.json("https://gist.githubusercontent.com/mbostock/4090846/raw/d534aba169207548a8a3d670c9c2cc719ff05c47/world-110m.json", function(error, world) {
  if (error) throw error;

  var land = topojson.feature(world, world.objects.land);

  context.fillStyle = "#ddd";
  context.beginPath();
  path(land);
  context.fill();

  context.strokeStyle = "#ccc";
  context.beginPath();
  path(graticule());
  context.lineWidth = 1;
  context.stroke();

  context.fillStyle = "#444";
  context.textAlign = "center";
  context.textBaseline = "middle";
  context.font = "12px sans-serif";

  /*
  var equator = projection([0,0]);
  context.save();
  context.translate(equator[0], equator[1]);
  context.rotate(-Math.PI/2);
  context.fillText("Equator", 0,0);
  context.restore();
  */

  var latitude = projection([-58,0]);
  context.save();
  context.translate(latitude[0], latitude[1]);
  context.rotate(Math.PI/6);
  context.fillText("Latitude", 0, 0);
  context.restore();

  context.textBaseline = "middle";
  context.textAlign = "center";

  d3.range(-80,90,10).forEach(function(lat) {
    var xy = projection([-50,lat]);
    context.fillText(lat + "°", xy[0]+2, xy[1]);
  });

  d3.range(-80,90,10).forEach(function(lat) {
    var xy = projection([130,lat]);
    context.fillText(lat + "°", xy[0]+2, xy[1]);
  });

  context.font = "bold 12px sans-serif";

  var northpole = projection([0,90]);
  context.fillText("N", northpole[0], northpole[1]);

  var southpole = projection([0,-90]);
  context.fillText("S", southpole[0], southpole[1]);

  // source: //www.ripublication.com/aasa/aasav3n1_02.pdf
  var collision = projection([97.88,72.51]);
  context.textBaseline = "middle";
  context.textAlign = "left";
  context.fillText("2009 Collision", collision[0]+8, collision[1]);

  context.fillStyle = "#333";
  context.beginPath();
  context.arc(collision[0], collision[1], 2.5, 0, 2*Math.PI);
  context.fill();

  context.fillStyle = color("IRIDI");
  context.fillText("Iridium 33 Debris", 0.76*width, 0.25*height-15);
  context.fillStyle = color("COSMO");
  context.fillText("Kosmos 2251 Debris", 0.76*width, 0.25*height);

  d3.text("debris.txt", function(error2, data) {
    if (error2) throw error2;

    var stations = [];
    var lines = data.split("\n");
    lines.forEach(function(line) {
      if (line.length == 0) return;

      if (line[0] == "1") {
        var obj = stations[stations.length-1];
        obj.tle1 = line;
        return; 
      }

      if (line[0] == "2") {
        var obj = stations[stations.length-1];
        obj.tle2 = line;
        return; 
      }
      
      stations.push({
        name: line.trim()
      });
    });

    var iridium = stations.filter(function(d) { return d.name.indexOf("IRIDIUM") > -1; });
    var kosmos = stations.filter(function(d) { return d.name.indexOf("COSMOS") > -1; });

    var now = new Date();

    d3.timer(function(elapsed) {
      var time = new Date(now.getTime() + 120*elapsed);
      overlay.text("Predicted debris positions at " + timeFormat(time));

      context3.clearRect(0,0,width,height);
      context3.globalAlpha = .5;
      context3.drawImage(canvas2.node(),0,0);
      context2.globalCompositeOperation = "source-over";
      context2.clearRect(0,0,width,height);
      context2.drawImage(canvas3.node(),0,0);
      context2.globalCompositeOperation = "darken";
      context2.globalAlpha = 0.6;

      context2.fillStyle = color("IRIDI");
      iridium.forEach(function(d) {
        context2.beginPath();
        plotsat(d, time);
        context2.fill();
      });

      context2.fillStyle = color("COSMO");
      kosmos.forEach(function(d) {
        context2.beginPath();
        plotsat(d, time);
        context2.fill();
      });
    });

    function plotsat(station, time) {
      var satrec = satellite.twoline2satrec(station.tle1, station.tle2);

      // increment time by 5 minutes

      var positionAndVelocity = satellite.propagate(
          satrec,
          time.getUTCFullYear(),
          time.getUTCMonth() + 1, // Note, this function requires months in range 1-12.
          time.getUTCDate(),
          time.getUTCHours(),
          time.getUTCMinutes(),
          time.getUTCSeconds()
      );

      if (!positionAndVelocity.position) {
        if (time.getTime() - now.getTime() > 1000) return;
        console.log("No position data for:");
        console.log(station, satrec);
        return;
      }

      var gmst = satellite.gstimeFromDate(
          time.getUTCFullYear(),
          time.getUTCMonth() + 1, // Note, this function requires months in range 1-12.
          time.getUTCDate(),
          time.getUTCHours(),
          time.getUTCMinutes(),
          time.getUTCSeconds()
      );

      // The position_velocity result is a key-value pair of ECI coordinates.
      // These are the base results from which all other coordinates are derived.
      var positionEci = positionAndVelocity.position,
          velocityEci = positionAndVelocity.velocity;

      var positionGd = satellite.eciToGeodetic(positionEci, gmst)
      drawSat(station, positionGd);
    };
  });

  function drawSat(sat, pos) {
    var name = sat.name;
    var xy = projection([pos.longitude*180/Math.PI, pos.latitude*180/Math.PI]);
    context2.arc(xy[0],xy[1],2,0,2*Math.PI);
  };
});

d3.select(self.frameElement).style("height", height + "px");

</script>

update.sh

curl http://www.celestrak.com/NORAD/elements/iridium-33-debris.txt > iridium-33-debris.txt
curl http://www.celestrak.com/NORAD/elements/cosmos-2251-debris.txt > cosmos-2251-debris.txt
cat iridium-33-debris.txt cosmos-2251-debris.txt > debris.txt
rm iridium-33-debris.txt cosmos-2251-debris.txt 

sed -i '' -e '$ d' README.md
echo "Orbital data collected "(date "+%Y-%m-%d %H:%M:%S PDT") >> README.md