Wave Packets

Physics
Code
chart = {
  const margin = { top: 20, right: 10, bottom: 20, left: 10 };
  const width = fullWidth - margin.left - margin.right,
        height = fullHeight - margin.top - margin.bottom;

  const window = d3.create("svg")
    .attr("width", "100%")
    .attr("height", "100%")
    .attr("viewBox", `0 0 ${fullWidth} ${fullHeight}`)
    .attr("preserveAspectRatio", "xMidYMid meet");

  const svg = window.append("g")
    .attr("class", "pulse")
    .attr("transform", `translate(${margin.left},${margin.top})`);

  const envelope = svg.append("path")
    .attr("class", "envelope")
    .attr("opacity", 0.2)
    .style("fill", "#1f77b4");

  const signal = svg.append("path")
    .attr("class", "signal")
    .style("fill", "none")
    .style("stroke", "#d62728")
    .style("stroke-width", 3);

  const range = d3.range(-10, 10.1, 0.05);

  const x = d3.scaleLinear().domain(d3.extent(range)).range([0, width]),
        y = d3.scaleLinear().domain([-1, 1]).range([height, 0]);

  const re = d3.line()
    .x(d => x(d.x))
    .y(d => y(d.re))
    .curve(d3.curveBasis);

  const abs = d3.area()
    .x(d => x(d.x))
    .y0(d => y(-d.abs))
    .y1(d => y(d.abs))
    .curve(d3.curveBasis);

  function f(x) {
    const f0 = tau;
    return {
      r: f0 / Math.sqrt(Math.PI) / tau
        * Math.exp(-(t - k1 * x) * (t - k1 * x) / (2 * tau * tau)),
      phi: w0 * t - k0 * x,
    };
  }

  let t = 0, // animation time
      dt = 0.05; // time step

  let tau = defaults.tau,
      w0 = defaults.w0,
      k0 = defaults.k0,
      k1 = defaults.k1;

  function tick() {
    t += dt;

    if (t > k1 * 10 || t < -k1 * 10) {
      dt *= -1; // reverse the direction of motion
    }

    const data = range.map(x => {
      const y = f(x);
      return {
        x: x,
        re: y.r * Math.cos(y.phi),
        abs: y.r
      };
    });

    envelope
      .datum(data)
      .attr("d", abs);

    signal
      .datum(data)
      .attr("d", re);
  }

  const timer = d3.interval(tick, 20);

  invalidation.then(() => {
    timer.stop();
  });

  return Object.assign(window.node(), {
    update(values) {
      tau = values.tau;
      w0 = values.w0;
      k0 = values.k0;
      t *= values.k1 / k1;
      k1 = values.k1;
    },
  });
}

This pulse is described by the following equation, where \(\tau\) is the pulse width, \(\omega_0\) is the frequency, \(k_0\) is the first wavenumber, and \(k'\) is the second wavenumber:

\[E(x,t)=\frac{E_0}{\sqrt{\pi}\tau}e^{-\frac{(t-k'x)^2}{2\tau^2}}e^{i\omega_0t-ik_0x}\]

The phase propagates at velocity \(v_{ph}=\frac{\omega_0}{k_0}\) and the envelope at \(v_{gr}=\frac{1}{k'}\).

Resources