Mueller Matrix Examples

Scott Prahl

Feb 2026

Here are examples of Mueller matrices that can be used for propagating polarized light through a system.

  • Linear Polarizers

  • Quarter Wave Plates

  • Half Wave Plates

  • Fresnel reflection/transmission

[1]:
%config InlineBackend.figure_format = 'retina'

import sys
import numpy as np
import matplotlib.pyplot as plt

if sys.platform == "emscripten":
    import micropip

    await micropip.install("pypolar")

from pypolar import fresnel
from pypolar import jones
from pypolar import mueller
from pypolar import visualization as vis

Linear Polarizers

Kliger Appendix B page 285

[2]:
for theta in [0, 45, 90, -45]:
    print("Mueller matrix for perfect linear polarizer at angle theta=%.1f°" % theta)
    L = mueller.op_linear_polarizer(np.radians(theta))
    print(np.round(L, 3))
    print()
Mueller matrix for perfect linear polarizer at angle theta=0.0°
[[0.5 0.5 0.  0. ]
 [0.5 0.5 0.  0. ]
 [0.  0.  0.  0. ]
 [0.  0.  0.  0. ]]

Mueller matrix for perfect linear polarizer at angle theta=45.0°
[[0.5 0.  0.5 0. ]
 [0.  0.  0.  0. ]
 [0.5 0.  0.5 0. ]
 [0.  0.  0.  0. ]]

Mueller matrix for perfect linear polarizer at angle theta=90.0°
[[ 0.5 -0.5  0.   0. ]
 [-0.5  0.5 -0.   0. ]
 [ 0.  -0.   0.   0. ]
 [ 0.   0.   0.   0. ]]

Mueller matrix for perfect linear polarizer at angle theta=-45.0°
[[ 0.5  0.  -0.5  0. ]
 [ 0.   0.  -0.   0. ]
 [-0.5 -0.   0.5  0. ]
 [ 0.   0.   0.   0. ]]

Quarter-Wave Plates

Kliger Appendix B, page 287

[3]:
for theta in [0, 90, 45, -45]:
    print("Mueller matrix for quarter-wave plate with fast axis at angle theta=", theta)
    L = mueller.op_quarter_wave_plate(np.radians(theta))
    print(np.round(L, 3))
    print("Should be the same as")
    L = mueller.op_retarder(np.radians(theta), np.pi / 2)
    print(np.round(L, 3))
    print()
Mueller matrix for quarter-wave plate with fast axis at angle theta= 0
[[ 1.  0.  0.  0.]
 [ 0.  1.  0. -0.]
 [ 0.  0.  0.  1.]
 [ 0.  0. -1.  0.]]
Should be the same as
[[ 1.  0.  0.  0.]
 [ 0.  1.  0. -0.]
 [ 0.  0.  0.  1.]
 [ 0.  0. -1.  0.]]

Mueller matrix for quarter-wave plate with fast axis at angle theta= 90
[[ 1.  0.  0.  0.]
 [ 0.  1. -0. -0.]
 [ 0. -0.  0. -1.]
 [ 0.  0.  1.  0.]]
Should be the same as
[[ 1.  0.  0.  0.]
 [ 0.  1. -0. -0.]
 [ 0. -0.  0. -1.]
 [ 0.  0.  1.  0.]]

Mueller matrix for quarter-wave plate with fast axis at angle theta= 45
[[ 1.  0.  0.  0.]
 [ 0.  0.  0. -1.]
 [ 0.  0.  1.  0.]
 [ 0.  1. -0.  0.]]
Should be the same as
[[ 1.  0.  0.  0.]
 [ 0.  0.  0. -1.]
 [ 0.  0.  1.  0.]
 [ 0.  1. -0.  0.]]

Mueller matrix for quarter-wave plate with fast axis at angle theta= -45
[[ 1.  0.  0.  0.]
 [ 0.  0. -0.  1.]
 [ 0. -0.  1.  0.]
 [ 0. -1. -0.  0.]]
Should be the same as
[[ 1.  0.  0.  0.]
 [ 0.  0. -0.  1.]
 [ 0. -0.  1.  0.]
 [ 0. -1. -0.  0.]]

Half-Wave Plates

Kliger Appendix B, page 286

[4]:
for theta in [0, 90, 45, -45]:
    print("Mueller matrix for half-wave plate with fast axis at angle theta=", theta)
    L = mueller.op_half_wave_plate(np.radians(theta))
    print(np.round(L, 3))
    print("Should be the same as")
    L = mueller.op_retarder(np.radians(theta), np.pi)
    print(np.round(L, 3))
    print()
