Close

Unpacking FSR: Visualizing Diffraction Grating Order Overlap

A project log for JASPER: VIS-NIR SPECTROMETER

Grating-based VIS-NIR Spectrometer: Customizable for spectral range, resolution, SNR, and detector options aided by a software design tool

tony-francisTony Francis 08/23/2025 at 19:510 Comments

This post is a follow-up to the  previous entry on Free Spectral Range (FSR). In that article, the diagram depicting a diffraction grating had a key inaccuracy: it didn't correctly show the overlap of different diffraction orders, which is a fundamental concept for understanding the performance of a spectrometer.

This new Octave script aims to correct that oversight by providing an accurate visualization of how two different wavelengths, 400 nm and 800 nm, are diffracted and how their orders can overlap.

The Physics Behind the Code

The core principle governing how a diffraction grating splits light is described by the grating equation. For a transmission grating, this equation is:

Let's break down what each term means:

This equation is the foundation of the script, as it calculates the precise angle (θm) for each diffracted beam based on the grating's properties and the incident light.

How the Octave Code Works

The Octave script uses this equation to calculate the diffraction angles for two wavelengths (400 nm and 800 nm) for several orders (m=1,m=2,m=−1,m=−2).

  1. Parameters: The script starts with a few user-modifiable parameters at the top, like the angle of incidence (alpha_i) and the grating's ruling density.
  2. Calculations: It then calculates the diffraction angle for each combination of wavelength and diffraction order using the grating equation.
  3. Visualization: The code plots these results as lines originating from the center of the grating. Each wavelength-order combination is given a distinct color, making it easy to see which line corresponds to which beam. Crucially, the length of the lines is adjusted to show where the orders overlap, particularly the second-order 400 nm beam and the first-order 800 nm beam. This visualization highlights how different wavelengths can be diffracted to the same angle, a key concept related to Free Spectral Range.
    % This Octave script simulates diffraction grating geometry to show order overlap.
    % It plots the incident beam, zero-order beam, and the first- and second-order
    % diffracted beams for 400 nm and 800 nm wavelengths.
    % The diffraction grating is plotted as a vertical dotted line.
     close all;
     clear all;
      % --- User-modifiable parameters ---
      % Angle of incidence (in radians).
      % alpha_i = 0 degrees = 0 * pi / 180 radians.
      alpha_i = 0;
    
      % Grating Ruling density (lines/mm).
      ruling_density = 600;
    
      % Groove spacing (in nm).
      d = 1000000 / ruling_density;
    
      % --- Wavelengths of interest (in nm) ---
      lambda_400 = 400; % Plotted as blue
      lambda_800 = 800; % Plotted as magenta
    
      % --- Constants ---
      pi_half = pi / 2; % 90 degrees in radians
    
      % --- Calculate angles and coordinates for a TRANSMISSION GRATING ---
    
      % The grating is at x=0. Beams are diffracted at the origin (0,0).
    
      % Incident beam (at angle alpha_i from the normal, which is the x-axis)
      % We'll plot this as a line coming *to* the origin.
      incident_length = 1.0;
      x_incident_end = -incident_length * cos(alpha_i);
      y_incident_end = incident_length * sin(alpha_i);
    
      % Zero-order beam (transmitted straight through)
      % The angle is the same as the incident angle, but on the other side.
      x_zero = incident_length * cos(alpha_i);
      y_zero = -incident_length * sin(alpha_i);
    
      % First-order diffraction (m=1)
    
      % Calculate the angle for 400 nm (transmission equation is d * sin(theta_m) = m * lambda + d * sin(theta_i))
      % so, theta_m = asin(m * lambda / d + sin(theta_i))
      angle_400_m1 = asin(lambda_400 / d + sin(alpha_i));
      if isreal(angle_400_m1)
        x_400_m1 = cos(angle_400_m1);
        y_400_m1 = sin(angle_400_m1);
      else
        x_400_m1 = 0;
        y_400_m1 = 0;
      end
    
      % Calculate the angle for 800 nm
      angle_800_m1 = asin(lambda_800 / d + sin(alpha_i));
      if isreal(angle_800_m1)
        x_800_m1 = cos(angle_800_m1);
        y_800_m1 = sin(angle_800_m1);
      else
        x_800_m1 = 0;
        y_800_m1 = 0;
      end
    
      % Second-order diffraction (m=2)
    
      % Calculate the angle for 400 nm
      angle_400_m2 = asin(2 * lambda_400 / d + sin(alpha_i));
      if isreal(angle_400_m2)
        x_400_m2 = cos(angle_400_m2);
        y_400_m2 = sin(angle_400_m2);
      else
        x_400_m2 = 0;
        y_400_m2 = 0;
      end
    
      % Calculate the angle for 800 nm, second order
      angle_800_m2 = asin(2 * lambda_800 / d + sin(alpha_i));
      if isreal(angle_800_m2)
        x_800_m2 = cos(angle_800_m2);
        y_800_m2 = sin(angle_800_m2);
      else
        x_800_m2 = 0;
        y_800_m2 = 0;
      end
    
      % Negative First-order diffraction (m=-1)
    
      % Calculate the angle for 400 nm
      angle_400_m_minus_1 = asin(-lambda_400 / d + sin(alpha_i));
      if isreal(angle_400_m_minus_1)
        x_400_m_minus_1 = cos(angle_400_m_minus_1);
        y_400_m_minus_1 = sin(angle_400_m_minus_1);
      else
        x_400_m_minus_1 = 0;
        y_400_m_minus_1 = 0;
      end
    
      % Calculate the angle for 800 nm
      angle_800_m_minus_1 = asin(-lambda_800 / d + sin(alpha_i));
      if isreal(angle_800_m_minus_1)
        x_800_m_minus_1 = cos(angle_800_m_minus_1);
        y_800_m_minus_1 = sin(angle_800_m_minus_1);
      else
        x_800_m_minus_1 = 0;
        y_800_m_minus_1 = 0;
      end
    
      % --- NEW: Negative Second-order diffraction (m=-2) ---
    
      % Calculate the angle for 400 nm
      angle_400_m_minus_2 = asin(-2 * lambda_400 / d + sin(alpha_i));
      if isreal(angle_400_m_minus_2)
        x_400_m_minus_2 = cos(angle_400_m_minus_2);
        y_400_m_minus_2 = sin(angle_400_m_minus_2);
      else
        x_400_m_minus_2 = 0;
        y_400_m_minus_2 = 0;
      end
    
      % Calculate the angle for 800 nm
      angle_800_m_minus_2 = asin(-2 * lambda_800 / d + sin(alpha_i));
      if isreal(angle_800_m_minus_2)
        x_800_m_minus_2 = cos(angle_800_m_minus_2);
        y_800_m_minus_2 = sin(angle_800_m_minus_2);
      else
        x_800_m_minus_2 = 0;
        y_800_m_minus_2 = 0;
      end
    
      % --- Plotting ---
    
      % Set background to cyan
      whitebg('c');
    
      % Set plot limits for a good view
      axis([-1.2 1.2 -1.2 1.2]);
    
      % Hold on to plot multiple lines
      hold on;
    
      % Plot the vertical dotted diffraction grating at x=0
      plot([0, 0], [-1.2, 1.2], 'r:', 'LineWidth', 2);
    
      % Plot the normal line to the grating (x-axis)
      plot([-1.2, 1.2], [0, 0], 'k--', 'LineWidth', 1);
    
      % Plot incident and zero-order beams
      plot([x_incident_end, 0], [y_incident_end, 0], 'k-', 'LineWidth', 2);
      plot([0, x_zero], [0, y_zero], 'k-', 'LineWidth', 2);
    
      % Plot the first-order diffracted beams (m=1)
      plot([0, x_400_m1], [0, y_400_m1], 'b-', 'LineWidth', 2); % 400 nm, 1st order (blue)
      plot([0, x_800_m1], [0, y_800_m1], 'm-', 'LineWidth', 2); % 800 nm, 1st order (magenta)
    
      % Plot the second-order diffracted beam (m=2)
      % The second-order 400 nm beam is plotted half the length to show overlap.
      plot([0, 0.5*x_400_m2], [0, 0.5*y_400_m2], 'c-', 'LineWidth', 2); % 400 nm, 2nd order (cyan)
    
      % Plot the 800 nm, second-order beam
      plot([0, x_800_m2], [0, y_800_m2], 'y-', 'LineWidth', 2); % 800 nm, 2nd order (yellow)
    
      % Plot the negative first-order diffracted beams (m=-1)
      plot([0, x_400_m_minus_1], [0, y_400_m_minus_1], 'b-', 'LineWidth', 2); % 400 nm, -1st order (green)
      plot([0, x_800_m_minus_1], [0, y_800_m_minus_1], 'm-', 'LineWidth', 2); % 800 nm, -1st order (yellow)
    
      % --- NEW: Plot the negative second-order diffracted beams (m=-2) ---
      % The second-order 400 nm beam is plotted half the length to show overlap.
      plot([0, 0.5*x_400_m_minus_2], [0, 0.5*y_400_m_minus_2], 'c-', 'LineWidth', 2); % 400 nm, -2nd order (blue)
    
      % Plot the 800 nm, negative second-order beam
      plot([0, x_800_m_minus_2], [0, y_800_m_minus_2], 'y-', 'LineWidth', 2); % 800 nm, -2nd order (magenta)
    
      % --- Labels and Title ---
    
      % Label the vertical dotted line as "Transmission Grating"
      text(-0.05, 1.1, 'Transmission Grating', 'Color', 'r', 'HorizontalAlignment', 'right', 'FontSize', 12);
    
      % Label the incident and zero-order beams
      text(x_incident_end, y_incident_end - 0.05, 'Incident Beam', 'Color', 'b', 'FontSize', 12);
      text(x_zero, y_zero - 0.05, 'Zero Order', 'Color', 'b', 'FontSize', 12);
    
      % Label the diffracted beams
      text(x_400_m1, y_400_m1, '400 nm (m=1)', 'Color', 'm', 'FontSize', 12);
      text(x_800_m1, y_800_m1, '800 nm (m=1)', 'Color', 'b', 'FontSize', 12);
      text(0.5*x_400_m2, 0.5*y_400_m2 - 0.05, '400 nm (m=2)', 'Color', 'c', 'FontSize', 12);
      text(x_800_m2, y_800_m2, '800 nm (m=2)', 'Color', 'b', 'FontSize', 12);
    
      % Label the negative first-order diffracted beams
      text(x_400_m_minus_1, y_400_m_minus_1, '400 nm (m=-1)', 'Color', 'm', 'FontSize', 12);
      text(x_800_m_minus_1, y_800_m_minus_1, '800 nm (m=-1)', 'Color', 'b', 'FontSize', 12);
    
      % --- NEW: Label the negative second-order diffracted beams ---
      text(0.5*x_400_m_minus_2, 0.5*y_400_m_minus_2 + 0.05, '400 nm (m=-2)', 'Color', 'c', 'FontSize', 12);
      text(x_800_m_minus_2, y_800_m_minus_2, '800 nm (m=-2)', 'Color', 'b', 'FontSize', 12);
    
      % Add title and axis labels
      title('Diffraction Grating Order Overlap (400 nm and 800 nm)', 'FontSize', 14);
      xlabel('X-axis', 'FontSize', 14);
      ylabel('Y-axis', 'FontSize', 14);
    
      % Turn off hold
      hold off;
    

Discussions