Initiation à la mécanique quantique
 Interféromètre de Mach-Zenhder

Présentation

 La lumière est constituée de particules élémentaires indivisibles: les photons.

 On sait réaliser des miroirs semi-transparents (ou des lames semi-réfléchissantes) qui laissent passer la moitié de la lumière et qui réfléchissent la moitié de la lumière. (C'est assez facile à faire en jouant sur l'épaisseur du dépôt métallique). Très exactement, cela veut dire ceci: si on éclaire ce miroir semi-transparent avec un laser de 100 mW: 50 mW est réfléchi et 50 mW est transmis.

Dispositif à une séparatrice

Dans le cas où un photon unique arrive sur un miroir semi-transparent, on ne peut pas prédire si celui-ci sera transmis ou réfléchi. Le phénomène est aléatoire (complètement imprévisible).

Simuler l'arrivée d'un photon sur un miroir semi-transparent

 en utilisant des probabilités classiques

 en utilisant le formalisme quantique.

Ce formalisme repose sur trois principes.

 Premier principe:
la probabilité $P$ pour qu'une particule, émise initialement en $I$, soit détectée finalement en $F$, est le module
carré d'un nombre complexe qui représente l'amplitude de probabilité pour que la particule aille de $I$ à $F$.
On écrit: $P=\Big|\,{\langle F|I\rangle}\,\Big|^2$.

Avec cette notation: le symbole $\langle...\rangle$ signifie "amplitude de probabilité pour que ..." et le contenu des crochets signifie "condition finale $|$ condition initiale".

Pour une particule libre (i.e. soumise à aucune force), d'impulsion $\vec p$, l'amplitude de probabilité
d'aller de $I$ à $F$ est (à un facteur numérique près):
$\langle F|I\rangle={1\over IF}.e^{i.\vec p.\overrightarrow{IF\ }/\hbar}$

avec $p^2.c^2=E^2-(m_0.c^2)^2$ pour une particule relativiste

ou $p^2 =2.m.E_c$ (i.e. $\vec p=m.\vec v$) pour une particule non-relativiste.

 Deuxième principe:
lorsqu'une particule a à sa disposition deux chemins indiscernables \encercle{1}  ou \encercle{2} pour aller de $I$ à $F$,
on  somme les amplitudes de probabilité: $\langle F|I\rangle=\langle F|I\rangle_1+\langle F|I\rangle_2$.
On a alors: $P=\Big|\,\langle F|I\rangle_1+\langle F|I\rangle_2\,\Big|^2$.

En revanche, si les deux chemins sont discernables, on somme les probabilités (et non les amplitudes):
$P=\Big|\,\langle F|I\rangle_1\,\Big|^2+\Big|\,\langle F|I\rangle_2\,\Big|^2=P_1+P_2$.

 Troisième principe:
lorsqu'un chemin particulier se décompose en deux étapes, par exemple s'il faut que la particule aille de $I$ à $E$
 et de $E$ à $F$, on  multiplie les amplitudes de probabilité:
$\langle F|I\rangle=\langle F|E\rangle.\langle E|I\rangle$.

Ici, la source émet une particule dans l'état $|S\rangle$.

On montre, en électromagnétisme, que la réflexion sur un miroir introduit un déphasage qui se traduit ici par une multiplication par $e^{i.\pi/2}=i$.

L'état initial $|S\rangle$ doit s'écrire: $|S\rangle={1\over\sqrt{2}}.(|T\rangle + i.|R\rangle)$;
calculer $\langle T|S\rangle$ et $\langle R|S\rangle$; en déduire les probabilités d'atteindre les détecteurs $R$ et $T$.

On pourra utiliser la bibliothèque <tt>sympy</tt>:

from sympy.physics.quantum import Bra,Ket,qapply

Deux séparatrices en cascade

Simuler le comportement d'un photon sur deux miroirs semi-transparents en cascade (voir figure).

 en utilisant des probabilités classiques

 en utilisant le formalisme quantique.

Calculer $\langle TT|S\rangle$, $\langle TR|S\rangle$, $\langle RR|S\rangle$ et $\langle RT|S\rangle$; en déduire les probabilités d'atteindre les différents détecteurs.

Interféromètre de Mach Zehnder

Simuler le comportement d'un photon dans un interféromètre de Mach Zehnder (voir figure).

 en utilisant des probabilités classiques

 en utilisant le formalisme quantique.
 Les miroirs parfaits transforment $|T\rangle$ en $|T\rangle=i.|T'\rangle$ et $|R\rangle$ en $|R\rangle=i.|R'\rangle$.
