Experimental Concerns for Beam Measurement

Scott Prahl

Sept 2023

Many mistakes can be made when making a beam measurement. This notebook collects a number of these.

The ISO 11146 standard recommends masking the image with a rotated rectangular mask around the center of the image. This notebook explains how that was implemented and then shows some results for artifically generated images of non-circular Gaussian beams. As noise increases, the first-order parameters (beam center) are robust, but the second-order parameters (diameters) are shown to be much more sensitive to image noise.

[1]:
import imageio.v3 as iio
import numpy as np
import matplotlib.pyplot as plt
import laserbeamsize as lbs

def side_by_side_plot(h,v,xc,yc,dx,dy,phi,noise=0):
    """Creates plot of original and of fitted beam."""
    test = lbs.create_test_image(h,v,xc,yc,dx,dy,phi,noise=noise)
    xc_found, yc_found, dx_found, dy_found, phi_found = lbs.beam_size(test, iso_noise=True)

    plt.subplots(1,2,figsize=(12,5))
    plt.subplot(1,2,1)
    plt.imshow(test,cmap=lbs.create_plus_minus_cmap(test))
    plt.plot(xc,yc,'ob',markersize=2)
    plt.title('Original (%d,%d), dx=%.0f, dy=%.0f, $\phi$=%.0f°' % (xc,yc,dx,dy,np.degrees(phi)))

    plt.subplot(1,2,2)
    plt.imshow(test,cmap='gist_ncar')
    xp,yp = lbs.rotated_rect_arrays(xc_found, yc_found, dx_found, dy_found, phi_found)
    plt.plot(xp,yp,':y')
    xp,yp = lbs.ellipse_arrays(xc_found, yc_found, dx_found, dy_found, phi_found)
    plt.plot(xp,yp,':b')
    plt.plot(xc_found,yc_found,'ob',markersize=2)
    plt.title('Found (%d,%d), dx=%.0f, dy=%.0f, $\phi$=%.0f°' % (xc_found,yc_found,dx_found,dy_found,np.degrees(phi_found)))


pixel_size_µm = 3.75               # microns
repo = "https://github.com/scottprahl/laserbeamsize/raw/master/docs/"

Image of beam is saturated

[2]:
sat_img = iio.imread(repo + "k-200mm.png")
lbs.plot_image_analysis(sat_img, pixel_size=pixel_size_µm)
_images/05-Experiment_3_0.png

Image of beam is too small

To illustrate we create a 20x40 pixel beam in a 600x600 image and a 200x200 image. 2% noise is added to the image and we try to extract the beam parameters. The beam in the larger image fails and the smaller image succeeds.

[3]:
h,v,xc,yc,dx,dy,phi = 600, 600, 100, 100, 20, 40, 0
side_by_side_plot(h,v,xc,yc,dx,dy,phi,noise=5)
h,v,xc,yc,dx,dy,phi = 200, 200, 100, 100, 20, 40, 0
side_by_side_plot(h,v,xc,yc,dx,dy,phi,noise=5)

_images/05-Experiment_5_0.png
_images/05-Experiment_5_1.png

Image of beam is too large

The algorithm does not do too badly with these. Here artifical beams 250x250 pixels in size are placed in 250x250 images or 900x900 images. No noise is added. The beam in the small image results in 192x181 pixel beam, while the larger image generates a 245x245 pixel beam.

[4]:
h,v,xc,yc,dx,dy,phi = 250, 250, 150, 150, 250, 250, 0
side_by_side_plot(h,v,xc,yc,dx,dy,phi,noise=0)
h,v,xc,yc,dx,dy,phi = 900, 900, 450, 450, 250, 250, 0
side_by_side_plot(h,v,xc,yc,dx,dy,phi,noise=0)

_images/05-Experiment_7_0.png
_images/05-Experiment_7_1.png

Image of beam is too close to margins

[5]:
margin_img = iio.imread(repo+"TEM00_300mm.pgm")>>4

options = {'pixel_size': pixel_size_µm, 'units': "µm"}
lbs.plot_image_analysis(margin_img, **options)

# works a bit better with iso_noise=False
lbs.plot_image_analysis(margin_img, **options, iso_noise=False)
_images/05-Experiment_9_0.png
_images/05-Experiment_9_1.png

Image has artifacts, example 1

With the standard color map it is not obvious why the vertical dimension is nuts.

[6]:
art1_img = iio.imread(repo+"TEM00_150mm.pgm")

options = {'pixel_size': pixel_size_µm, 'units': "µm", 'iso_noise':True, 'cmap':'gist_ncar'}
lbs.plot_image_analysis(art1_img, **options)
_images/05-Experiment_11_0.png

Cropping the beam allows a reasonable fit to be obtained. However, in the image on the top right below, the integration rectangle extends beyond the image. Thus the result is not ISO 11146 compliant.

[7]:
options = {'pixel_size': pixel_size_µm, 'units': "µm", 'iso_noise':True, 'cmap':'gist_ncar'}
lbs.plot_image_analysis(art1_img[420:620,550:750], **options)
_images/05-Experiment_13_0.png

Image has artifacts, 2

Here a small artifact above the primary beam image (perhaps a reflection) dramatically changes the vertical beam diameter.

[8]:
options = {'pixel_size': pixel_size_µm, 'units': "µm", 'cmap':'gist_ncar'}
art2_img = iio.imread(repo+"sb_259mm_10.pgm")
lbs.plot_image_analysis(art2_img, **options)
_images/05-Experiment_15_0.png

Cropping the image produces much more reasonable values for the diameters.

[9]:
lbs.plot_image_analysis(art2_img[365:565,543:743], **options)
_images/05-Experiment_17_0.png

Image of beam has too much noise

The background is nearly half of the central beam intensity. Although subtracting the background kind of worked, the offset affects the fitted gaussian and makes the diameter too wide. In this case, assuming iso_noise=True fails but when turned off, a reasonable fit is achieved.

[10]:
noise_img = iio.imread(repo+"k-800mm.png")
options = {'pixel_size': pixel_size_µm, 'units': "µm", 'cmap':lbs.create_plus_minus_cmap(noise_img)}
lbs.plot_image_analysis(noise_img, **options, iso_noise=True)
lbs.plot_image_analysis(noise_img, **options, iso_noise=False)
_images/05-Experiment_19_0.png
_images/05-Experiment_19_1.png
[ ]: