{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Using the Mueller module \n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"In this notebook, we demonstrate how to use the Mueller module, which defines the `MuellerMatrix` and `StokesVector` classes and various operations on them.\n",
"\n",
"The first thing, of course, is to import the package and some other packages that we will be using. We will be creating some random matrices and vectors, so we need `random`, and we will be graphing a few things, so we need `maptplotlib.pyplot`."
]
},
{
"cell_type": "code",
"execution_count": 1,
"metadata": {},
"outputs": [],
"source": [
"from pySCATMECH.mueller import *\n",
"import random \n",
"import matplotlib.pyplot as plt"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Mueller matrices\n",
"\n",
"The class `MuellerMatrix` is used for handling Mueller matrices. Here we show several ways one can create a unit Mueller matrix. The `JonesMueller()` function converts a 2 x 2 complex Jones matrix into a Mueller matrix. And `MuellerUnit()` returns a unit Mueller matrix."
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"[[1. 0. 0. 0.]\n",
" [0. 1. 0. 0.]\n",
" [0. 0. 1. 0.]\n",
" [0. 0. 0. 1.]]\n"
]
}
],
"source": [
"m1 = MuellerMatrix([[1,0,0,0],[0,1,0,0],[0,0,1,0],[0,0,0,1]])\n",
"m2 = MuellerMatrix([1,0,0,0],[0,1,0,0],[0,0,1,0],[0,0,0,1])\n",
"m3 = MuellerMatrix(1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1)\n",
"m4 = JonesMueller([[1,0],[0,1]])\n",
"m5 = MuellerUnit()\n",
"print(m5)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"We can check to see that these are valid matrices. The `valid` method tests whether a Mueller matrix maps the set of valid Stokes vectors onto itself. The `physically_valid` method tests whether a Mueller matrix is a convex sum of Jones-Mueller matrices. The latter is a more stringent test of whether the matrix is realizable."
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"True\n",
"True\n"
]
}
],
"source": [
"print(m1.valid())\n",
"print(m1.physically_valid())"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"But, a random matrix is not necessarily valid. In fact, it probably isn't!"
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Number valid() is True: 1\n",
"Number physically valid() is True: 0\n"
]
}
],
"source": [
"# Returns a random number with a normal distribution...\n",
"ran = lambda : random.gauss(0,1)\n",
"\n",
"# Create 20 random matrices...\n",
"m1 = [MuellerMatrix([[ran(), ran(), ran(), ran()],\n",
" [ran(), ran(), ran(), ran()],\n",
" [ran(), ran(), ran(), ran()],\n",
" [ran(), ran(), ran(), ran()]]) for i in range(20)]\n",
"\n",
"# See if they are valid...\n",
"print(\"Number valid() is True:\", sum([m.valid() for m in m1]))\n",
"print(\"Number physically valid() is True:\", sum([m.physically_valid() for m in m1]))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"A Mueller matrix made from a random Jones matrix, however, always yields a valid Mueller matrix."
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Number value() is True: 20\n",
"Number physically valid() is True: 20\n"
]
}
],
"source": [
"# Returns a random complex number with a normal distribution...\n",
"ranc = lambda : random.gauss(0,1)+random.gauss(0,1)*1j\n",
"\n",
"# Create 20 random Jones-Mueller matrices...\n",
"m1 = [JonesMueller([[ranc(), ranc()], [ranc(), ranc()]]) for i in range(20)]\n",
"\n",
"# See if they are valid...\n",
"print(\"Number value() is True:\", sum([m.valid() for m in m1]))\n",
"print(\"Number physically valid() is True:\", sum([m.physically_valid() for m in m1]))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"To make a random depolarizing Mueller matrix, we average some random Jones-Mueller matrices:"
]
},
{
"cell_type": "code",
"execution_count": 6,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"[[ 0.79126519 0.51754966 0.04396498 -0.09197144]\n",
" [-0.21857972 -0.10891561 0.03399935 0.04409256]\n",
" [ 0.24109773 0.27199561 0.06684414 -0.02241909]\n",
" [ 0.31260027 0.21946993 0.16903187 -0.02210762]]\n",
"m is a valid Stokes to Stokes mapper: True\n",
"m is the sum of Jones-Mueller matrices: True\n"
]
}
],
"source": [
"def RandomMuellerMatrix(n):\n",
" \"\"\"\n",
" Creates a random Mueller matrix by averaging `n` Jones-Mueller matrices.\n",
" \"\"\"\n",
" ranc = lambda : (random.gauss(0,1)+random.gauss(0,1)*1j)/2\n",
" return sum([JonesMueller([[ranc(),ranc()],[ranc(),ranc()]]) for i in range(n)])/n\n",
"\n",
"m = RandomMuellerMatrix(4)\n",
"print(m)\n",
"print(\"m is a valid Stokes to Stokes mapper:\",m.valid())\n",
"print(\"m is the sum of Jones-Mueller matrices:\",m.physically_valid())\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Stokes Vectors\n",
"\n",
"\n",
"The class `StokesVector` is used for handling Stokes vectors.\n",
"We can create a Stokes vector a several ways. The `Polarization` function provides a means for generating arbitrary polarizations by name or parameter. (Note that SCATMECH's convention for the signs of the Stokes vector elements differs from some others.)"
]
},
{
"cell_type": "code",
"execution_count": 7,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Unpolarized Stokes vector: StokesVector(1,0,0,0)\n",
"Unpolarized Stokes vector: StokesVector(1,0,0,0)\n",
"s-polarized unit polarization from a Jones vector: StokesVector(1.0,1.0,0.0,0.0)\n",
"p-polarized unit Stokes vector: StokesVector(1,-1,0,0)\n",
"s-polarized unit Stokes vector: StokesVector(1,1,0,0)\n",
"Left-handed circularly polarized unit Stokes vector: StokesVector(1,0,0,1)\n",
"Right-handed circularly polarized unit Stokes vector with intensity 2: StokesVector(2,0,0,-2)\n",
"Unpolarized Stokes vector: StokesVector(1,0,0,0)\n",
"Unpolarized Stokes vector: StokesVector(1,0,0,0)\n",
"Linear polarization at 45 degrees: StokesVector(1.0,6.123233995736766e-17,1.0,0.0)\n",
"Elliptically polarized radiation: StokesVector(1.0,0.2869652992419897,0.7102640395405222,0.6427876096865393)\n",
"Partially polarized radiation: StokesVector(1.0,0.8,0.0,0.0)\n",
"Partially polarized elliptical polarized radiation with intensity 3:\n",
" StokesVector(3.0,0.6026271284081782,1.4915544830350964,1.3498539803417322)\n"
]
}
],
"source": [
"print(\"Unpolarized Stokes vector:\", StokesVector((1,0,0,0)) )\n",
"\n",
"print(\"Unpolarized Stokes vector:\", StokesVector(1,0,0,0) )\n",
"\n",
"print(\"s-polarized unit polarization from a Jones vector:\", JonesStokes((1.,0.)) )\n",
"\n",
"print(\"p-polarized unit Stokes vector:\", Polarization('p') )\n",
"\n",
"print(\"s-polarized unit Stokes vector:\", Polarization(state = 's') )\n",
"\n",
"print(\"Left-handed circularly polarized unit Stokes vector:\", Polarization(\"L\") )\n",
"\n",
"print(\"Right-handed circularly polarized unit Stokes vector with intensity 2:\", Polarization(\"R\", I=2) )\n",
"\n",
"print(\"Unpolarized Stokes vector:\", Polarization(\"U\") )\n",
"\n",
"print(\"Unpolarized Stokes vector:\", Polarization('s', DOP=0) )\n",
"\n",
"print(\"Linear polarization at 45 degrees:\", Polarization(angle = 45*deg) )\n",
"\n",
"print(\"Elliptically polarized radiation:\", Polarization(angle = 34*deg, ellipticity = 20*deg) )\n",
"\n",
"print(\"Partially polarized radiation:\", Polarization(\"S\", DOP = 0.8) )\n",
"\n",
"print(\"Partially polarized elliptical polarized radiation with intensity 3:\\n\", \n",
" Polarization(angle = 34*deg, ellipticity = 20*deg, DOP = 0.7, I = 3) )"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Note that polarization sensitivity can also be expressed as a Stokes vector. However, there is often a factor of two that enters for all but unpolarized sensitivity. That is, a perfect polarizer transmits 50 % of unpolarized radiation. We can apply `senstivity = True` to the `Polarization()` function, or use a `Sensitivity` function."
]
},
{
"cell_type": "code",
"execution_count": 8,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Signal for p-polarization: 1.0\n",
"Signal for s-polarization: 0.0\n"
]
}
],
"source": [
"# Only sensitive to p-polarization\n",
"# The following two statements are equivalent...\n",
"sens = Polarization('p', sensitivity = True)\n",
"sens = Sensitivity('p')\n",
"\n",
"print('Signal for p-polarization:',sens @ Polarization('p'))\n",
"print('Signal for s-polarization:',sens @ Polarization('s'))\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Sensitivity does not need to be full polarizing. By setting `DOP` in the range [0,1], sensitivity to the orthogonal polarization can be non-zero."
]
},
{
"cell_type": "code",
"execution_count": 9,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"sens = StokesVector(0.6,-0.4,0.0,0.0)\n",
"Signal for p-polarization: 1.0\n",
"Signal for s-polarization: 0.19999999999999996\n"
]
}
],
"source": [
"sens = Sensitivity('p',DOP=.8)\n",
"print('sens = ', sens)\n",
"\n",
"print('Signal for p-polarization:',sens @ Polarization('p'))\n",
"print('Signal for s-polarization:',sens @ Polarization('s'))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"In a manner similar to what we did with Mueller matrices, we can create a random Stokes vector by averaging a number of Stokes \n",
"vectors created from Jones vectors. For a single Jones vector, the Stokes vector is depolarized. For more than one, the Stokes vector is partially polarized or unpolarized. We illustrate that by plotting the degree of polarization (using the `DOP()` method) as a function of the number of Jones-Stokes vectors we add."
]
},
{
"cell_type": "code",
"execution_count": 10,
"metadata": {},
"outputs": [
{
"data": {
"image/svg+xml": [
"\n",
"\n",
"\n"
],
"text/plain": [
"