Calculer $\langle D_1|S\rangle$ et $\langle D_2|S\rangle$; en déduire les probabilités d'atteindre les détecteurs $D_1$ et $D_2$.

Comparer les deux méthodes et conclure.

Solution

Monte Carlo

```ocaml
let separatrice () =
    let choix = ["R";"T"] in
    List.nth choix (Random.int 2)
```

val separatrice : unit -> string = <fun>

```ocaml
let proba_separatrice nbre_essais =
    let rec loop num_essai proba_R proba_T =
       if num_essai<nbre_essais then
           if separatrice () = "R"
              then loop (num_essai+1) (proba_R+1) proba_T
              else loop (num_essai+1) proba_R (proba_T+1)
       else
           List.map (fun x -> float_of_int x/.(float_of_int nbre_essais))
                    [proba_R; proba_T] in

    loop 0 0 0;;

proba_separatrice 1000;;
```

val proba_separatrice : int -> float list = <fun>

- : float list = [0.491; 0.509]

```ocaml
let separatrice_en_cascade () =
    if separatrice()="R" then
        begin
        let choix = ["RR";"RT"] in
        List.nth choix (Random.int 2)
        end
    else begin
        let choix = ["TR";"TT"] in
        List.nth choix (Random.int 2)
        end;;
```

val separatrice_en_cascade : unit -> string = <fun>

```ocaml
exception Error;;
let proba_separatrice_en_cascade nbre_essais =
     let rec loop num_essai proba_RR proba_RT proba_TR proba_TT =
          if num_essai<nbre_essais then
             let res = separatrice_en_cascade () in
             match res with
             | "RR" -> loop (num_essai+1) (proba_RR+1) proba_RT proba_TR proba_TT
             | "RT" -> loop (num_essai+1) proba_RR (proba_RT+1) proba_TR proba_TT
             | "TR" -> loop (num_essai+1) proba_RR proba_RT (proba_TR+1) proba_TT
             | "TT" -> loop (num_essai+1) proba_RR proba_RT proba_TR (proba_TT+1)
             | _ -> raise Error
         else
         List.map (fun x -> float_of_int x/.(float_of_int nbre_essais))
                  [proba_RR; proba_RT; proba_TR; proba_TT] in

    loop 0 0 0 0 0;;

proba_separatrice_en_cascade 1000;;
```

exception Error

val proba_separatrice_en_cascade : int -> float list = <fun>

- : float list = [0.242; 0.248; 0.255; 0.255]

```ocaml
let mach_zehnder() =
    if separatrice()="R" then
        begin
        let choix = ["D1";"D2"] in
        List.nth choix (Random.int 2)
        end
    else begin
        let choix = ["D1";"D2"] in
        List.nth choix (Random.int 2)
        end;;
```

val mach_zehnder : unit -> string = <fun>

```ocaml
exception Error;;
let proba_mach_zehnder nbre_essais =
     let rec loop num_essai proba_D1 proba_D2 =
          if num_essai<nbre_essais then
             let res = mach_zehnder () in
             match res with
             | "D1" -> loop (num_essai+1) (proba_D1+1) proba_D2
             | "D2" -> loop (num_essai+1) proba_D1 (proba_D2+1)
             | _ -> raise Error
         else
         List.map (fun x -> float_of_int x/.(float_of_int nbre_essais))
                  [proba_D1; proba_D2] in

    loop 0 0 0;;

proba_mach_zehnder 1000;;
```

exception Error

val proba_mach_zehnder : int -> float list = <fun>

- : float list = [0.505; 0.495]

Discussion

Dispositif à une séparatrice

 Le comportement du photon est complètement aléatoire.

Il n'y a aucun moyen de prévoir le comportement d'une seule particule. Le hasard n'a pas de mémoire. Si les trois premières particules ont été détectées sur le chemin R, rien ne dit que la quatrième suivra également le chemin R. Il ne faut pas croire non plus qu'il y ait une sorte de "déficit" sur le chemin T et que, pour compenser, la prochaine particule devra suivre le chemin T.

 En revanche, comme la séparatrice a une réflectivité de 50%:
si on envoie 100 milliards de particules,
on aura à peu près (aux fluctuations statistiques près) 50 milliards de particules réfléchies et 50 milliards de particules transmises. Le comportement collectif lui est complètement prévisible.

 Le hasard quantique n'est pas de même nature que celui que l'on rencontre en mécanique classique dans l'étude des phénomènes chaotiques par exemple. (Le chaos se manifeste dans des systèmes extrêmement sensibles aux conditions initiales). Dans les phénomènes chaotiques, l'impression de hasard vient du fait que l'expérience n'est pas exactement reproductible; mais, sur le principe, si on pouvait lancer une pièce de monnaie (ou un dé ou une bille à la roulette d'un casino) avec des conditions initiales strictement identiques, on obtiendrait des résultats reproductibles et la trajectoire de la pièce (ou du dé ou de la bille) serait, en théorie, prédictible. Ici, dans l'expérience du photon sur la séparatrice, les conditions initiales sont parfaitement définies et pourtant le résultat n'est pas prédicitible.

 Les probabilités quantiques ne sont pas, non plus, de même nature que les probabilités de la mécanique statistique (où l'on s'intéresse à des milliards de milliards de particules, alors que - dans l'expérience quantique décrite - on s'intéresse à un seul photon). Si, en mécanique statistique, on fait des moyennes c'est parce que l'on n'a pas le courage d'écrire un milliard d'équations (on parle d'explosion calculatoire). Il n'empêche que - sur le principe - ça serait possible. D'ailleurs, avec de très gros ordinateurs, on peut simuler le comportement de quelques centaines, voire quelques milliers, de particules. On est alors capable de prédire la trajectoire de toutes les particules individuellement.

Deux séparatrices en cascade

Pour un physicien, quelque chose de rigoureusement impossible à calculer, c'est tellement nouveau que certains ont imaginé des  échappatoires pour rétablir -  pour des raisons philosophiques - le déterminisme.
Certains ont objecté que, peut-être, toutes les particules émises par la source ne sont pas identiques. Certaines particules pourraient être programmées pour ne faire que des transmissions, d'autres que des réflexions. C'est astucieux: qui dit que, dans l'avenir, on ne découvrira pas un paramètre interne (une sorte de "gène") qui explique le comportement individuel des particules sans invoquer le hasard.

L'expérience avec deux séparatrice en cascade permet de rejeter cette objection.