Mueller matrix for half-wave plate with fast axis at angle theta= 0
[[ 1.  0.  0.  0.]
 [ 0.  1.  0.  0.]
 [ 0.  0. -1.  0.]
 [ 0.  0.  0. -1.]]
Should be the same as
[[ 1.  0.  0.  0.]
 [ 0.  1.  0. -0.]
 [ 0.  0. -1.  0.]
 [ 0.  0. -0. -1.]]

Mueller matrix for half-wave plate with fast axis at angle theta= 90
[[ 1.  0.  0.  0.]
 [ 0.  1. -0.  0.]
 [ 0. -0. -1.  0.]
 [ 0.  0.  0. -1.]]
Should be the same as
[[ 1.  0.  0.  0.]
 [ 0.  1. -0. -0.]
 [ 0. -0. -1. -0.]
 [ 0.  0.  0. -1.]]

Mueller matrix for half-wave plate with fast axis at angle theta= 45
[[ 1.  0.  0.  0.]
 [ 0. -1.  0.  0.]
 [ 0.  0.  1.  0.]
 [ 0.  0.  0. -1.]]
Should be the same as
[[ 1.  0.  0.  0.]
 [ 0. -1.  0. -0.]
 [ 0.  0.  1.  0.]
 [ 0.  0. -0. -1.]]

Mueller matrix for half-wave plate with fast axis at angle theta= -45
[[ 1.  0.  0.  0.]
 [ 0. -1. -0.  0.]
 [ 0. -0.  1.  0.]
 [ 0.  0.  0. -1.]]
Should be the same as
[[ 1.  0.  0.  0.]
 [ 0. -1. -0.  0.]
 [ 0. -0.  1.  0.]
 [ 0. -0. -0. -1.]]

Fresnel Reflection/Transmission

Note that these Mueller matrices include the change in perspective needed for the reflected beam.

Normal incidence

\[\begin{split}M_R(0) = {(n-1)^2\over(n+1)^2} \left[ \begin{array}{cccc} 1 & 0 & 0 & 0\\ 0 & 1 & 0 & 0\\ 0 & 0 & -1& 0\\ 0 & 0 & 0 &-1\\ \end{array}\right] \qquad\mbox{and}\qquad M_T(0) = {4n\over(n+1)^2} \left[ \begin{array}{cccc} 1 & 0 & 0 & 0\\ 0 & 1 & 0 & 0\\ 0 & 0 & 1& 0\\ 0 & 0 & 0 &1\\ \end{array}\right]\end{split}\]
[5]:
MR = mueller.op_fresnel_reflection(1.5, 0)
print("M_R=")
print(MR)
M_R=
[[ 0.04  0.    0.    0.  ]
 [ 0.    0.04  0.    0.  ]
 [ 0.    0.   -0.04  0.  ]
 [ 0.    0.    0.   -0.04]]
[6]:
print(fresnel.t_per_amplitude(1.5, 0))
print(fresnel.t_par_amplitude(1.5, 0))

print(fresnel.T_per(1.5, 0))
print(fresnel.T_par(1.5, 0))


MT = mueller.op_fresnel_transmission(1.5, 0)
print("M_T=")
print(MT)
0.8
0.8
0.9600000000000002
0.9600000000000002
M_T=
[[0.64 0.   0.   0.  ]
 [0.   0.64 0.   0.  ]
 [0.   0.   0.64 0.  ]
 [0.   0.   0.   0.64]]

Light incident at Brewster’s angle

Brewster’s angle for a dielectric material is

\[\tan\theta_B = m\]

and reflected field parallel to the plane of incidence becomes zero.

The special case for reflection at Brewster’s angle is

\[\begin{split}M_R(\theta_B) = {1\over2}\cos^2 2\theta_B \left[ \begin{array}{cccc} 1 & -1 & 0 & 0\\ -1 & 1 & 0 & 0\\ 0 & 0 & 0 & 0\\ 0 & 0 & 0 & 0\\ \end{array}\right]\end{split}\]
[7]:
m = 1.5
thetaB = np.arctan(m)
print("theta_B = %.3f°" % np.degrees(thetaB))
MR = mueller.op_fresnel_reflection(1.5, thetaB)
print("M_R=")
print(np.round(MR, 4))

print("Matrix at Brewster's angle should be")
const = 0.5 * np.cos(2 * thetaB) ** 2
MR = const * np.array([[1, -1, 0, 0], [-1, 1, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]])
print(np.round(MR, 4))
theta_B = 56.310°
M_R=
[[ 0.074 -0.074  0.     0.   ]
 [-0.074  0.074  0.     0.   ]
 [ 0.     0.    -0.     0.   ]
 [ 0.     0.     0.    -0.   ]]
