(************** Content-type: application/mathematica ************** Mathematica-Compatible Notebook This notebook can be used with any Mathematica-compatible application, such as Mathematica, MathReader or Publicon. The data for the notebook starts with the line containing stars above. To get the notebook into a Mathematica-compatible application, do one of the following: * Save the data starting with the line of stars above into a file with a name ending in .nb, then open the file inside the application; * Copy the data starting with the line of stars above to the clipboard, then use the Paste menu command inside the application. Data for notebooks contains only printable 7-bit ASCII and can be sent directly in email or through ftp in text mode. Newlines can be CR, LF or CRLF (Unix, Macintosh or MS-DOS style). NOTE: If you modify the data for this notebook not in a Mathematica- compatible application, you must delete the line below containing the word CacheID, otherwise Mathematica-compatible applications may try to use invalid cache data. For more information on notebooks and Mathematica-compatible applications, contact Wolfram Research: web: http://www.wolfram.com email: info@wolfram.com phone: +1-217-398-0700 (U.S.) Notebook reader applications are available free of charge from Wolfram Research. *******************************************************************) (*CacheID: 232*) (*NotebookFileLineBreakTest NotebookFileLineBreakTest*) (*NotebookOptionsPosition[ 21386, 675]*) (*NotebookOutlinePosition[ 22282, 708]*) (* CellTagsIndexPosition[ 22238, 704]*) (*WindowFrame->Normal*) Notebook[{ Cell[TextData[{ "Memo to: HETE Group\nSubject: Attitude Determination\nFrom: John Doty\n\ Date: 10/19/93\nHETE Memo #: 106\n\n", StyleBox["This memo is available as an interactive ", FontSize->12, FontWeight->"Plain"], StyleBox["Mathematica", FontSize->12, FontWeight->"Plain", FontSlant->"Italic"], StyleBox[" notebook: open /hete/memo/source/LinTrigFunc.ma.", FontSize->12, FontWeight->"Plain"] }], "Subsection", ImageRegion->{{-0, 1}, {0, 1}}], Cell[TextData[{ "Fast, simple least squares determination of spacecraft attitude matrices \ directly from vector star observations: A ", StyleBox["Mathematica", FontSlant->"Italic"], " notebook." }], "Section", ImageRegion->{{-0, 1}, {0, 1}}], Cell["Needs[ \"LinearAlgebra`Master`\" ]", "Input", InitializationCell->True, ImageRegion->{{-0, 1}, {0, 1}}], Cell[CellGroupData[{Cell["\<\ First, define functions for projecting points in a plane tangent to \ a sphere at the z axis onto the sphere and vice versa. Points on the sphere \ are represented by normalized 3-vectors, while points in the tangent plane \ are represented by 2-vectors. Note that this mapping corresponds directly to \ what happens in a pinhole camera, so it is a good model for how an image of \ the sky corresponds to the sky itself (lens distortion is neglected).\ \>", \ "Text", ImageRegion->{{-0, 1}, {0, 1}}], Cell["\<\ PlaneToSphere[ { x_, y_ } ] := \tNormalize[ {x, y, 1 } ] \ \>", "Input", InitializationCell->True, ImageRegion->{{-0, 1}, {0, 1}}], Cell["SphereToPlane[ {x_,y_,z_} ] := { x / z, y / z }", "Input", InitializationCell->True, ImageRegion->{{-0, 1}, {0, 1}}]}, Open]], Cell[CellGroupData[{Cell[TextData[{ "We'll want these functions to work on lists of vectors. The convention \ here is that a list of vectors will literally have the structure \"list of \ vectors\" in ", StyleBox["Mathematica", FontSlant->"Italic"], ": thus, when we want to think of a matrix as a collection of vectors, the \ vectors themselves will correspond to the rows of the matrix." }], "Text", ImageRegion->{{-0, 1}, {0, 1}}], Cell["\<\ SphereToPlane[ m_ ] := \tMap[ SphereToPlane, m ] /; MatrixQ[ m ]\ \>", "Input", InitializationCell->True, ImageRegion->{{-0, 1}, {0, 1}}], Cell["\<\ PlaneToSphere[ m_ ] := \tMap[ PlaneToSphere, m ] /; MatrixQ[ m ]\ \>", "Input", InitializationCell->True, ImageRegion->{{-0, 1}, {0, 1}}]}, Open]], Cell[CellGroupData[{Cell["\<\ In three dimensions, there is a direct analogy between vectors and \ antisymmetric tensors: each has three degrees of freedom. Although the tensor \ is a more general concept, vectors are easier for humans to understand, so in \ physics we tend to use \"axial vectors\" instead of antisymmetric tensors. \ For purposes of putting a least squares fitting problem in matrix form, \ however, the matrix representation of the tensor is more convenient. The \ following function converts a vector into its associated antisymmetric \ tensor. Kids, be sure you are working in a three dimensional space before \ attempting this at home!\ \>", "Text", ImageRegion->{{-0, 1}, {0, 1}}], Cell["\<\ Tensorize[ {x_,y_,z_ } ] := { \t{ 0, -z, y }, \t{ z, 0, -x }, \t{ -y, x, 0 }}\ \>", "Input", InitializationCell->True, ImageRegion->{{-0, 1}, {0, 1}}]}, Open]], Cell[CellGroupData[{Cell["\<\ The dot product of an antisymmetric tensor with a vector is the \ same as the more familiar cross product:\ \>", "Text", ImageRegion->{{-0, 1}, {0, 1}}], Cell[CellGroupData[{Cell["Tensorize[ { a, b, c } ] . { d, e, f }", "Input", ImageRegion->{{-0, 1}, {0, 1}}], Cell[OutputFormData["\<\ {-(c*e) + b*f, c*d - a*f, -(b*d) + a*e}\ \>", \ "\<\ {-(c e) + b f, c d - a f, -(b d) + a e}\ \>"], "Output", ImageRegion->{{-0, 1}, {0, 1}}]}, Open]], Cell[CellGroupData[{Cell["Cross[ { a, b, c } , { d, e, f } ]", "Input", ImageRegion->{{-0, 1}, {0, 1}}], Cell[OutputFormData["\<\ {-(c*e) + b*f, c*d - a*f, -(b*d) + a*e}\ \>", \ "\<\ {-(c e) + b f, c d - a f, -(b d) + a e}\ \>"], "Output", ImageRegion->{{-0, 1}, {0, 1}}]}, Open]]}, Open]], Cell[CellGroupData[{Cell["\<\ To tensorize a list of vectors, we just stack the tensors atop one \ another:\ \>", "Text", ImageRegion->{{-0, 1}, {0, 1}}], Cell["\<\ Tensorize[ m_ ] := \tFlatten[ Map[ Tensorize, m ], 1 ] /; MatrixQ[ m ]\ \>", "Input", InitializationCell->True, ImageRegion->{{-0, 1}, {0, 1}}], Cell[CellGroupData[{Cell["Tensorize[ {{ a, b, c },{ d, e, f }} ] // MatrixForm", "Input", ImageRegion->{{-0, 1}, {0, 1}}], Cell[OutputFormData["\<\ MatrixForm[{{0, -c, b}, {c, 0, -a}, {-b, a, 0}, {0, -f, e}, {f, 0, -d}, {-e, d, 0}}]\ \>", "\<\ 0 -c b c 0 -a -b a 0 0 -f e f 0 -d -e d 0\ \>"], "Output", ImageRegion->{{-0, 1}, {0, 1}}]}, Open]]}, Open]], Cell[CellGroupData[{Cell[TextData[{ "In general, we will be determining attitude from observations that \ overdetermine the result.. A least squares solution is a good way to proceed \ in this case. The simplest way to get a least squares solution to an \ overdetermined equation ", StyleBox["Mx=b", FontWeight->"Bold"], " is to multiply both sides by ", StyleBox["M", FontWeight->"Bold"], StyleBox["T", FontVariations->{"CompatibilityType"->"Superscript"}], " and solve the resulting (no longer overdetermined) matrix equation. This \ yields an unweighted least squares result. There are much more complicated \ ways to do this that may yield better results when the equation is nearly \ singular, but I don't think they are worth it here." }], "Text", ImageRegion->{{-0, 1}, {0, 1}}], Cell["\<\ LSQSolve[ m_, b_ ] := \tLinearSolve[ Transpose[ m ] . m, Transpose[ m ] . b ]\ \>", "Input", InitializationCell->True, ImageRegion->{{-0, 1}, {0, 1}}]}, Open]], Cell[CellGroupData[{Cell[TextData[{ "First order determination of a rotation: a small rotation may be \ represented by a short vector ", StyleBox["du", FontWeight->"Bold"], " which crossed with a vector ", StyleBox["v", FontWeight->"Bold"], " gives the change ", StyleBox["dv", FontWeight->"Bold"], " in ", StyleBox["v", FontWeight->"Bold"], " due to the rotation. The components of ", StyleBox["du", FontWeight->"Bold"], " are conventionally termed \"pitch\", \"yaw\", and \"roll\". The following \ function finds a first order rotation vector that rotates a set of reference \ vectors into a set of observations. The method develops as follows:\n\nWe \ start with an overdetermined set of matrix equations:\n\n", StyleBox["Cross[ du, v ] == dv\n", FontWeight->"Bold"], "\nConvert it to the form of a standard matrix equation:\n\n", StyleBox["-Tensorize[ v ] . du == dv\n", FontWeight->"Bold"], "\nNote that the minus sign is due to the fact that to put the equations \ into standard form for a matrix equation, we must reverse the cross product. \ To solve for the unknown vector ", StyleBox["du", FontWeight->"Bold"], ", we just make an overdetermined equation by stacking up the ", StyleBox["v", FontWeight->"Bold"], " and ", StyleBox["dv", FontWeight->"Bold"], " matrices. Our Tensorize function already does this, and we can use \ Flatten to do the same to the observed differences. In the following \ function, ", StyleBox["ref", FontWeight->"Bold"], " represents the initial vector ", StyleBox["v", FontWeight->"Bold"], " above, while ", StyleBox["obs", FontWeight->"Bold"], " represents the result of the rotation: thus ", StyleBox["obs - ref", FontFamily->"Courier", FontWeight->"Bold"], " represents ", StyleBox["dv.", FontWeight->"Bold"] }], "Text", ImageRegion->{{-0, 1}, {0, 1}}], Cell["\<\ PitchYawRoll[ref_, obs_] := LSQSolve[ \t\t-Tensorize[ ref ], \t\tFlatten[obs - ref] ] \ \>", "Input", InitializationCell->True, ImageRegion->{{-0, 1}, {0, 1}}]}, Open]], Cell[CellGroupData[{Cell["\<\ An antisymmetric tensor or axial vector adequately represents the \ way that a small rotation changes a vector. For larger rotations, however, a \ rotation matrix is more useful. A rotation matrix doesn't just tell how a \ vector changes: the product of a rotation matrix and a vector is a rotated \ vector. For small rotations, one may turn an antisymmetric tensor into a \ rotation matrix simply by adding an identity matrix to it: the rotated vector \ is just the original vector plus its change due to rotation. In the \ following function we start from the axial vector representation:\ \>", "Text",\ ImageRegion->{{-0, 1}, {0, 1}}], Cell["\<\ SmallRotation[ v_ ] := \tTensorize[ v ] + IdentityMatrix[ 3 ]\ \>", "Input", InitializationCell->True, ImageRegion->{{-0, 1}, {0, 1}}]}, Open]], Cell[CellGroupData[{Cell[TextData[{ "A rotation matrix is an orthogonal matrix. The matrices returned by ", StyleBox["SmallRotation", FontWeight->"Bold"], " are orthogonal only to first order. If the rotation is truly small, this \ is okay, but we need a way to obtain a rotation matrix for large rotations. \ We can do this by using the Gram-Schmidt procedure to orthonormalize the \ first order rotation matrix returned by ", StyleBox["SmallRotation", FontWeight->"Bold"], ". The result of the Gram-Schmidt procedure is a true rotation matrix, \ although not necessarily a good approximation to the desired rotation matrix \ unless the rotation is small. It is, however, a step in the right direction, \ so we may use this method to obtain a succession of better approximations. If \ you've never heard of Gram-Schmidt, see any linear algebra or matrix algebra \ text: it's not a subtle or difficult algorithm.\n\nThe function ", StyleBox["RefineRotation", FontWeight->"Bold"], " yields an approximation to a rotation matrix rotating a set of reference \ vectors into a set of observations given an initial guess. It works by \ rotating the reference vectors by the guess, solving for a (hopefully) small \ rotation that rotates the rotated reference vectors to match the \ observations. It then rotates the guess to yield an approximation to the \ total rotation, and applies Gram-Schmidt to insure that the result is a \ properly orthogonal rotation matrix." }], "Text", ImageRegion->{{-0, 1}, {0, 1}}], Cell["\<\ RefineRotation[ref_, obs_, guess_] := \tGramSchmidt[ \t\tSmallRotation[ \t\t\tPitchYawRoll[ref . Transpose[guess], obs] \t\t] . guess \t]\ \>", "Input", InitializationCell->True, ImageRegion->{{-0, 1}, {0, 1}}]}, Open]], Cell["\<\ Now for a demo. The following reference and observation vectors \ define a rotation through 90 degrees:\ \>", "Text", ImageRegion->{{-0, 1}, {0, 1}}], Cell[CellGroupData[{Cell["\<\ rv = { \t{ 1, 0, 0 }, \t{ 0, 1, 0 } }//N ov = { \t{ 0, 0, 1 }, \t{ 0, 1, 0 } }//N \ \>", "Input", ImageRegion->{{-0, 1}, {0, 1}}], Cell[OutputFormData["\<\ {{1., 0, 0}, {0, 1., 0}}\ \>", "\<\ {{1., 0, 0}, {0, \ 1., 0}}\ \>"], "Output", ImageRegion->{{-0, 1}, {0, 1}}], Cell[OutputFormData["\<\ {{0, 0, 1.}, {0, 1., 0}}\ \>", "\<\ {{0, 0, 1.}, {0, \ 1., 0}}\ \>"], "Output", ImageRegion->{{-0, 1}, {0, 1}}]}, Open]], Cell[TextData[{ "We now apply ", StyleBox["RefineRotation", FontWeight->"Bold"], " until it converges: To give the method a workout, we use an identity \ matrix as our first guess, thus assuming no rotation. This will make our \ first estimates of the rotation rather inaccurate (it certainly won't be a \ small rotation atop our initial guess):" }], "Text", ImageRegion->{{-0, 1}, {0, 1}}], Cell[CellGroupData[{Cell["RefineRotation[ rv, ov, IdentityMatrix[3]]", "Input", ImageRegion->{{-0, 1}, {0, 1}}], Cell[OutputFormData["\<\ {{0.7071067811865475, 0., -0.7071067811865475}, {0., 1., 0.}, {0.7071067811865475, 0., 0.7071067811865475}}\ \>", "\<\ {{0.707107, 0., -0.707107}, {0., 1., 0.}, {0.707107, 0., 0.707107}}\ \>"], "Output", ImageRegion->{{-0, 1}, {0, 1}}]}, Open]], Cell[CellGroupData[{Cell["RefineRotation[ rv, ov, % ]", "Input", ImageRegion->{{-0, 1}, {0, 1}}], Cell[OutputFormData["\<\ {{0.1691019787257627, 0., -0.985598559653489}, {0., 1., 0.}, {0.985598559653489, 0., 0.1691019787257627}}\ \>", "\<\ {{0.169102, 0., -0.985599}, {0., 1., 0.}, {0.985599, 0., 0.169102}}\ \>"], "Output", ImageRegion->{{-0, 1}, {0, 1}}]}, Open]], Cell[CellGroupData[{Cell["RefineRotation[ rv, ov, % ]", "Input", ImageRegion->{{-0, 1}, {0, 1}}], Cell[OutputFormData["\<\ {{0.002401221999859747, 0., -0.999997117062298}, {0., 1., 0.}, {0.999997117062298, 0., 0.002401221999859747}}\ \>", "\<\ {{0.00240122, 0., -0.999997}, {0., 1., \ 0.}, {0.999997, 0., 0.00240122}}\ \>"], "Output", ImageRegion->{{-0, 1}, {0, 1}}]}, Open]], Cell[CellGroupData[{Cell["RefineRotation[ rv, ov, % ]", "Input", ImageRegion->{{-0, 1}, {0, 1}}], Cell[OutputFormData["\<\ {{6.922553476455328*10^-9, 0., -1.}, {0., 1., 0.}, {1., 0., 6.922553476455328*10^-9}}\ \>", "\<\ -9 {{6.92255 10 , 0., -1.}, {0., 1., 0.}, -9 {1., 0., 6.92255 10 }}\ \>"], "Output", ImageRegion->{{-0, 1}, {0, 1}}]}, Open]], Cell[CellGroupData[{Cell["RefineRotation[ rv, ov, % ]", "Input", ImageRegion->{{-0, 1}, {0, 1}}], Cell[OutputFormData["\<\ {{0., 0., -1.}, {0., 1., 0.}, {1., 0., 0.}}\ \>", \ "\<\ {{0., 0., -1.}, {0., 1., 0.}, {1., 0., 0.}}\ \>"], "Output", ImageRegion->{{-0, 1}, {0, 1}}]}, Open]], Cell[TextData[{ "Convergence is very rapid: four iterations to better than a part in 10", StyleBox["8", FontVariations->{"CompatibilityType"->"Superscript"}], ", five to machine precision. The number of correct digits in the result \ doubles with each iteration (this is known as \"quadratic convergence\" in \ the jargon of numerical approximation theory). We can automate this iteration \ procedure in ", StyleBox["Mathematica", FontSlant->"Italic"], " as follows:" }], "Text", ImageRegion->{{-0, 1}, {0, 1}}], Cell["\<\ Rotation[ref_, obs_, guess_] := FixedPoint[RefineRotation[ref, obs, #1] & , guess]\ \>", "Input", InitializationCell->True, ImageRegion->{{-0, 1}, {0, 1}}], Cell[CellGroupData[{Cell["Rotation[ rv, ov, IdentityMatrix[ 3 ]]", "Input", ImageRegion->{{-0, 1}, {0, 1}}], Cell[OutputFormData["\<\ {{0., 0., -1.}, {0., 1., 0.}, {1., 0., 0.}}\ \>", \ "\<\ {{0., 0., -1.}, {0., 1., 0.}, {1., 0., 0.}}\ \>"], "Output", ImageRegion->{{-0, 1}, {0, 1}}]}, Open]], Cell["\<\ This is a very effective method for reducing observations to \ rotation matrices as long as some sort of guess is available: even for a \ guess 90 degrees off it converges rapidly. Convergence can be much slower for \ guesses that are worse, however, and the iteration has (unstable) fixed \ points at some 180 degree rotations:\ \>", "Text", ImageRegion->{{-0, 1}, {0, 1}}], Cell[CellGroupData[{Cell["\<\ ov = { \t{ -1, 0, 0 }, \t{ 0, 1, 0 }} Rotation[ rv, ov, IdentityMatrix[ 3 ]]\ \>", "Input", ImageRegion->{{-0, 1}, {0, 1}}], Cell[OutputFormData["\<\ {{-1, 0, 0}, {0, 1, 0}}\ \>", "\<\ {{-1, 0, 0}, {0, \ 1, 0}}\ \>"], "Output", ImageRegion->{{-0, 1}, {0, 1}}], Cell[OutputFormData["\<\ {{1., 0., 0.}, {0., 1., 0.}, {0., 0., 1.}}\ \>", "\<\ \ {{1., 0., 0.}, {0., 1., 0.}, {0., 0., 1.}}\ \>"], "Output", ImageRegion->{{-0, 1}, {0, 1}}]}, Open]], Cell["\<\ Note that in the case above, the method returned an identity \ matrix, even though the observations imply a 180 degree rotation about the y \ axis. Perturbing the guess by a slight rotation about the y axis should fix \ things in this case, although if you do the iterations by hand the early \ ones won't make much progress.\ \>", "Text", ImageRegion->{{-0, 1}, {0, 1}}], Cell[CellGroupData[{Cell["\<\ Rotation[ rv, ov , IdentityMatrix[3] + \tTensorize[ { 0, 0.0001, 0 } ]]\ \>", "Input", ImageRegion->{{-0, 1}, {0, 1}}], Cell[OutputFormData["\<\ {{-1., 0., 0.}, {0., 1., 0.}, {0., 0., -1.}}\ \>", "\ \<\ {{-1., 0., 0.}, {0., 1., 0.}, {0., 0., -1.}}\ \>"], "Output", ImageRegion->{{-0, 1}, {0, 1}}]}, Open]], Cell[TextData[{ "For HETE onboard software, ", StyleBox["PitchYawRoll", FontWeight->"Bold"], " applied to an arbitrarily selected set of stars is obviously the thing \ to use for the attitude rates. The best results will come from applying it to \ data from multiple cameras. \n\nFor absolute attitude we may apply ", StyleBox["Rotation", FontWeight->"Bold"], " to our idetified reference stars." }], "Text", ImageRegion->{{-0, 1}, {0, 1}}], Cell["Addendum: an effective method to get an initial guess", "Section", ImageRegion->{{-0, 1}, {0, 1}}], Cell[TextData[{ "Only two star sightings are needed in principle to determine a rotation \ matrix. The following method uses only the first two vectors in the lists of \ observed and reference vectors to solve for a rotation matrix. It is a \ non-iterative method, so there is no question of convergence. The only \ restriction is that the vectors must be distinct, and not exactly 180 degrees \ apart (it should be geometrically obvious that no method can cope with those \ singular cases). Its major limitation is that it is not a least-squares \ method, and it cannot take into account more than two stars.\n\nThe method \ works by using the two vectors to construct an orthonormal set of basis \ vectors. First, It uses ", StyleBox["GramSchmidt", FontWeight->"Bold"], " on the 2 by 3 matrix of vectors to construct two axes. The first axis is \ the first vector, while the second is forced to be orthogonal. The third axis \ is constructed by ", StyleBox["Cross", FontWeight->"Bold"], ". The matrix representation of an orthonormal basis is itself a rotation \ matrix (from the implicit reference frame to the reference frame defined by \ the basis), so to get the rotation from one frame to the other, we just dot \ the inverse (transpose) of one matrix by the other." }], "Text", ImageRegion->{{-0, 1}, {0, 1}}], Cell["\<\ MakeZ[ v_ ] := { v[[ 1 ]], v[[ 2 ]], \tCross[ v[[ 1 ]], v[[ 2 ]] ] } \ \>", "Input", InitializationCell->True, ImageRegion->{{-0, 1}, {0, 1}}], Cell["Basis2[ v_ ] := MakeZ[ GramSchmidt[ Take[ v, 2 ] ] ]", "Input", InitializationCell->True, ImageRegion->{{-0, 1}, {0, 1}}], Cell["\<\ Rotation2[ ref_, obs_ ] := \tTranspose[ Basis2[ obs ] ] . Basis2[ ref ]\ \>", "Input", InitializationCell->True, ImageRegion->{{-0, 1}, {0, 1}}], Cell["A demonstration:", "Text", ImageRegion->{{-0, 1}, {0, 1}}], Cell[CellGroupData[{Cell["guess = Rotation2[ rv, ov ]", "Input", ImageRegion->{{-0, 1}, {0, 1}}], Cell[OutputFormData["\<\ {{0., 0., -1.}, {0., 1., 0.}, {1., 0., 0.}}\ \>", \ "\<\ {{0., 0., -1.}, {0., 1., 0.}, {1., 0., 0.}}\ \>"], "Output", ImageRegion->{{-0, 1}, {0, 1}}]}, Open]], Cell[CellGroupData[{Cell["Rotation[ rv, ov, guess ]", "Input", ImageRegion->{{-0, 1}, {0, 1}}], Cell[OutputFormData["\<\ {{0., 0., -1.}, {0., 1., 0.}, {1., 0., 0.}}\ \>", \ "\<\ {{0., 0., -1.}, {0., 1., 0.}, {1., 0., 0.}}\ \>"], "Output", ImageRegion->{{-0, 1}, {0, 1}}]}, Open]], Cell[TextData[{ "I suspect that a single iteration of ", StyleBox["RefineRotation", FontWeight->"Bold"], " following ", StyleBox["Rotation2", FontWeight->"Bold"], " will be good enough in most cases." }], "Text", ImageRegion->{{-0, 1}, {0, 1}}], Cell[TextData[{ "Roland has a C implementation of these functions. He has pointed out to me \ that for ", StyleBox["Rotation2", FontWeight->"Bold"], " to work properly, it is very important that the Gram-Schmidt algorithm \ work by rows rather than by columns." }], "Text", ImageRegion->{{-0, 1}, {0, 1}}] }, FrontEndVersion->"4.1 for X", ScreenRectangle->{{0, 1280}, {0, 1024}}, AutoGeneratedPackage->None, WindowToolbars->{}, CellGrouping->Manual, WindowSize->{520, 600}, WindowMargins->{{380, Automatic}, {Automatic, 212}}, PrivateNotebookOptions->{"ColorPalette"->{RGBColor, -1}}, ShowCellLabel->True, ShowCellTags->False, RenderingOptions->{"ObjectDithering"->True, "RasterDithering"->False}, Magnification->1.25 ] (******************************************************************* Cached data follows. If you edit this Notebook file directly, not using Mathematica, you must remove the line containing CacheID at the top of the file. The cache data will then be recreated when you save this file from within Mathematica. *******************************************************************) (*CellTagsOutline CellTagsIndex->{} *) (*CellTagsIndex CellTagsIndex->{} *) (*NotebookFileOutline Notebook[{ Cell[1707, 52, 484, 14, 70, "Subsection"], Cell[2194, 68, 254, 7, 70, "Section"], Cell[2451, 77, 113, 2, 70, "Input", InitializationCell->True], Cell[CellGroupData[{ Cell[2587, 81, 511, 9, 70, "Text"], Cell[3101, 92, 145, 5, 70, "Input", InitializationCell->True], Cell[3249, 99, 126, 2, 70, "Input", InitializationCell->True] }, Open ]], Cell[CellGroupData[{ Cell[3407, 103, 424, 9, 70, "Text"], Cell[3834, 114, 152, 5, 70, "Input", InitializationCell->True], Cell[3989, 121, 151, 5, 70, "Input", InitializationCell->True] }, Open ]], Cell[CellGroupData[{ Cell[4172, 128, 686, 11, 70, "Text"], Cell[4861, 141, 170, 7, 70, "Input", InitializationCell->True] }, Open ]], Cell[CellGroupData[{ Cell[5063, 150, 164, 4, 70, "Text"], Cell[CellGroupData[{ Cell[5250, 156, 89, 1, 70, "Input"], Cell[5342, 159, 168, 6, 70, "Output"] }, Open ]], Cell[CellGroupData[{ Cell[5542, 167, 85, 1, 70, "Input"], Cell[5630, 170, 168, 6, 70, "Output"] }, Open ]] }, Open ]], Cell[CellGroupData[{ Cell[5839, 178, 135, 4, 70, "Text"], Cell[5977, 184, 158, 5, 70, "Input", InitializationCell->True], Cell[CellGroupData[{ Cell[6158, 191, 103, 1, 70, "Input"], Cell[6264, 194, 254, 16, 70, "Output"] }, Open ]] }, Open ]], Cell[CellGroupData[{ Cell[6559, 212, 792, 17, 70, "Text"], Cell[7354, 231, 164, 5, 70, "Input", InitializationCell->True] }, Open ]], Cell[CellGroupData[{ Cell[7550, 238, 1901, 56, 70, "Text"], Cell[9454, 296, 195, 9, 70, "Input", InitializationCell->True] }, Open ]], Cell[CellGroupData[{ Cell[9681, 307, 651, 11, 70, "Text"], Cell[10335, 320, 148, 5, 70, "Input", InitializationCell->True] }, Open ]], Cell[CellGroupData[{ Cell[10515, 327, 1514, 26, 70, "Text"], Cell[12032, 355, 236, 9, 70, "Input", InitializationCell->True] }, Open ]], Cell[12280, 366, 161, 4, 70, "Text"], Cell[CellGroupData[{ Cell[12464, 372, 142, 11, 70, "Input"], Cell[12609, 385, 138, 6, 70, "Output"], Cell[12750, 393, 138, 6, 70, "Output"] }, Open ]], Cell[12900, 401, 402, 9, 70, "Text"], Cell[CellGroupData[{ Cell[13325, 412, 93, 1, 70, "Input"], Cell[13421, 415, 274, 9, 70, "Output"] }, Open ]], Cell[CellGroupData[{ Cell[13727, 426, 78, 1, 70, "Input"], Cell[13808, 429, 272, 9, 70, "Output"] }, Open ]], Cell[CellGroupData[{ Cell[14112, 440, 78, 1, 70, "Input"], Cell[14193, 443, 282, 10, 70, "Output"] }, Open ]], Cell[CellGroupData[{ Cell[14507, 455, 78, 1, 70, "Input"], Cell[14588, 458, 283, 10, 70, "Output"] }, Open ]], Cell[CellGroupData[{ Cell[14903, 470, 78, 1, 70, "Input"], Cell[14984, 473, 176, 6, 70, "Output"] }, Open ]], Cell[15172, 481, 531, 12, 70, "Text"], Cell[15706, 495, 172, 5, 70, "Input", InitializationCell->True], Cell[CellGroupData[{ Cell[15901, 502, 89, 1, 70, "Input"], Cell[15993, 505, 176, 6, 70, "Output"] }, Open ]], Cell[16181, 513, 387, 7, 70, "Text"], Cell[CellGroupData[{ Cell[16591, 522, 136, 7, 70, "Input"], Cell[16730, 531, 136, 6, 70, "Output"], Cell[16869, 539, 174, 6, 70, "Output"] }, Open ]], Cell[17055, 547, 384, 7, 70, "Text"], Cell[CellGroupData[{ Cell[17462, 556, 131, 4, 70, "Input"], Cell[17596, 562, 178, 6, 70, "Output"] }, Open ]], Cell[17786, 570, 461, 11, 70, "Text"], Cell[18250, 583, 106, 1, 70, "Section"], Cell[18359, 586, 1337, 23, 70, "Text"], Cell[19699, 611, 157, 6, 70, "Input", InitializationCell->True], Cell[19859, 619, 131, 2, 70, "Input", InitializationCell->True], Cell[19993, 623, 158, 5, 70, "Input", InitializationCell->True], Cell[20154, 630, 66, 1, 70, "Text"], Cell[CellGroupData[{ Cell[20243, 633, 78, 1, 70, "Input"], Cell[20324, 636, 176, 6, 70, "Output"] }, Open ]], Cell[CellGroupData[{ Cell[20532, 644, 76, 1, 70, "Input"], Cell[20611, 647, 176, 6, 70, "Output"] }, Open ]], Cell[20799, 655, 264, 9, 70, "Text"], Cell[21066, 666, 317, 8, 70, "Text"] } ] *) (******************************************************************* End of Mathematica Notebook file. *******************************************************************)