Comme tout à l'heure, la particule peut être transmise ou réfléchie puis à nouveau transmise ou réfléchie. Tout se passe bien comme prévu: 1 chance/2 d'être transmise la première fois; puis 1 chance/2 d'être transmise une seconde fois. Finalement, quand on mesure la probabilité d'arriver en TT, on obtient bien de 1 chance/4. De même pour les autres trajets (TR, RT, RR). (La situation est analogue à deux tirages "pile" successifs ou bien pile-face, face-pile, face-face). Si certaines particules étaient programmées pour ne faire que des transmissions, on aurait mesuré une probabilité nulle pour le chemin TR (de même pour le chemin RT si d'autres étaient programmées pour ne faire que des réflexions).

C'est la preuve que le phénomène est parfaitement aléatoire.

Interféromètre de Mach Zehnder

A la première séparatrice, la particule peut "choisir" de continuer tout droit (1 chance/2), c'est le chemin T, puis elle est réfléchie avec une probabilité de 100 %, enfin elle peut "choisir" de continuer tout droit ou d'être réfléchie.
De même pour le chemin R.

Essayons de deviner ce que va être le résultat de cette expérience. Facile, non ? La probabilité pour arriver en (TR ou RT) devrait s'écrire: $P(TR)+P(RT)={1\over2}.{1\over2}+{1\over2}.{1\over2}={1\over4}+{1\over4}={1\over2}$. De même pour (TT ou RR).

Pourtant l'expérience montre que toutes les particules vont en (TR ou RT). Aucune en (TT ou RR).
L'effet de la première séparatrice est complètement aléatoire.
L'effet de la deuxième séparatrice est complètement aléatoire. Mais l'effet de l'ensemble est certain !

Conclusion

Les probabilités quantiques sont de nature différente des probabilités classiques.
On ne peut pas simuler une expérience quantique avec la fonction <tt>random</tt> sur un ordinateur classique.

Dans l'interféromètre de Mach Zehnder, seul le calcul quantique permet de démontrer que toutes particules vont en (TR ou RT).

```ocaml

```


```python
from sympy import symbols, oo, integrate, exp, pi, sin, cos, sqrt
```

## Going to Khan Academy to review fundamentals

[https://www.khanacademy.org/math/multivariable-calculus/integrating-multivariable-functions/double-integrals-a/a/double-integrals](https://www.khanacademy.org/math/multivariable-calculus/integrating-multivariable-functions/double-integrals-a/a/double-integrals)

```python
x, y = symbols('x y', real=True)
```

```python
inner = integrate(x+sin(y)+1, (x, 0., 2.))
inner
```

$\displaystyle 2.0 \sin{\left(y \right)} + 4.0$

```python
outer = integrate(inner, (y, -pi, pi))
outer
```

$\displaystyle 8.0 \pi$

```python
inner = integrate(x+sin(y)+1, (y, -pi, pi))
inner
```

$\displaystyle 2 \pi x + 2 \pi$

```python
outer = integrate(inner, (x, 0., 2.))
outer
```

$\displaystyle 8.0 \pi$

```python
inner = integrate(cos(y)*x**2+1, (x, -1., 1.))
inner
```

$\displaystyle 0.666666666666667 \cos{\left(y \right)} + 2.0$

```python
outer = integrate(inner, (y, -pi, pi))
outer
```

$\displaystyle 4.0 \pi$

[https://www.khanacademy.org/math/multivariable-calculus/integrating-multivariable-functions/double-integrals-a/a/double-integrals-over-non-rectangular-regions](https://www.khanacademy.org/math/multivariable-calculus/integrating-multivariable-functions/double-integrals-a/a/double-integrals-over-non-rectangular-regions)

```python
inner = integrate(x*y**2, (y, 0, x))
inner
```

$\displaystyle \frac{x^{4}}{3}$

```python
outer = integrate(x**4/3., (x, 0., 2.))
outer
```

$\displaystyle 2.13333333333333$

```python
lower = -sqrt(1-x**2)
upper = sqrt(1-x**2)
integrate(3+y-x**2, (y, lower, upper))
```

$\displaystyle 2 \sqrt{1 - x^{2}} \left(3 - x^{2}\right)$

```python
upper = y+2
lower = y**2
inner = integrate(x+2*y, (x, lower, upper))
inner
```

$\displaystyle - \frac{y^{4}}{2} - 2 y^{3} + 2 y \left(y + 2\right) + \frac{\left(y + 2\right)^{2}}{2}$

```python
outer = integrate(inner, (y, 0., 2.))
outer
```

$\displaystyle 11.4666666666667$

[https://www.khanacademy.org/math/multivariable-calculus/integrating-multivariable-functions/double-integrals-a/a/double-integrals-in-polar-coordinates](https://www.khanacademy.org/math/multivariable-calculus/integrating-multivariable-functions/double-integrals-a/a/double-integrals-in-polar-coordinates)

```python
r, theta = symbols('r theta', real=True, positive=True)
```

```python
inner = integrate(r**3, (theta, 0, 2*pi))
inner
```

$\displaystyle 2 \pi r^{3}$

```python
outer = integrate(inner, (r, 0., 2.))
outer
```

$\displaystyle 8.0 \pi$

```python
inner = integrate(r**2*sin(theta), (r, 0., cos(2*theta)))
inner
```

$\displaystyle \frac{\sin{\left(\theta \right)} \cos^{3}{\left(2 \theta \right)}}{3}$

```python
outer = integrate(inner, (theta, 0., 2*pi))
outer
```

$\displaystyle 0$

```python

```


## Predator-Prey Population Differential Equations

In this notebook we will a simple population equation [1]

```python
## Library
import numpy as np
import math
import matplotlib.pyplot as plt
```

## Predators and prey
The cyclical relationship of Predators and Prey in the wild  means that when there is an abundance of prey, the predators will eat more and their population will increase. On the other hand, if there is a shortage in the number of prey, the number of predators will decrease. One of the of the most famous examples of this was observed by the fur traders  Hudson's Bay Company of Canada. The company collected data about the number of lynx and hare pelts they purchased over a 90 year period. Their data showed the cylical nature of the predator prey relationship (Figure below).

 Figure 1: The Lynx-Hare Cycle  [1].
This kind of behaviour has been observed in many pairs of predators and prey from mammals to fish to beyond.

## Snow Hares and Lynxes
In a balanced eco system the relationship between snow hares (prey) and lynxes (predator) can be described mathematically using a Loketta-Volterra model [2-4]
\begin{equation}
\begin{array}{cl}
\frac{d H}{dt}=a_{Birth} H-b_{Con}LH,\\
\frac{d L}{dt}=-c_{Death}L+d_{Food} L H,\\
\end{array}
\end{equation}
this set of equations models the interaction between snow hares (H) and lynxes (L). The lynes are the predators who eat the snow hares to survive. Where there parameters
* $a_{Birth}$ is the birth rate of the snow hares;
* $b_{Con}$ is the consumation rate of snow hares by lynxes (interaction);
* $c_{Death}$ is the death rate of lynxes if there is no food source;
* $d_{Food}$ is the rate that lynxes eat the snow hares to survive (interaction).

```python
a_Birth=4.0
b_Con=0.1
c_Death=0.9
d_Food=0.001

```

## Discrete Domain
To numiercally approximate the solution we discretise the continuous domain using a step size, $h=1$,
which gives
\begin{equation}
t_i=0+i h,
\end{equation}
for $i=0,...10$.
The figure below illustrate the discrete domain.

```python
h=0.001
t=np.arange(1850,1925+h/2,h)
fig = plt.figure(1,figsize=(5,4))
ax = fig.add_subplot(1,1,1)
ax.plot(t,0*t,'o:',color='k')
ax.set_xlabel('Time (yrs)')
plt.title('Discrete Time Domain')
plt.show()
```

```python
N=len(t) # Number of Steps
H=np.zeros(N) # Numerical Solution Hares
H[0]=900
L=np.zeros(N) # Numerical Solution Lynxes
L[0]=40

```

We numerically approximate the differential equation using Eulers method to give the difference equation
\begin{equation}
\text{ INSERT DIFFERENCE EQUATION HERE,}
\end{equation}
where $h$ is the stepsize and where $P_i$ is the numerical approximation of $p(t_i)$ at distance $t_i$, for $i=0,...,N$

```python
a_Birth=0.4
b_Con=0.01
c_Death=0.09
d_Food=0.001

for i in range (0,N-1):
    H[i+1]=H[i]+h*(a_Birth-b_Con*L[i])*H[i]# INSERT EQUATION HERE
    L[i+1]=L[i]+h*(-c_Death+d_Food*H[i])*L[i]# INSERT EQUATION HERE

```

## Results
Figure 2 shows a simulation of the populations of salmon and small fish from 2000 to 2100, assuming that nothing is added to enviroment.  The salmon population fluxuates between 45 and 55 billion while the small fish population fluctuates from 25 to 85 billion. The equation illustates a relative equilibrium between the two populations ensuring neither get too big or too small.

```python
## Plotting Figure
fig = plt.figure(1,figsize=(10,4))

ax = fig.add_subplot(1,1,1)

ax.plot(t,H,':',color='green',label='Hares')
ax.plot(t,L,':',color='red',label='Lynxes')

ax.legend()
ax.set_xlabel('Time (yrs)')
ax.set_ylabel('Population (tens of thousands)')
#ax.legend(loc='best')
ax.set_title('Predator Prey Relationship')
plt.tight_layout()
plt.subplots_adjust(top=0.85)
plt.show()

```

## Phase Plane Plot

```python
## Plotting Figure
fig = plt.figure(1,figsize=(5,5))

ax = fig.add_subplot(1,1,1)

ax.plot(L,H,'-',color='black')

ax.set_xlabel('Lynx Population (tens of thousands)')
ax.set_ylabel('Hare Population (tens of thousands)')
#ax.legend(loc='best')
ax.set_title('Predator Prey Relationship')
plt.tight_layout()
plt.subplots_adjust(top=0.85)
plt.xlim(0,200)
plt.ylim(0,900)

plt.show()
```

## Equilibrium
The Loketta-Volterra model [4] can be written in matrix frorm
\begin{equation}
\begin{pmatrix}
\frac{dH}{dt}\\
\frac{dL}{dt}
\end{pmatrix}
=\begin{pmatrix}
a_{Birth} & -b_{Con}L \\
-c_{Death} & d_{Food}H
\end{pmatrix}
\begin{pmatrix}
H \\
L
\end{pmatrix}.
\end{equation}
The point of equilibrium (stability) is when $\frac{dH}{dt}=0$ and $\frac{dL}{dt}=0$,
\begin{equation}
\begin{pmatrix}
0\\
0
\end{pmatrix}
=\begin{pmatrix}
a_{Birth} & -b_{Con}L \\
-c_{Death} & d_{Food}H
\end{pmatrix}
\begin{pmatrix}
H \\
L
\end{pmatrix},
\end{equation}
this gives two solutions for $H$ and $L$:
1. the trivial solution is $H=0$ and $L=0$;
2. the non-trivial solution is $H=\frac{c_{Death}}{d_{Food}}$ and $L=\frac{a_{Birth}}{b_{Con}}$.

```python
## Plotting Figure
fig = plt.figure(1,figsize=(5,5))

ax = fig.add_subplot(1,1,1)

ax.plot(L,H,'-',color='black',label='Predator - Prey Cycle')

ax.plot(a_Birth/b_Con,c_Death/d_Food,'o',markersize=7,color='g',markeredgecolor='k',label='Stable Point')
ax.plot(0,0,'o',markersize=7,color='g',markeredgecolor='b',label='Trivial Stable Point')

ax.set_xlabel('Lynx Population (tens of thousands)')
ax.set_ylabel('Hare Population (tens of thousands)')
#ax.legend(loc='best')
ax.set_title('Predator Prey Relationship')
plt.tight_layout()
plt.subplots_adjust(top=0.85)
plt.xlim(0,200)
plt.ylim(0,900)
plt.legend()
plt.show()
```

## Nullclines
The Nullclines are defined as curves when $\frac{dH}{dt}=0$ or $\frac{dH}{dt}=0$.
Here we have two simple nullcline;
1. For $\frac{dH}{dt}=0$, gives the vertical nullcline
$$L=\frac{a_{Birth}}{b_{Con}};$$
2. For $\frac{dL}{dt}=0$, gives the horizontal nullcline
$$H=\frac{a_{Birth}}{b_{Con}}.$$
The nullclines divides the graph into quadrantes:
1. The first quadrant (Q1) is when $\frac{dH}{dt}<0$ and $\frac{dL}{dt}>0$, the Hare population is decreasing while the Lynx population is increasing;
2. The second quadrant (Q2) is when $\frac{dH}{dt}>0$ and $\frac{dL}{dt}>0$, the Hare population and the Lynx population are increasing;

3. The third quadrant (Q3) is when $\frac{dH}{dt}>0$ and $\frac{dL}{dt}<0$, the Hare population is increasing while the Lynx population is decreasing;

4. The fourth quadrant (Q1) is when $\frac{dH}{dt}<0$ and $\frac{dL}{dt}<0$, the Hare and Lynx populations are decreasing.

```python
## Plotting Figure
fig = plt.figure(1,figsize=(5,5))

ax = fig.add_subplot(1,1,1)

ax.plot(L,H,'-',color='black',label='Predator - Prey Cycle')

ax.plot(a_Birth/b_Con,c_Death/d_Food,'o',markersize=7,color='g',markeredgecolor='k',label='Stable Point')
ax.plot(0,0,'o',markersize=7,color='g',markeredgecolor='b',label='Trivial Stable Point')

ax.plot(a_Birth/b_Con,c_Death/d_Food,'o',markersize=7,color='g',markeredgecolor='k',label='Stable Point')

ax.axvline(a_Birth/b_Con,linewidth=4, color='r',label=r'nullcline $\frac{dH}{dt}=0$')

ax.axhline(c_Death/d_Food,linewidth=4, color='y',label=r'nullcline $\frac{dL}{dt}=0$')

ax.set_xlabel('Lynx Population (tens of thousands)')
ax.set_ylabel('Hare Population (tens of thousands)')
#ax.legend(loc='best')
ax.set_title('Predator Prey Relationship')
plt.tight_layout()
plt.subplots_adjust(top=0.85)
plt.text(a_Birth/b_Con*0.5,c_Death/d_Food*0.5,r'Q1')
plt.text(a_Birth/b_Con*1.5,c_Death/d_Food*0.5,r'Q2')
plt.text(a_Birth/b_Con*1.5,c_Death/d_Food*1.5,r'Q3')

plt.text(a_Birth/b_Con*0.5,c_Death/d_Food*1.5,r'Q4')
plt.xlim(0,200)
plt.ylim(0,900)
plt.legend()
plt.show()
```

```python
def dX_dt(H,L):
   # """ Return the growth rate of fox and rabbit populations. """
    return np.array([
    a_Birth*H -   b_Con*L*H ])

nbpoints=10
y = np.linspace(0, 900, nbpoints)
x = np.linspace(0, 200, nbpoints)

X1 , Y1  = np.meshgrid(x, y)                       # create a grid
DX1, DY1 = dX_dt(X1, Y1)                      # compute growth rate on the gridt
M = (np.hypot(DX1, DY1))/(np.hypot(DX1, DY1))                        # Norm of the growth rate
M[ M == 0] = 1.                              # Avoid zero division errors
DX1 /= M                                        # Normalize each arrows
DY1 /= M

## Plotting Figure
fig = plt.figure(1,figsize=(5,5))

ax = fig.add_subplot(1,1,1)

ax.plot(L,H,'-',color='black',label='Predator - Prey Cycle')

ax.plot(a_Birth/b_Con,c_Death/d_Food,'o',markersize=7,color='g',markeredgecolor='k',label='Stable Point')
ax.plot(0,0,'o',markersize=7,color='g',markeredgecolor='b',label='Trivial Stable Point')

ax.plot(a_Birth/b_Con,c_Death/d_Food,'o',markersize=7,color='g',markeredgecolor='k',label='Stable Point')

ax.axvline(a_Birth/b_Con,linewidth=4, color='r',label=r'nullcline $\frac{dH}{dt}=0$')

ax.axhline(c_Death/d_Food,linewidth=4, color='y',label=r'nullcline $\frac{dL}{dt}=0$')

ax.set_xlabel('Lynx Population (tens of thousands)')
ax.set_ylabel('Hare Population (tens of thousands)')
#ax.legend(loc='best')
ax.set_title('Predator Prey Relationship')
plt.tight_layout()
plt.subplots_adjust(top=0.85)
plt.text(a_Birth/b_Con*0.5,c_Death/d_Food*0.5,r'Q1')
plt.text(a_Birth/b_Con*1.5,c_Death/d_Food*0.5,r'Q2')
plt.text(a_Birth/b_Con*1.5,c_Death/d_Food*1.5,r'Q3')

plt.quiver(X1, Y1, DX1, DY1, M, pivot='mid', cmap=plt.cm.jet)

plt.text(a_Birth/b_Con*0.5,c_Death/d_Food*1.5,r'Q4')
plt.xlim(0,300)
plt.ylim(0,1000)
plt.legend()
plt.show()
```

## Jacobian Matrix
The Loketta-Volterra model [4] can be written in matrix frorm
\begin{equation}
\begin{pmatrix}
\frac{dH}{dt}\\
\frac{dL}{dt}
\end{pmatrix}
=\begin{pmatrix}
a_{Birth} & -b_{Con}L \\
-c_{Death} & d_{Food}H
\end{pmatrix}
\begin{pmatrix}
H \\
L
\end{pmatrix}.
\end{equation}
The point of equilibrium (stability) is when $\frac{dH}{dt}=0$ and $\frac{dL}{dt}=0$,
\begin{equation}
\begin{pmatrix}
0\\
0
\end{pmatrix}
=\begin{pmatrix}
a_{Birth} & -b_{Con}L \\
-c_{Death} & d_{Food}H
\end{pmatrix}
\begin{pmatrix}
H \\
L
\end{pmatrix},
\end{equation}
this gives two solutions for $H$ and $L$:
1. the trivial solution is $H=0$ and $L=0$;
2. the non-trivial solution is $H=\frac{c_{Death}}{d_{Food}}$ and $L=\frac{a_{Birth}}{b_{Con}}$.

# References

[1] Stover, Christopher and Weisstein, Eric W. "Population Growth." From MathWorld--A Wolfram Web Resource. http://mathworld.wolfram.com/PopulationGrowth.html

[2]  Vito Volterra.  Fluctuations in the abundance of a species considered mathematically. Nature,118:558–560,1926.

[3] Alfred J Lotka.   Analytical note on certain rhythmic  relations inorganic  systems.Proceedings of the National Academy of Sciences,6(7):410–415,1920.

[4]

```python
a_Birth*400 -   b_Con*200*400
```

    -6400.0

```python
-c_Death*200 + d_Food*200*400
```

    620.0

```python
dX_dt(400,200)
```

    array([  620., -6400.])

```python

```

.ipynb_checkpoints/08_Snow Hares and Lynxes-Stability-Jacobian-checkpoint.ipynb


# Characterization of Systems in the Time Domain

*This Jupyter notebook is part of a [collection of notebooks](../index.ipynb) in the bachelors module Signals and Systems, Communications Engineering, Universität Rostock. Please direct questions and suggestions to [Sascha.Spors@uni-rostock.de](mailto:Sascha.Spors@uni-rostock.de).*

## Impulse Response

The response $y(t)$ of a linear time-invariant (LTI) system $\mathcal{H}$ to an arbitrary input signal $x(t)$ is derived in the following. The input signal can be represented as an integral when applying the [sifting-property of the Dirac impulse](../continuous_signals/standard_signals.ipynb#Dirac-Impulse)

\begin{equation}
x(t) = \int_{-\infty}^{\infty} x(\tau) \cdot \delta(t-\tau) \; d \tau
\end{equation}

The output signal of the system is then given as

\begin{equation}
y(t) = \mathcal{H} \left\{ \int_{-\infty}^{\infty} x(\tau) \cdot \delta(t-\tau) \; d \tau \right\}
\end{equation}

The integration and system response operator can be exchanged under the assumption that the system is linear

\begin{equation}
y(t) = \int_{-\infty}^{\infty}  x(\tau) \cdot \mathcal{H} \left\{ \delta(t-\tau) \right\} \; d \tau
\end{equation}

where $\mathcal{H} \{\cdot\}$ was only applied to the Dirac impulse, since $x(\tau)$ can be regarded as constant factor with respect to the time $t$. It is obvious that the response of a system to a Dirac impulse plays an important role in the calculation of the output signal for arbitrary input signals.

The response of a system to a Dirac impulse as input signal is denoted as [*impulse response*](https://en.wikipedia.org/wiki/Impulse_response). It is defined as

\begin{equation}
h(t) = \mathcal{H} \left\{ \delta(t) \right\}
\end{equation}

If the system is time-invariant, the response to a shifted Dirac impulse is $\mathcal{H} \left\{ \delta(t-\tau) \right\} = h(t-\tau)$. Hence, for an LTI system we finally get

\begin{equation}
y(t) = \int_{-\infty}^{\infty}  x(\tau) \cdot h(t-\tau) \; d \tau
\end{equation}

Due to its relevance in the theory of LTI systems, this operation is explicitly termed as [*convolution*](https://en.wikipedia.org/wiki/Convolution). It is commonly abbreviated by $*$, hence for above integral we get $y(t) = x(t) * h(t)$.

The properties of an LTI system are entirely characterized by its impulse response. The response $y(t)$ of a system to an arbitrary input signal $x(t)$ is given by the convolution of the input signal $x(t)$ with its impulse response $h(t)$.

**Example**

The following example considers an LTI system whose relation between input $x(t)$ and output $y(t)$ is given by an ordinary differential equation (ODE) with constant coefficients

\begin{equation}
y(t) + \frac{d}{dt} y(t) = x(t)
\end{equation}

The system response is computed for $x(t) = e^{- 2 t} \cdot \epsilon(t)$ by

1. explicitly solving the ODE and by
2. computing the impulse response $h(t)$ and convolution with the input signal.

The solution should fulfill the initial conditions $y(t)\big\vert_{t = 0-} = 0$ and $\frac{d}{dt}y(t)\big\vert_{t = 0-} = 0$ due to causality.

First the ODE is defined in `SymPy`

```python
%matplotlib inline
import sympy as sym
sym.init_printing()

t = sym.symbols('t', real=True)
x = sym.Function('x')(t)
y = sym.Function('y')(t)

ode = sym.Eq(y + y.diff(t) , x)
ode
```

The ODE is solved for the given input signal in order to calculate the output signal. Note that the integration constant is set to zero to fulfill the initial conditions

```python
solution = sym.dsolve(ode.subs(x, sym.exp(-2*t)*sym.Heaviside(t)))
y1 = solution.rhs.subs('C1', 0)
y1
```

Lets plot the output signal derived by explicit solution of the ODE

```python
sym.plot(y1, (t,-1,10), ylabel=r'$y(t)$');
```

The impulse response $h(t)$ is computed by solving the ODE for a Dirac impulse as input signal, $x(t) = \delta(t)$

```python
solution2 = sym.dsolve(ode.subs(x, sym.DiracDelta(t)))
h = solution2.rhs.subs('C1', 0)
h
```

Lets plot the impulse response $h(t)$ of the LTI system

```python
sym.plot(h, (t,-1,10), ylabel=r'$h(t)$');
```

As alternative to the explicit solution of the ODE, the system response is computed by evaluating the convolution integral. Since `SymPy` cannot handle the Heaviside function properly in integrands, the convolution integral is first simplified. Both the input signal $x(t)$ and the impulse response $h(t)$ are causal signals. Hence, the convolution integral degenerates to

\begin{equation}
y(t) = \int_{0}^{t} x(\tau) \cdot h(t - \tau) \; d\tau
\end{equation}

for $t \geq 0$. Note that $y(t) = 0$ for $t<0$.

```python
tau = sym.symbols('tau', real=True)

y2 = sym.integrate(sym.exp(-2*tau) * h.subs(sym.Heaviside(t), 1).subs(t, t-tau), (tau, 0, t))
y2
```

Lets plot the output signal derived by evaluation of the convolution

```python
sym.plot(y2, (t,0,10), ylabel=r'$y(t)$');
```

**Exercise**

* Compare the output signal derived by explicit solution of the ODE with the signal derived by convolution. Are both equal?
* Check if the impulse response $h(t)$ is a solution of the ODE by manual calculation. Hint $\frac{d}{dt} \epsilon(t) = \delta(t)$.
* Check the solution of the convolution integral by manual calculation including the Heaviside functions.

**Copyright**

The notebooks are provided as [Open Educational Resource](https://de.wikipedia.org/wiki/Open_Educational_Resources). Feel free to use the notebooks for your own educational purposes. The text is licensed under [Creative Commons Attribution 4.0](https://creativecommons.org/licenses/by/4.0/), the code of the IPython examples under the [MIT license](https://opensource.org/licenses/MIT). Please attribute the work as follows: *Lecture Notes on Signals and Systems* by Sascha Spors.