Matrix at Brewster's angle should be
[[ 0.074 -0.074  0.     0.   ]
 [-0.074  0.074  0.     0.   ]
 [ 0.     0.     0.     0.   ]
 [ 0.     0.     0.     0.   ]]

Goldstein gives the following for the Mueller matrix for transmitted light incident at Brewster’s angle

\[\begin{split}M_T(\theta_B) = {1\over2} \left[ \begin{array}{cccc} \sin^22\theta_B+1 & \sin^22\theta_B-1 & 0 & 0\\ \sin^22\theta_B-1 & \sin^22\theta_B+1 & 0 & 0\\ 0 & 0 & 2\sin2\theta_B& 0\\ 0 & 0 & 0 &2\sin2\theta_B\\ \end{array}\right]\end{split}\]
[8]:
m = 1.5
thetaB = np.arctan(m)
print("Brewster's angle is %.3f°" % (np.degrees(thetaB)))
print()

MT1 = mueller.op_fresnel_transmission(m, thetaB)
print("(direct) M_T=")
print(MT1)
print()

print("At Brewster's angle the matrix should be")
a = np.sin(2 * thetaB) ** 2 + 1
b = np.sin(2 * thetaB) ** 2 - 1
c = 2 * np.sin(2 * thetaB)
MT = 0.5 * np.array([[a, b, 0, 0], [b, a, 0, 0], [0, 0, c, 0], [0, 0, 0, c]])
print(MT)
Brewster's angle is 56.310°

(direct) M_T=
[[0.41157133 0.03287311 0.         0.        ]
 [0.03287311 0.41157133 0.         0.        ]
 [0.         0.         0.41025641 0.        ]
 [0.         0.         0.         0.41025641]]

At Brewster's angle the matrix should be
[[ 0.9260355  -0.0739645   0.          0.        ]
 [-0.0739645   0.9260355   0.          0.        ]
 [ 0.          0.          0.92307692  0.        ]
 [ 0.          0.          0.          0.92307692]]

Light incident at 45° to the surface

This is the other special case where the Fresnel formulas simplify. Goldstein 2003 gives

\[\theta_r = 45^\circ\]

thus

\[\begin{split}M_R(\theta_r) = {1-\sin2\theta_r\over(1+\sin2\theta_r)^2} \left[ \begin{array}{cccc} 1 & \sin2\theta_r & 0 & 0\\ \sin2\theta_r & 1 & 0 & 0\\ 0 & 0 & -\cos2\theta_r & 0\\ 0 & 0 & 0 & -\cos2\theta_r\\ \end{array}\right]\end{split}\]

which may be off by a minus sign in the lower two diagonal elements?

[9]:
m = 1.5
thetai = np.pi / 4

MR = mueller.op_fresnel_reflection(1.5, thetai)
print("M_R=")
print(MR)

print("Matrix at 45° angle should be")
thetar = np.arcsin(np.sin(thetai) / m)
const = (1 - np.sin(2 * thetar)) / (1 + np.sin(2 * thetar)) ** 2
a = np.sin(2 * thetar)
b = -np.cos(2 * thetar)
MR = const * np.array([[1, a, 0, 0], [a, 1, 0, 0], [0, 0, b, 0], [0, 0, 0, b]])
print(MR)
M_R=
[[ 0.05023991 -0.04177345  0.          0.        ]
 [-0.04177345  0.05023991  0.          0.        ]
 [ 0.          0.         -0.02791106  0.        ]
 [ 0.          0.          0.         -0.02791106]]
Matrix at 45° angle should be
[[ 0.05023991  0.04177345  0.          0.        ]
 [ 0.04177345  0.05023991  0.          0.        ]
 [ 0.          0.         -0.02791106  0.        ]
 [ 0.          0.          0.         -0.02791106]]

Optical isolator

[10]:
A = mueller.stokes_right_circular()  # incident light
B = mueller.op_linear_polarizer(np.pi / 4)  # polarizer at 45°
C = mueller.op_quarter_wave_plate(0)  # QWP with fast axis horizontal
D = mueller.op_mirror()  # first surface mirror
E = mueller.op_quarter_wave_plate(0)  # QWP still has fast axis horizontal
F = mueller.op_linear_polarizer(-np.pi / 4)  # now at -45° because travelling backwards
[11]:
# net result is no light
mueller.intensity(F @ E @ D @ C @ B @ A)
[11]:
np.float64(9.37349864163661e-34)
[12]:
F @ E @ D @ C @ B @ A
[12]:
array([ 9.37349864e-34,  5.73961255e-50, -9.37349864e-34,  0.00000000e+00])
[ ]: