5
$\begingroup$

I'm trying to compare the unit normal definition in calculus texts (i.e., $\vec N=\vec T'/||\vec T'||$) where $\vec T$ is the unit tangent vector, with the unit normal vector returned by the FrenetSerretSystem. Using the calculus definition, this works:

Manipulate[

 Module[{r, unitT, unitN},

  r[x_] = {x, Sin[x]};
  unitT[x_] = r'[x]/Sqrt[r'[x].r'[x]];
  unitN[x_] = unitT'[x]/Sqrt[unitT'[x].unitT'[x]];

  ParametricPlot[r[x], {x, 0, 2 Pi},
   Epilog -> { 
     Orange, Thick, Arrow[{r[tt], r[tt] + unitN[tt]}],
     Red, PointSize[Large], Point[r[tt]]
     }, PlotRange -> {{0, 2 Pi}, {-4, 4}}]],

 {tt, 0.01, 2 Pi - 0.01}]

But trying the FrenetSerretSystem, this doesn't.

Manipulate[

 Module[{r, unitT, unitN, sys},

  r[x_] = {x, Sin[x]};
  sys = FrenetSerretSystem[r[x], x];
  unitT[x_] = sys[[2, 1]];
  unitN[x_] = sys[[2, 2]];

  ParametricPlot[r[x], {x, 0, 2 Pi},
   Epilog -> { 
     Orange, Thick, Arrow[{r[tt], r[tt] + unitN[tt]}],
     Red, PointSize[Large], Point[r[tt]]
     }, PlotRange -> {{0, 2 Pi}, {-4, 4}}]

  ],

 {tt, 0.01, 2 Pi - 0.01}]

I get an error such as this:

Coordinate {0.01 - Cos[$CellContext`x] (1 + Cos[$CellContext`x]^2)^Rational[-1, 2], 0.009999833334166664 + (1 + Cos[$CellContext`x]^2)^Rational[-1, 2]} should be a pair of numbers, or a Scaled or Offset form.

And this gives a similar error.

DynamicModule[{r, unitT, unitN, sys},

 r[x_] = {x, Sin[x]};
 sys = FrenetSerretSystem[r[x], x];
 unitT[x_] = sys[[2, 1]];
 unitN[x_] = sys[[2, 2]];

 Manipulate[

  ParametricPlot[r[x], {x, 0, 2 Pi},
   Epilog -> { 
     Orange, Thick, Arrow[{r[tt], r[tt] + unitN[tt]}],
     Red, PointSize[Large], Point[r[tt]]
     }, PlotRange -> {{0, 2 Pi}, {-4, 4}}],

  {tt, 0.01, 2 Pi - 0.01}]]

Once I get this repaired, I am going to see the unit normal vector (calculus definition) pointing in the opposite direction of the unit normal vector (FrenetSerretSystem) from 0 to $\pi$ and I am wondering why. I think it might have something to do with the fact that the calculus books tend to use the curvature, whereas the FrenetSerretSystem uses the signed curvature, but I am still trying to figure out the different directions of the unit normal.

Thanks for the help.

Update due to m_goldberg help:

This works:

Manipulate[

 Module[{r, k, unitT, unitN},

  r[x_] = {x, Sin[x]};
  {{k[x_]}, {unitT[x_], unitN[x_]}} = FrenetSerretSystem[r[x], x];

  ParametricPlot[r[x], {x, 0, 2 Pi},
   Epilog -> { 
     Orange, Thick, Arrow[{r[tt], r[tt] + unitN[tt]}],
     Red, Thick, Arrow[{r[tt], r[tt] + unitT[tt]}],
     Red, PointSize[Large], Point[r[tt]]
     }, PlotRange -> {{0, 2 Pi}, {-4, 4}}]

  ],

 {tt, 0.01, 2 Pi - 0.01}]

And this works:

DynamicModule[{r, unitT, unitN, k},

 r[x_] = {x, Sin[x]};
 {{k[x_]}, {unitT[x_], unitN[x_]}} = FrenetSerretSystem[r[x], x];

 Manipulate[ParametricPlot[r[x], {x, 0, 2 Pi},
   Epilog -> {
     Orange, Thick, Arrow[{r[tt], r[tt] + unitN[tt]}],
     Red, Thick, Arrow[{r[tt], r[tt] + unitT[tt]}],
     Red, PointSize[Large], Point[r[tt]]}, 
   PlotRange -> {{0, 2 Pi}, {-4, 4}}], {tt, 0.01, 2 Pi - 0.01}]]

Both protect the functions in the modules from being changed when functions with the same name are entered in the same notebook in the global workspace.

$\endgroup$
  • 1
    $\begingroup$ The second of your updated solutions is good, but you don't need to write k[x_] since you don't use k as a function (you don't use it at all) a simple k or any other variable name, say, notused will do. $\endgroup$ – m_goldberg Oct 4 '15 at 12:30
  • 1
    $\begingroup$ For the reasons I gave in point 3 of my answer, I do not like your 1st updated solution. You want to keep computations made in the 1st argument given to a Manipulate expression to the absolute minimum to insure good performance. The performance hit may not be noticeable in this simple problem, but it is there. $\endgroup$ – m_goldberg Oct 4 '15 at 12:37
  • $\begingroup$ @m_goldberg Thanks for the added comments and your wonderful assistance. $\endgroup$ – David Oct 4 '15 at 20:32
4
$\begingroup$

This much simpler implementation seems to work just fine.

Clear[k, n, t]
r[x_] := {x, Sin[x]};
{{k}, {t[x_], n[x_]}} = FrenetSerretSystem[r[x], x];

Manipulate[
  ParametricPlot[r[x], {x, 0, 2 Pi},
    Epilog -> {
      Orange, Thick, 
      Arrow[{r[tt], r[tt] + n[tt]}],
      Arrow[{r[tt], r[tt] + t[tt]}],
      Red, PointSize[Large], Point[r[tt]]}, 
      PlotRange -> {{-Pi/4, 2 Pi}, {-2, 2}}],
  {tt, 0., 2 Pi}]

demo

Update

The reason your code produces the error message is because you have a scoping problem

If you were to insert a debugging code into your Manipulate expression like so

Manipulate[
  Module[{r, unitT, unitN, sys},
    ...
    unitN[x_] = sys[[2, 2]];
    Print[Definition[unitN]];
    ParametricPlot[...],
  {tt, 0.01, 2 Pi - 0.01}]

you would see

debug

Note that on the lhs the independent variable is x$_ and the rhs it is x, so your function definitions for the tangent and normal don't work. There several ways you can fix this. Here are three.

  1. Define the functions for r, t and n at top-level as I did in the code given above. This is not a bad solution. It's only real drawback is that the Manipulate expression is not self-contained.

  2. Define the functions in an Initialization clause of the Manipulate expression. The functions are still defined globally but, at least, they are only defined once and the Manipulate expression is self-contained. This is my recommendation.

  3. Fix the scoping problem with a variable injection trick I learned form Mr.Wizard (I am not sure he invented it). Although this will fix the scoping, I do not recommend it because it still leaves the problem that the expressions defining r, t and n are re-evaluated each time the front-end updates the Manipulate's content pane -- a big performance hit.

My recommendation is to use the following code.

Manipulate[
  ParametricPlot[r[x], {x, 0, 2 Pi},
    Epilog -> {
      Orange, Thick,
      Arrow[{r[tt], r[tt] + n[tt]}],
      Arrow[{r[tt], r[tt] + t[tt]}],
      Red, PointSize[Large], Point[r[tt]]}, 
    PlotRange -> {{-Pi/4, 2 Pi}, {-2, 2}}],
  {tt, 0., 2. Pi},
  Initialization :> (
    Clear[k, n, t];
    r[x_] := {x, Sin[x]}; 
    {{k}, {t[x_], n[x_]}} = FrenetSerretSystem[r[x], x];)]

The code that only addresses the scoping problem is:

Manipulate[
  Module[{r, unitT, unitN, sys},
    r[x_] = {x, Sin[x]};
    sys = FrenetSerretSystem[r[x], x];
    Function[unitT[x_] = #][sys[[2, 1]]];
    Function[unitN[x_] = #][sys[[2, 2]]];
    ParametricPlot[r[x], {x, 0, 2 Pi},
      Epilog -> {
        Orange, Thick,
        Arrow[{r[tt], r[tt] + unitN[tt]}],
        Arrow[{r[tt], r[tt] + unitT[tt]}],
        Red, PointSize[Large], Point[r[tt]]}, 
      PlotRange -> {{-Pi/4, 2 Pi}, {-2, 2}}]],
  {tt, 0., 2. Pi}]
$\endgroup$
  • $\begingroup$ Thanks, this is helpful, but I still need to know why my code in my post does not work. $\endgroup$ – David Oct 3 '15 at 21:24
  • $\begingroup$ Really great investigation and an excellent explanation. However, like one of our [old conversations] (mathematica.stackexchange.com/questions/89486/…) , it doesn't protect r[x] getting changed in the global workspace. Try typing r[x_]={x,Cos[x]} after running the code. It changes the image. But your line {{k}, {t[x_], n[x_]}} = FrenetSerretSystem[r[x], x];` makes my code work and protects r[x]. See update to my post. $\endgroup$ – David Oct 4 '15 at 4:55

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.