Calculating linear adiabatic stellar oscillations
---

**Contributors**:
- [Earl Patrick Bellinger](https://earlbellinger.com), Stellar Astrophysics Centre, Aarhus University, Denmark
- [Warrick Ball](https://warrickball.github.io/), School of Physics and Astronomy, University of Birmingham, UK

**References**:
- *J. Christensen-Dalsgaard, [Lecture Notes on Stellar Oscillations](http://astro.phys.au.dk/~jcd/oscilnotes/)*
- *R. H. Townsend, [GYRE Equations & Variables](https://bitbucket.org/rhdtownsend/gyre/src/tip/doc/equations.pdf)*
- *Press, Teukolsky, Vetterling, and Flannery, [Numerical Recipes in Fortran 77](https://websites.pmc.ucsc.edu/~fnimmo/eart290c_17/NumericalRecipesinF77.pdf)*

```python
import numpy as np
import pandas as pd
from scipy import integrate
from scipy.interpolate import InterpolatedUnivariateSpline
```

```python
import matplotlib.pyplot as plt
import seaborn as sns
sns.set(style="ticks",
        palette="muted",
        rc={"xtick.bottom" : True, "ytick.left" : True})
plt.style.use('matplotlibrc')
```

Begin by loading a stellar model; in this case, we will use JCD's Model S of the present Sun.

```python
modelS = pd.read_table('modelS.dat')
modelS = modelS.reindex(index=modelS.index[::-1]) # reverse, reverse!
modelS
```

      x
      m
      c2
      u
      Y
      r
      q
      T
      P
      rho
      ...
      r_X
      Z
      R_min_r
      eps_g
      L_g
      X_He3
      X_C12
      X_C13
      X_N14
      X_O16

      2481
      1.436803e-60
      1.989000e-27
      2.546774e+15
      1.526582e+15
      0.642473
      1.000000e-49
      -1.381551e+02
      1.566847e+07
      2.349248e+17
      1.538894e+02
      ...
      -2.773489e-18
      0.020313
      6.959895e+10
      -0.122841
      0.0
      0.000008
      0.0
      0.0
      0.005131
      0.009162

      2480
      1.391083e-03
      5.849560e+26
      2.546840e+15
      1.526622e+15
      0.642407
      9.681792e+07
      -1.503936e+01
      1.566779e+07
      2.348937e+17
      1.538650e+02
      ...
      -2.773025e-18
      0.020313
      6.950213e+10
      -0.122841
      0.0
      0.000008
      0.0
      0.0
      0.005131
      0.009162

      2479
      1.409791e-03
      6.088733e+26
      2.546840e+15
      1.526622e+15
      0.642406
      9.811996e+07
      -1.499929e+01
      1.566777e+07
      2.348929e+17
      1.538645e+02
      ...
      -2.773007e-18
      0.020313
      6.950083e+10
      -0.122835
      0.0
      0.000008
      0.0
      0.0
      0.005131
      0.009162

      2478
      1.428750e-03
      6.337684e+26
      2.546844e+15
      1.526624e+15
      0.642404
      9.943950e+07
      -1.495921e+01
      1.566776e+07
      2.348920e+17
      1.538637e+02
      ...
      -2.773000e-18
      0.020313
      6.949951e+10
      -0.122843
      0.0
      0.000008
      0.0
      0.0
      0.005131
      0.009162

      2477
      1.447964e-03
      6.596813e+26
      2.546847e+15
      1.526626e+15
      0.642401
      1.007768e+08
      -1.491914e+01
      1.566774e+07
      2.348911e+17
      1.538629e+02
      ...
      -2.772992e-18
      0.020313
      6.949817e+10
      -0.122844
      0.0
      0.000008
      0.0
      0.0
      0.005131
      0.009162

      2476
      1.467437e-03
      6.866537e+26
      2.546851e+15
      1.526628e+15
      0.642399
      1.021321e+08
      -1.487907e+01
      1.566772e+07
      2.348902e+17
      1.538621e+02
      ...
      -2.772985e-18
      0.020313
      6.949681e+10
      -0.122841
      0.0
      0.000008
      0.0
      0.0
      0.005131
      0.009162

      2475
      1.487172e-03
      7.147288e+26
      2.546853e+15
      1.526630e+15
      0.642396
      1.035056e+08
      -1.483899e+01
      1.566770e+07
      2.348893e+17
      1.538613e+02
      ...
      -2.772978e-18
      0.020313
      6.949544e+10
      -0.122842
      0.0
      0.000008
      0.0
      0.0
      0.005131
      0.009162

      2474
      1.507171e-03
      7.439517e+26
      2.546857e+15
      1.526632e+15
      0.642394
      1.048975e+08
      -1.479892e+01
      1.566768e+07
      2.348884e+17
      1.538605e+02
      ...
      -2.772969e-18
      0.020313
      6.949405e+10
      -0.122843
      0.0
      0.000008
      0.0
      0.0
      0.005131
      0.009162

      2473
      1.527440e-03
      7.743694e+26
      2.546861e+15
      1.526635e+15
      0.642391
      1.063082e+08
      -1.475885e+01
      1.566765e+07
      2.348874e+17
      1.538596e+02
      ...
      -2.772960e-18
      0.020313
      6.949264e+10
      -0.122845
      0.0
      0.000008
      0.0
      0.0
      0.005131
      0.009162

      2472
      1.547982e-03
      8.060307e+26
      2.546864e+15
      1.526637e+15
      0.642388
      1.077379e+08
      -1.471878e+01
      1.566763e+07
      2.348864e+17
      1.538587e+02
      ...
      -2.772951e-18
      0.020313
      6.949121e+10
      -0.122845
      0.0
      0.000008
      0.0
      0.0
      0.005131
      0.009162

      2471
      1.568800e-03
      8.389864e+26
      2.546868e+15
      1.526639e+15
      0.642386
      1.091868e+08
      -1.467870e+01
      1.566761e+07
      2.348853e+17
      1.538578e+02
      ...
      -2.772941e-18
      0.020313
      6.948976e+10
      -0.122846
      0.0
      0.000008
      0.0
      0.0
      0.005130
      0.009162

      2470
      1.589897e-03
      8.732894e+26
      2.546871e+15
      1.526641e+15
      0.642383
      1.106552e+08
      -1.463863e+01
      1.566759e+07
      2.348843e+17
      1.538569e+02
      ...
      -2.772931e-18
      0.020313
      6.948829e+10
      -0.122847
      0.0
      0.000008
      0.0
      0.0
      0.005130
      0.009162

      2469
      1.611279e-03
      9.089949e+26
      2.546875e+15
      1.526643e+15
      0.642380
      1.121433e+08
      -1.459856e+01
      1.566756e+07
      2.348832e+17
      1.538560e+02
      ...
      -2.772920e-18
      0.020313
      6.948680e+10
      -0.122850
      0.0
      0.000008
      0.0
      0.0
      0.005130
      0.009162

      2468
      1.632948e-03
      9.461602e+26
      2.546878e+15
      1.526645e+15
      0.642377
      1.136514e+08
      -1.455849e+01
      1.566754e+07
      2.348820e+17
      1.538550e+02
      ...
      -2.772908e-18
      0.020313
      6.948530e+10
      -0.122848
      0.0
      0.000008
      0.0
      0.0
      0.005130
      0.009163

      2467
      1.654908e-03
      9.848449e+26
      2.546882e+15
      1.526647e+15
      0.642374
      1.151798e+08
      -1.451841e+01
      1.566751e+07
      2.348808e+17
      1.538540e+02
      ...
      -2.772896e-18
      0.020313
      6.948377e+10
      -0.122851
      0.0
      0.000008
      0.0
      0.0
      0.005130
      0.009163

      2466
      1.677164e-03
      1.025111e+27
      2.546885e+15
      1.526650e+15
      0.642371
      1.167288e+08
      -1.447834e+01
      1.566749e+07
      2.348797e+17
      1.538530e+02
      ...
      -2.772885e-18
      0.020313
      6.948222e+10
      -0.122851
      0.0
      0.000008
      0.0
      0.0
      0.005130
      0.009163

      2465
      1.699719e-03
      1.067024e+27
      2.546890e+15
      1.526652e+15
      0.642368
      1.182986e+08
      -1.443827e+01
      1.566746e+07
      2.348784e+17
      1.538520e+02
      ...
      -2.772872e-18
      0.020313
      6.948065e+10
      -0.122851
      0.0
      0.000008
      0.0
      0.0
      0.005130
      0.009163

      2464
      1.722577e-03
      1.110650e+27
      2.546893e+15
      1.526654e+15
      0.642365
      1.198895e+08
      -1.439820e+01
      1.566743e+07
      2.348772e+17
      1.538510e+02
      ...
      -2.772860e-18
      0.020313
      6.947906e+10
      -0.122852
      0.0
      0.000008
      0.0
      0.0
      0.005130
      0.009163

      2463
      1.745743e-03
      1.156059e+27
      2.546897e+15
      1.526656e+15
      0.642362
      1.215018e+08
      -1.435813e+01
      1.566740e+07
      2.348759e+17
      1.538499e+02
      ...
      -2.772847e-18
      0.020313
      6.947744e+10
      -0.122852
      0.0
      0.000008
      0.0
      0.0
      0.005130
      0.009163

      2462
      1.769220e-03
      1.203325e+27
      2.546902e+15
      1.526659e+15
      0.642359
      1.231358e+08
      -1.431805e+01
      1.566738e+07
      2.348746e+17
      1.538488e+02
      ...
      -2.772831e-18
      0.020314
      6.947581e+10
      -0.122856
      0.0
      0.000008
      0.0
      0.0
      0.005130
      0.009163

      2461
      1.793013e-03
      1.252524e+27
      2.546906e+15
      1.526661e+15
      0.642355
      1.247918e+08
      -1.427798e+01
      1.566735e+07
      2.348733e+17
      1.538477e+02
      ...
      -2.772816e-18
      0.020314
      6.947415e+10
      -0.122857
      0.0
      0.000008
      0.0
      0.0
      0.005130
      0.009163

      2460
      1.817126e-03
      1.303733e+27
      2.546910e+15
      1.526664e+15
      0.642352
      1.264700e+08
      -1.423791e+01
      1.566732e+07
      2.348719e+17
      1.538465e+02
      ...
      -2.772800e-18
      0.020314
      6.947248e+10
      -0.122858
      0.0
      0.000008
      0.0
      0.0
      0.005130
      0.009163

      2459
      1.841563e-03
      1.357037e+27
      2.546914e+15
      1.526666e+15
      0.642348
      1.281709e+08
      -1.419784e+01
      1.566728e+07
      2.348704e+17
      1.538453e+02
      ...
      -2.772784e-18
      0.020314
      6.947078e+10
      -0.122857
      0.0
      0.000008
      0.0
      0.0
      0.005130
      0.009163

      2458
      1.866329e-03
      1.412519e+27
      2.546918e+15
      1.526669e+15
      0.642345
      1.298945e+08
      -1.415777e+01
      1.566725e+07
      2.348689e+17
      1.538440e+02
      ...
      -2.772770e-18
      0.020314
      6.946905e+10
      -0.122859
      0.0
      0.000008
      0.0
      0.0
      0.005130
      0.009163

      2457
      1.891428e-03
      1.470270e+27
      2.546924e+15
      1.526672e+15
      0.642341
      1.316414e+08
      -1.411770e+01
      1.566722e+07
      2.348674e+17
      1.538427e+02
      ...
      -2.772755e-18
      0.020313
      6.946731e+10
      -0.122857
      0.0
      0.000008
      0.0
      0.0
      0.005130
      0.009163

      2456
      1.916865e-03
      1.530381e+27
      2.546928e+15
      1.526675e+15
      0.642337
      1.334118e+08
      -1.407763e+01
      1.566718e+07
      2.348659e+17
      1.538414e+02
      ...
      -2.772739e-18
      0.020313
      6.946554e+10
      -0.122861
      0.0
      0.000008
      0.0
      0.0
      0.005130
      0.009163

      2455
      1.942643e-03
      1.592950e+27
      2.546932e+15
      1.526677e+15
      0.642334
      1.352059e+08
      -1.403755e+01
      1.566715e+07
      2.348642e+17
      1.538401e+02
      ...
      -2.772718e-18
      0.020313
      6.946374e+10
      -0.122864
      0.0
      0.000008
      0.0
      0.0
      0.005130
      0.009163

      2454
      1.968769e-03
      1.658077e+27
      2.546934e+15
      1.526679e+15
      0.642330
      1.370242e+08
      -1.399748e+01
      1.566711e+07
      2.348626e+17
      1.538389e+02
      ...
      -2.772691e-18
      0.020314
      6.946192e+10
      -0.122863
      0.0
      0.000008
      0.0
      0.0
      0.005130
      0.009163

      2453
      1.995245e-03
      1.725866e+27
      2.546936e+15
      1.526680e+15
      0.642327
      1.388670e+08
      -1.395741e+01
      1.566708e+07
      2.348609e+17
      1.538377e+02
      ...
      -2.772660e-18
      0.020314
      6.946008e+10
      -0.122865
      0.0
      0.000008
      0.0
      0.0
      0.005130
      0.009163

      2452
      2.022078e-03
      1.796427e+27
      2.546938e+15
      1.526681e+15
      0.642324
      1.407345e+08
      -1.391734e+01
      1.566704e+07
      2.348592e+17
      1.538365e+02
      ...
      -2.772630e-18
      0.020314
      6.945821e+10
      -0.122867
      0.0
      0.000008
      0.0
      0.0
      0.005130
      0.009163

      ...
      ...
      ...
      ...
      ...
      ...
      ...
      ...
      ...
      ...
      ...
      ...
      ...
      ...
      ...
      ...
      ...
      ...
      ...
      ...
      ...
      ...

      29
      1.000470e+00
      1.989000e+33
      4.788354e+11
      2.901145e+11
      0.244686
      6.963165e+10
      7.973501e-11
      4.398485e+03
      4.714738e+03
      1.625130e-08
      ...
      0.000000e+00
      0.018062
      -3.270773e+07
      0.000000
      0.0
      0.000000
      0.0
      0.0
      0.004588
      0.009782

      28
      1.000479e+00
      1.989000e+33
      4.784068e+11
      2.897940e+11
      0.244686
      6.963226e+10
      8.002657e-11
      4.393452e+03
      4.453802e+03
      1.536886e-08
      ...
      0.000000e+00
      0.018062
      -3.331030e+07
      0.000000
      0.0
      0.000000
      0.0
      0.0
      0.004588
      0.009782

      27
      1.000487e+00
      1.989000e+33
      4.780145e+11
      2.895039e+11
      0.244686
      6.963286e+10
      8.030187e-11
      4.388879e+03
      4.207418e+03
      1.453320e-08
      ...
      0.000000e+00
      0.018062
      -3.391195e+07
      0.000000
      0.0
      0.000000
      0.0
      0.0
      0.004588
      0.009782

      26
      1.000496e+00
      1.989000e+33
      4.776405e+11
      2.892411e+11
      0.244686
      6.963346e+10
      8.056178e-11
      4.384728e+03
      3.974810e+03
      1.374220e-08
      ...
      0.000000e+00
      0.018062
      -3.451264e+07
      0.000000
      0.0
      0.000000
      0.0
      0.0
      0.004588
      0.009782

      25
      1.000504e+00
      1.989000e+33
      4.772775e+11
      2.890034e+11
      0.244686
      6.963406e+10
      8.080713e-11
      4.380963e+03
      3.755231e+03
      1.299373e-08
      ...
      0.000000e+00
      0.018062
      -3.511233e+07
      0.000000
      0.0
      0.000000
      0.0
      0.0
      0.004588
      0.009782

      24
      1.000513e+00
      1.989000e+33
      4.769468e+11
      2.887891e+11
      0.244686
      6.963466e+10
      8.103871e-11
      4.377549e+03
      3.547971e+03
      1.228568e-08
      ...
      0.000000e+00
      0.018062
      -3.571099e+07
      0.000000
      0.0
      0.000000
      0.0
      0.0
      0.004588
      0.009782

      23
      1.000522e+00
      1.989000e+33
      4.766379e+11
      2.885958e+11
      0.244686
      6.963526e+10
      8.125729e-11
      4.374455e+03
      3.352358e+03
      1.161610e-08
      ...
      0.000000e+00
      0.018062
      -3.630858e+07
      0.000000
      0.0
      0.000000
      0.0
      0.0
      0.004588
      0.009782

      22
      1.000530e+00
      1.989000e+33
      4.763382e+11
      2.884215e+11
      0.244686
      6.963585e+10
      8.146357e-11
      4.371654e+03
      3.167748e+03
      1.098305e-08
      ...
      0.000000e+00
      0.018062
      -3.690507e+07
      0.000000
      0.0
      0.000000
      0.0
      0.0
      0.004588
      0.009782

      21
      1.000539e+00
      1.989000e+33
      4.760390e+11
      2.882645e+11
      0.244686
      6.963645e+10
      8.165823e-11
      4.369119e+03
      2.993533e+03
      1.038467e-08
      ...
      0.000000e+00
      0.018062
      -3.750041e+07
      0.000000
      0.0
      0.000000
      0.0
      0.0
      0.004588
      0.009782

      20
      1.000547e+00
      1.989000e+33
      4.757339e+11
      2.881227e+11
      0.244686
      6.963704e+10
      8.184193e-11
      4.366824e+03
      2.829134e+03
      9.819198e-09
      ...
      0.000000e+00
      0.018062
      -3.809456e+07
      0.000000
      0.0
      0.000000
      0.0
      0.0
      0.004588
      0.009782

      19
      1.000556e+00
      1.989000e+33
      4.754312e+11
      2.879952e+11
      0.244686
      6.963763e+10
      8.201526e-11
      4.364749e+03
      2.674004e+03
      9.284891e-09
      ...
      0.000000e+00
      0.018062
      -3.868749e+07
      0.000000
      0.0
      0.000000
      0.0
      0.0
      0.004588
      0.009782

      18
      1.000564e+00
      1.989000e+33
      4.751352e+11
      2.878806e+11
      0.244686
      6.963823e+10
      8.217882e-11
      4.362873e+03
      2.527627e+03
      8.780122e-09
      ...
      0.000000e+00
      0.018062
      -3.927915e+07
      0.000000
      0.0
      0.000000
      0.0
      0.0
      0.004588
      0.009782

      17
      1.000573e+00
      1.989000e+33
      4.748481e+11
      2.877782e+11
      0.244686
      6.963882e+10
      8.233315e-11
      4.361178e+03
      2.389510e+03
      8.303304e-09
      ...
      0.000000e+00
      0.018062
      -3.986950e+07
      0.000000
      0.0
      0.000000
      0.0
      0.0
      0.004588
      0.009782

      16
      1.000581e+00
      1.989000e+33
      4.745713e+11
      2.876871e+11
      0.244686
      6.963941e+10
      8.247877e-11
      4.359646e+03
      2.259191e+03
      7.852946e-09
      ...
      0.000000e+00
      0.018062
      -4.045848e+07
      0.000000
      0.0
      0.000000
      0.0
      0.0
      0.004588
      0.009782

      15
      1.000590e+00
      1.989000e+33
      4.743060e+11
      2.876066e+11
      0.244686
      6.963999e+10
      8.261615e-11
      4.358261e+03
      2.136238e+03
      7.427640e-09
      ...
      0.000000e+00
      0.018062
      -4.104602e+07
      0.000000
      0.0
      0.000000
      0.0
      0.0
      0.004588
      0.009782

      14
      1.000598e+00
      1.989000e+33
      4.740555e+11
      2.875354e+11
      0.244686
      6.964058e+10
      8.274576e-11
      4.357011e+03
      2.020244e+03
      7.026070e-09
      ...
      0.000000e+00
      0.018062
      -4.163201e+07
      0.000000
      0.0
      0.000000
      0.0
      0.0
      0.004588
      0.009782

      13
      1.000607e+00
      1.989000e+33
      4.738172e+11
      2.874726e+11
      0.244686
      6.964116e+10
      8.286803e-11
      4.355883e+03
      1.910823e+03
      6.646976e-09
      ...
      0.000000e+00
      0.018062
      -4.221635e+07
      0.000000
      0.0
      0.000000
      0.0
      0.0
      0.004588
      0.009782

      12
      1.000615e+00
      1.989000e+33
      4.735870e+11
      2.874178e+11
      0.244686
      6.964175e+10
      8.298335e-11
      4.354864e+03
      1.807613e+03
      6.289148e-09
      ...
      0.000000e+00
      0.018062
      -4.279893e+07
      0.000000
      0.0
      0.000000
      0.0
      0.0
      0.004588
      0.009782

      11
      1.000623e+00
      1.989000e+33
      4.733620e+11
      2.873703e+11
      0.244686
      6.964233e+10
      8.309212e-11
      4.353944e+03
      1.710269e+03
      5.951447e-09
      ...
      0.000000e+00
      0.018062
      -4.337961e+07
      0.000000
      0.0
      0.000000
      0.0
      0.0
      0.004588
      0.009782

      10
      1.000632e+00
      1.989000e+33
      4.731407e+11
      2.873299e+11
      0.244686
      6.964291e+10
      8.319470e-11
      4.353114e+03
      1.618466e+03
      5.632782e-09
      ...
      0.000000e+00
      0.018062
      -4.395827e+07
      0.000000
      0.0
      0.000000
      0.0
      0.0
      0.004588
      0.009782

      9
      1.000640e+00
      1.989000e+33
      4.729276e+11
      2.872959e+11
      0.244686
      6.964348e+10
      8.329143e-11
      4.352365e+03
      1.531898e+03
      5.332127e-09
      ...
      0.000000e+00
      0.018062
      -4.453475e+07
      0.000000
      0.0
      0.000000
      0.0
      0.0
      0.004588
      0.009782

      8
      1.000648e+00
      1.989000e+33
      4.727250e+11
      2.872676e+11
      0.244686
      6.964406e+10
      8.338264e-11
      4.351689e+03
      1.450275e+03
      5.048516e-09
      ...
      0.000000e+00
      0.018062
      -4.510889e+07
      0.000000
      0.0
      0.000000
      0.0
      0.0
      0.004588
      0.009782

      7
      1.000656e+00
      1.989000e+33
      4.725273e+11
      2.872444e+11
      0.244686
      6.964463e+10
      8.346862e-11
      4.351080e+03
      1.373325e+03
      4.781032e-09
      ...
      0.000000e+00
      0.018062
      -4.568051e+07
      0.000000
      0.0
      0.000000
      0.0
      0.0
      0.004588
      0.009782

      6
      1.000665e+00
      1.989000e+33
      4.723314e+11
      2.872260e+11
      0.244686
      6.964520e+10
      8.354967e-11
      4.350530e+03
      1.300789e+03
      4.528800e-09
      ...
      0.000000e+00
      0.018062
      -4.624943e+07
      0.000000
      0.0
      0.000000
      0.0
      0.0
      0.004588
      0.009782

      5
      1.000673e+00
      1.989000e+33
      4.721342e+11
      2.872116e+11
      0.244686
      6.964576e+10
      8.362607e-11
      4.350034e+03
      1.232423e+03
      4.290995e-09
      ...
      0.000000e+00
      0.018062
      -4.681541e+07
      0.000000
      0.0
      0.000000
      0.0
      0.0
      0.004588
      0.009782

      4
      1.000681e+00
      1.989000e+33
      4.719381e+11
      2.872010e+11
      0.244686
      6.964633e+10
      8.369805e-11
      4.349587e+03
      1.168000e+03
      4.066838e-09
      ...
      0.000000e+00
      0.018062
      -4.737825e+07
      0.000000
      0.0
      0.000000
      0.0
      0.0
      0.004588
      0.009782

      3
      1.000689e+00
      1.989000e+33
      4.717500e+11
      2.871941e+11
      0.244686
      6.964688e+10
      8.376588e-11
      4.349183e+03
      1.107302e+03
      3.855586e-09
      ...
      0.000000e+00
      0.018062
      -4.793767e+07
      0.000000
      0.0
      0.000000
      0.0
      0.0
      0.004588
      0.009782

      2
      1.000697e+00
      1.989000e+33
      4.715659e+11
      2.871905e+11
      0.244686
      6.964744e+10
      8.382977e-11
      4.348819e+03
      1.050125e+03
      3.656545e-09
      ...
      0.000000e+00
      0.018062
      -4.849342e+07
      0.000000
      0.0
      0.000000
      0.0
      0.0
      0.004588
      0.009782

      1
      1.000705e+00
      1.989000e+33
      4.713826e+11
      2.871900e+11
      0.244686
      6.964799e+10
      8.388994e-11
      4.348491e+03
      9.962773e+02
      3.469053e-09
      ...
      0.000000e+00
      0.018062
      -4.904521e+07
      0.000000
      0.0
      0.000000
      0.0
      0.0
      0.004588
      0.009782

      0
      1.000713e+00
      1.989000e+33
      4.711982e+11
      2.871925e+11
      0.244686
      6.964854e+10
      8.394659e-11
      4.348196e+03
      9.455764e+02
      3.292483e-09
      ...
      0.000000e+00
      0.018062
      -4.959271e+07
      0.000000
      0.0
      0.000000
      0.0
      0.0
      0.004588
      0.009782

2482 rows × 30 columns

```python
# constants
# TODO: tie in with TOMSO and grab from fgong directly
M = 1.989000000E+33 # g
R = 6.959894677E+10 # cm
G = 6.67428e-8

# coordinates
r = modelS['r'].values
x = modelS['x'].values
m = modelS['m'].values

def spline(var_name):
    return InterpolatedUnivariateSpline(x, modelS[var_name].values)

# dimensional variables
cs2    = spline('c2')
P      = spline('P')
rho    = spline('rho')
Gamma1 = spline('Gamma1')

# dimensionless mechanical variables
Astar = spline('conv_stab')

c1    = r**3/R**3 * M/m
c1[0] = 1/(4.*np.pi*rho(x[0])/3) * M/R**3
#1[0] = 0
c1    = InterpolatedUnivariateSpline(x, c1)

V = -np.gradient(np.log(P(x)), np.log(r))
U = 4.*np.pi*r**3*rho(x)/m

V[0] = 0
U[0] = 3

V = InterpolatedUnivariateSpline(x, V)
U = InterpolatedUnivariateSpline(x, U)
Vg = lambda x: V(x)/Gamma1(x)

#g   = InterpolatedUnivariateSpline(x, G*m/r**2)
#N2  = lambda y: g(y) * InterpolatedUnivariateSpline(x, Astar)(y)
```

```python
plt.figure(figsize=(9,8))

plt.subplot(221)
plt.plot(x, np.sqrt(cs2(x)),
        label=r'$c_s^2 = \Gamma_1 P/\rho$')
plt.legend()
plt.ylabel(r'sound speed $c_s$ [cm$/$sec]')

plt.subplot(222)
plt.plot(x, P(x))
plt.ylabel(r'pressure $P$ [dyn$/$cm$^2$]')

plt.subplot(223)
plt.plot(x, rho(x))
plt.xlabel(r'fractional radius $x\equiv r/R$')
plt.ylabel(r'density $\rho$ [g$/$cm$^3$]')

plt.subplot(224)
plt.plot(x, Gamma1(x),
        label=r'$\Gamma_1 = '\
         r'\left('\
             r'\dfrac{\mathrm{d}\,\ln\, P}{\mathrm{d}\,\ln\, \rho}'\
         r'\right)_{\mathrm{ad}}$')
plt.legend()
plt.xlabel(r'fractional radius $x\equiv r/R$')
plt.ylabel(r'adiabatic compressability $\Gamma_1$')

plt.tight_layout()
plt.show()
```

```python
# zoom into the core
x_ = x[:20]

plt.figure(figsize=(9,8))

plt.subplot(221)
plt.plot(x_, np.sqrt(cs2(x_)), 'k.-',
        label=r'$c_s^2 = \Gamma_1 P/\rho$')
plt.legend()
plt.ylabel(r'sound speed $c_s$ [cm$/$sec]')

plt.subplot(222)
plt.plot(x_, P(x_), 'k.-')
plt.ylabel(r'pressure $P$ [dyn$/$cm$^2$]')

plt.subplot(223)
plt.plot(x_, rho(x_), 'k.-')
plt.xlabel(r'fractional radius $x\equiv r/R$')
plt.ylabel(r'density $\rho$ [g$/$cm$^3$]')

plt.subplot(224)
plt.plot(x_, Gamma1(x_), 'k.-',
        label=r'$\Gamma_1 = '\
         r'\left('\
             r'\dfrac{\mathrm{d}\,\ln\, P}{\mathrm{d}\,\ln\, \rho}'\
         r'\right)_{\mathrm{ad}}$')
plt.legend()
plt.xlabel(r'fractional radius $x\equiv r/R$')
plt.ylabel(r'adiabatic compressability $\Gamma_1$')

plt.tight_layout()
plt.show()
```

```python
plt.figure(figsize=(9,8))

plt.subplot(221)
plt.plot(x, c1(x),
         label=r'$c_1 = \dfrac{r^3}{R^3} \, \dfrac{M}{m}$')
plt.legend()
plt.ylabel(r'$c_1$')

plt.subplot(222)
plt.plot(x, U(x),
        label=r'$U=\dfrac{\mathrm{d}\, \ln \, m}{\mathrm{d}\, \ln\, r}$')
plt.legend()
plt.ylabel(r'$U$')

plt.subplot(223)
plt.plot(x, V(x),
        label=r'$V=-\dfrac{\mathrm{d}\, \ln\, P}{\mathrm{d}\, \ln\, r}$')
plt.legend()
plt.xlabel(r'fractional radius $x\equiv r/R$')
plt.ylabel(r'$V$')

plt.subplot(224)
plt.plot(x, Astar(x),
        label=r'$A^\ast = \frac{1}{\Gamma_1}'\
         r'\frac{\mathrm{d}\,\ln\,P}{\mathrm{d}\,\ln\,r} - '\
         r'\frac{\mathrm{d}\,\ln\,\rho}{\mathrm{d}\,\ln\,r}$')
plt.legend()
plt.xlabel(r'fractional radius $x\equiv r/R$')
plt.ylabel(r'$A^\ast$')

plt.tight_layout()
plt.show()
```

```python
plt.figure(figsize=(9,8))

plt.subplot(221)
plt.plot(x_, c1(x_), 'k.-',
         label=r'$c_1 = \dfrac{r^3}{R^3} \, \dfrac{M}{m}$')
plt.legend()
plt.ylabel(r'$c_1$')

plt.subplot(222)
plt.plot(x_, U(x_), 'k.-',
        label=r'$U=\dfrac{\mathrm{d}\, \ln \, m}{\mathrm{d}\, \ln\, r}$')
plt.legend()
plt.ylabel(r'$U$')

plt.subplot(223)
plt.plot(x_, V(x_), 'k.-',
        label=r'$V=-\dfrac{\mathrm{d}\, \ln\, P}{\mathrm{d}\, \ln\, r}$')
plt.legend()
plt.xlabel(r'fractional radius $x\equiv r/R$')
plt.ylabel(r'$V$')

plt.subplot(224)
plt.plot(x_, Astar(x_), 'k.-',
        label=r'$\frac{1}{\Gamma_1}'\
         r'\frac{\mathrm{d}\,\ln\,P}{\mathrm{d}\,\ln\,r} - '\
         r'\frac{\mathrm{d}\,\ln\,\rho}{\mathrm{d}\,\ln\,r}$')
plt.legend()
plt.xlabel(r'fractional radius $x\equiv r/R$')
plt.ylabel(r'$A^\ast$')

plt.tight_layout()
plt.show()
```

Radial oscillations
---

**Reference**: *R. H. Townsend, [GYRE Equations & Variables](https://bitbucket.org/rhdtownsend/gyre/src/tip/doc/equations.pdf)*

Define dimensionless variables
\begin{align}
    x &= \frac{r}{R_\ast} \\
    y_1 &= x^2 \frac{\xi_r}{r} \\
    y_2 &= x^2 \frac{P'}{\rho g r}
\end{align}

Then solve the system of equations
\begin{align}
    x \frac{\text{d}y_1}{\text{d}x}
    &=
    \left(
        \frac{V}{\Gamma_1}
        -
        1
    \right)
    y_1
    +
    \frac{V}{\Gamma_1} y_2\\
    x \frac{\text{d}y_2}{\text{d}x}
    &=
    \left(
        c_1 \omega^2
        +
        U
        -
        A^*
    \right)
    y_1
    +
    \left(
        3
        -
        U
        +
        A^*
    \right)
    y_2
\end{align}
with a regularity-enforcing inner boundary condition:
\begin{equation}
    c_1 \omega^2 y_1 = \ell y_2
\end{equation}
and the vacuum surface pressure condition at the outer boundary:
\begin{equation}
    y_1 - y_2 = 0.
\end{equation}

```python
nu = 3090
nu = 0.3998014585387239E+004 # l = 0, n = 28
omega = 2.*np.pi*nu*10**-6*np.sqrt(R**3/G/M)
omega
```

    40.032124728286185

```python
def radial(x, y):
    if x == 0:
        return np.vstack((0, 0))
    dy1_dx = (Vg(x) - 1) * y[0] - \
              Vg(x)      * y[1]
    dy2_dx = (c1(x) * omega**2 + U(x) - Astar(x)) * y[0] + \
             (3                - U(x) + Astar(x)) * y[1]
    return np.vstack((dy1_dx/x, dy2_dx/x))
```

**Shooting method**
- Treat as an initial value problem and integrate outward from the core boundary condition
- Guess the unconstrained inner boundary and optimize it
- The eigenfrequencies are the solutions $\omega$ that satisfy the surface boundary condition

```python
# y1 = 0 at the inner boundary
# guess an inner boundary for y2
y2_0 = 0.8058888323526826E+000
```

```python
res = integrate.solve_ivp(
    fun=radial,
    t_span=(0, x[-1]),
    y0=[0, y2_0],
    vectorized=True,
    method='RK45',
    atol=1e-9,
    rtol=1e-9,
    t_eval=x)
```

```python
res
```

      message: 'The solver successfully reached the end of the integration interval.'
         nfev: 11648
         njev: 0
          nlu: 0
          sol: None
       status: 0
      success: True
            t: array([1.43680335e-60, 1.39108313e-03, 1.40979085e-03, ...,
           1.00069676e+00, 1.00070468e+00, 1.00071255e+00])
     t_events: None
            y: array([[-3.75449693e-111, -2.09206324e-003, -2.06566151e-003, ...,
             1.71670091e+004,  1.72218031e+004,  1.72719782e+004],
           [ 8.05888832e-001,  6.37259699e-001,  6.36771547e-001, ...,
             1.53899210e+004,  1.55738661e+004,  1.57597528e+004]])

```python
# outer boundary condition: y1=y2
res.y[0,-1] - res.y[1,-1]
```

    1512.2254639214461

```python
xi_r = res.y[0] * r / x**2
xi_r[0] = 0
#plt.plot(res.t, res.y[0])
plt.plot(res.t[:-500], xi_r[:-500])
#plt.plot(res.t, xi_r)
plt.xlabel(r'$r/R$')
plt.ylabel(r'$\xi_r$')
plt.show()
```

Compare with the results from GYRE

```python
eig = pd.read_table('modelS-gyre/00028-000_+00028', skiprows=5, sep='\\s+')
eig
```

      M_r
      x
      Re(xi_r)
      Im(xi_r)
      Re(xi_h)
      Im(xi_h)
      Re(eul_P)
      Im(eul_P)
      Re(y_1)
      Im(y_1)
      Re(y_2)
      Im(y_2)

      0
      0.000000e+00
      0.000000
      0.000000
      0.0
      0.0
      0.0
      1.100142e+02
      0.0
      0.000000
      -0.0
      0.805889
      -0.0

      1
      5.849560e+26
      0.001391
      -0.019823
      0.0
      0.0
      0.0
      1.099306e+02
      0.0
      -0.000028
      0.0
      0.805374
      -0.0

      2
      6.088733e+26
      0.001410
      -0.020517
      0.0
      0.0
      0.0
      1.099298e+02
      0.0
      -0.000029
      0.0
      0.805370
      -0.0

      3
      6.337684e+26
      0.001429
      -0.021209
      0.0
      0.0
      0.0
      1.099290e+02
      0.0
      -0.000030
      0.0
      0.805367
      -0.0

      4
      6.596813e+26
      0.001448
      -0.021899
      0.0
      0.0
      0.0
      1.099282e+02
      0.0
      -0.000032
      0.0
      0.805364
      -0.0

      5
      6.866537e+26
      0.001467
      -0.022588
      0.0
      0.0
      0.0
      1.099273e+02
      0.0
      -0.000033
      0.0
      0.805361
      -0.0

      6
      7.147288e+26
      0.001487
      -0.023276
      0.0
      0.0
      0.0
      1.099264e+02
      0.0
      -0.000035
      0.0
      0.805358
      -0.0

      7
      7.439517e+26
      0.001507
      -0.023962
      0.0
      0.0
      0.0
      1.099254e+02
      0.0
      -0.000036
      0.0
      0.805354
      -0.0

      8
      7.743694e+26
      0.001527
      -0.024649
      0.0
      0.0
      0.0
      1.099244e+02
      0.0
      -0.000038
      0.0
      0.805351
      -0.0

      9
      8.060307e+26
      0.001548
      -0.025334
      0.0
      0.0
      0.0
      1.099234e+02
      0.0
      -0.000039
      0.0
      0.805347
      -0.0

      10
      8.389864e+26
      0.001569
      -0.026020
      0.0
      0.0
      0.0
      1.099223e+02
      0.0
      -0.000041
      0.0
      0.805342
      -0.0

      11
      8.732894e+26
      0.001590
      -0.026706
      0.0
      0.0
      0.0
      1.099211e+02
      0.0
      -0.000042
      0.0
      0.805338
      -0.0

      12
      9.089949e+26
      0.001611
      -0.027392
      0.0
      0.0
      0.0
      1.099199e+02
      0.0
      -0.000044
      0.0
      0.805333
      -0.0

      13
      9.461602e+26
      0.001633
      -0.028079
      0.0
      0.0
      0.0
      1.099187e+02
      0.0
      -0.000046
      0.0
      0.805328
      -0.0

      14
      9.848449e+26
      0.001655
      -0.028766
      0.0
      0.0
      0.0
      1.099174e+02
      0.0
      -0.000048
      0.0
      0.805323
      -0.0

      15
      1.025111e+27
      0.001677
      -0.029455
      0.0
      0.0
      0.0
      1.099161e+02
      0.0
      -0.000049
      0.0
      0.805317
      -0.0

      16
      1.067024e+27
      0.001700
      -0.030145
      0.0
      0.0
      0.0
      1.099147e+02
      0.0
      -0.000051
      0.0
      0.805312
      -0.0

      17
      1.110650e+27
      0.001723
      -0.030836
      0.0
      0.0
      0.0
      1.099133e+02
      0.0
      -0.000053
      0.0
      0.805305
      -0.0

      18
      1.156059e+27
      0.001746
      -0.031529
      0.0
      0.0
      0.0
      1.099117e+02
      0.0
      -0.000055
      0.0
      0.805299
      -0.0

      19
      1.203325e+27
      0.001769
      -0.032225
      0.0
      0.0
      0.0
      1.099102e+02
      0.0
      -0.000057
      0.0
      0.805292
      -0.0

      20
      1.252524e+27
      0.001793
      -0.032922
      0.0
      0.0
      0.0
      1.099086e+02
      0.0
      -0.000059
      0.0
      0.805285
      -0.0

      21
      1.303733e+27
      0.001817
      -0.033622
      0.0
      0.0
      0.0
      1.099069e+02
      0.0
      -0.000061
      0.0
      0.805278
      -0.0

      22
      1.357037e+27
      0.001842
      -0.034324
      0.0
      0.0
      0.0
      1.099052e+02
      0.0
      -0.000063
      0.0
      0.805270
      -0.0

      23
      1.412519e+27
      0.001866
      -0.035029
      0.0
      0.0
      0.0
      1.099034e+02
      0.0
      -0.000065
      0.0
      0.805262
      -0.0

      24
      1.470270e+27
      0.001891
      -0.035737
      0.0
      0.0
      0.0
      1.099015e+02
      0.0
      -0.000068
      0.0
      0.805254
      -0.0

      25
      1.530381e+27
      0.001917
      -0.036449
      0.0
      0.0
      0.0
      1.098996e+02
      0.0
      -0.000070
      0.0
      0.805246
      -0.0

      26
      1.592950e+27
      0.001943
      -0.037164
      0.0
      0.0
      0.0
      1.098976e+02
      0.0
      -0.000072
      0.0
      0.805237
      -0.0

      27
      1.658077e+27
      0.001969
      -0.037882
      0.0
      0.0
      0.0
      1.098955e+02
      0.0
      -0.000075
      0.0
      0.805227
      -0.0

      28
      1.725866e+27
      0.001995
      -0.038605
      0.0
      0.0
      0.0
      1.098934e+02
      0.0
      -0.000077
      0.0
      0.805216
      -0.0

      29
      1.796427e+27
      0.002022
      -0.039331
      0.0
      0.0
      0.0
      1.098912e+02
      0.0
      -0.000080
      0.0
      0.805205
      -0.0

      ...
      ...
      ...
      ...
      ...
      ...
      ...
      ...
      ...
      ...
      ...
      ...
      ...

      2452
      1.989000e+33
      1.000470
      19209.252959
      0.0
      0.0
      0.0
      9.991606e+07
      0.0
      19218.280266
      -0.0
      15219.253389
      -0.0

      2453
      1.989000e+33
      1.000479
      19345.905535
      0.0
      0.0
      0.0
      1.012304e+08
      0.0
      19355.164553
      -0.0
      15402.824925
      -0.0

      2454
      1.989000e+33
      1.000487
      19480.786264
      0.0
      0.0
      0.0
      1.025509e+08
      0.0
      19490.278239
      -0.0
      15588.526899
      -0.0

      2455
      1.989000e+33
      1.000496
      19613.742684
      0.0
      0.0
      0.0
      1.038788e+08
      0.0
      19623.468723
      -0.0
      15776.459522
      -0.0

      2456
      1.989000e+33
      1.000504
      19744.618401
      0.0
      0.0
      0.0
      1.052154e+08
      0.0
      19754.579465
      -0.0
      15966.724420
      -0.0

      2457
      1.989000e+33
      1.000513
      19873.248488
      0.0
      0.0
      0.0
      1.065615e+08
      0.0
      19883.445387
      -0.0
      16159.422478
      -0.0

      2458
      1.989000e+33
      1.000522
      19999.455886
      0.0
      0.0
      0.0
      1.079183e+08
      0.0
      20009.889260
      -0.0
      16354.648136
      -0.0

      2459
      1.989000e+33
      1.000530
      20123.061171
      0.0
      0.0
      0.0
      1.092871e+08
      0.0
      20133.731490
      -0.0
      16552.500879
      -0.0

      2460
      1.989000e+33
      1.000539
      20243.875161
      0.0
      0.0
      0.0
      1.106688e+08
      0.0
      20254.782705
      -0.0
      16753.074900
      -0.0

      2461
      1.989000e+33
      1.000547
      20361.704648
      0.0
      0.0
      0.0
      1.120646e+08
      0.0
      20372.849503
      -0.0
      16956.468137
      -0.0

      2462
      1.989000e+33
      1.000556
      20476.348981
      0.0
      0.0
      0.0
      1.134755e+08
      0.0
      20487.731029
      -0.0
      17162.780469
      -0.0

      2463
      1.989000e+33
      1.000564
      20587.593085
      0.0
      0.0
      0.0
      1.149022e+08
      0.0
      20599.211984
      -0.0
      17372.102608
      -0.0

      2464
      1.989000e+33
      1.000573
      20695.214329
      0.0
      0.0
      0.0
      1.163457e+08
      0.0
      20707.069507
      -0.0
      17584.527934
      -0.0

      2465
      1.989000e+33
      1.000581
      20798.977350
      0.0
      0.0
      0.0
      1.178066e+08
      0.0
      20811.067978
      -0.0
      17800.142284
      -0.0

      2466
      1.989000e+33
      1.000590
      20898.636450
      0.0
      0.0
      0.0
      1.192856e+08
      0.0
      20910.961433
      -0.0
      18019.027261
      -0.0

      2467
      1.989000e+33
      1.000598
      20993.930909
      0.0
      0.0
      0.0
      1.207835e+08
      0.0
      21006.488851
      -0.0
      18241.247879
      -0.0

      2468
      1.989000e+33
      1.000607
      21084.594670
      0.0
      0.0
      0.0
      1.223011e+08
      0.0
      21097.383867
      -0.0
      18466.870982
      -0.0

      2469
      1.989000e+33
      1.000615
      21170.354165
      0.0
      0.0
      0.0
      1.238388e+08
      0.0
      21183.372588
      -0.0
      18695.958727
      -0.0

      2470
      1.989000e+33
      1.000623
      21250.926169
      0.0
      0.0
      0.0
      1.253971e+08
      0.0
      21264.171440
      -0.0
      18928.560070
      -0.0

      2471
      1.989000e+33
      1.000632
      21326.025425
      0.0
      0.0
      0.0
      1.269764e+08
      0.0
      21339.494812
      -0.0
      19164.729896
      -0.0

      2472
      1.989000e+33
      1.000640
      21395.356508
      0.0
      0.0
      0.0
      1.285770e+08
      0.0
      21409.046899
      -0.0
      19404.503968
      -0.0

      2473
      1.989000e+33
      1.000648
      21458.620319
      0.0
      0.0
      0.0
      1.301994e+08
      0.0
      21472.528209
      -0.0
      19647.913972
      -0.0

      2474
      1.989000e+33
      1.000656
      21515.513940
      0.0
      0.0
      0.0
      1.318440e+08
      0.0
      21529.635413
      -0.0
      19894.979108
      -0.0

      2475
      1.989000e+33
      1.000665
      21565.733659
      0.0
      0.0
      0.0
      1.335110e+08
      0.0
      21580.064374
      -0.0
      20145.709759
      -0.0

      2476
      1.989000e+33
      1.000673
      21608.975484
      0.0
      0.0
      0.0
      1.352004e+08
      0.0
      21623.510662
      -0.0
      20400.102034
      -0.0

      2477
      1.989000e+33
      1.000681
      21644.936592
      0.0
      0.0
      0.0
      1.369122e+08
      0.0
      21659.670996
      -0.0
      20658.131585
      -0.0

      2478
      1.989000e+33
      1.000689
      21673.319413
      0.0
      0.0
      0.0
      1.386461e+08
      0.0
      21688.247346
      -0.0
      20919.765761
      -0.0

      2479
      1.989000e+33
      1.000697
      21693.832975
      0.0
      0.0
      0.0
      1.404020e+08
      0.0
      21708.948264
      -0.0
      21184.944484
      -0.0

      2480
      1.989000e+33
      1.000705
      21706.198042
      0.0
      0.0
      0.0
      1.421793e+08
      0.0
      21721.494035
      -0.0
      21453.597680
      -0.0

      2481
      1.989000e+33
      1.000713
      21710.149200
      0.0
      0.0
      0.0
      1.439775e+08
      0.0
      21725.618760
      -0.0
      21725.618760
      -0.0

2482 rows × 12 columns

```python
plt.plot(eig['x'][:-500], eig['Re(xi_r)'][:-500])
plt.xlabel(r'$r/R$')
plt.ylabel(r'GYRE $\xi_r$')
plt.show()
```

```python
# TODO:

# optimize y2(core) to improve y1(surf)-y2(surf)

# implement double shooting
#     (i.e., integrate from the surface inward to some fitting point)

# try many values of omega,
#     find where the outer bc changes sign,
#     run a root finder on omega
```

Cowling approximation
---

Assume $\Phi'=0$ and neglect small terms. Then the system reduces to a system of differential equations for $\xi_r$:
\begin{equation}
    \frac{\text{d}\xi_r}{\text{d}r}
    =
    \frac{1}{\rho c^2}
    \left(
        \frac{S_\ell^2}{\omega^2}
        -
        1
    \right)
    P'
\end{equation}
\begin{equation}
    \frac{\text{d}P'}{\text{d}r}
    =
    \rho
    \left(
        \omega^2 - N^2
    \right)
    \xi_r
\end{equation}
where
\begin{equation}
    N^2
    =
    g
    \left(
        \frac{1}{\Gamma_1 P}
        \frac{\text{d}P}{\text{d}r}
        -
        \frac{1}{\rho}
        \frac{\text{d}\rho}{\text{d}r}
    \right)
\end{equation}
\begin{equation}
    S_\ell^2
    =
    \frac{\ell(\ell+1)c^2}{r^2}
\end{equation}
subject to the boundary conditions
\begin{equation}
    \xi_r \simeq \ell \xi_h \qquad \text{for }r \rightarrow 0\text{ when }\ell > 0
\end{equation}
\begin{equation}
    \delta P
    =
    P'
    +
    \xi_r
    \frac{\text{d}P}{\text{d}r}
    =
    0
    \qquad\text{at }r=R
\end{equation}
where
\begin{equation}
    \xi_h(r)
    =
    \frac{1}{r\omega^2}
    \left(
        \frac{P'}{\rho} + \Phi'
    \right)
    \qquad
    \Rightarrow
    \qquad
    \xi_h
    =
    \frac{1}{r\omega^2}
    \frac{P'}{\rho}
\end{equation}

```python
dP_dR_surf = np.gradient(P(x), r)[-1]
dP_dR_surf
```

```python
# TODO

def cowling(x, y):
    # x is the position in the star
    # y contains the radial displacement eigenfunction
    #   as well as the perturbed pressure
    #print(x.shape, y.shape)
    xi_r   = y[0]
    Pp     = y[1]

    S2 = ell * (ell + 1) * cs2(x) / x**2
    d_xi_r = 1/(rho(x) * cs2(x)) * (S2 / omega**2 - 1) * Pp
    d_Pp   = rho(x) * (omega**2 - N2(x)) * xi_r
    return np.vstack((d_xi_r, d_Pp))

def cowling_bcs(ya, yb):
    xi_r_core = ya[0]
    xi_r_surf = yb[0]
    Pp_core   = ya[1]
    Pp_surf   = yb[1]
    core_bc   = ell / (r[0] * omega**2) * Pp_core / rho(r[0])
    surf_bc   = Pp_surf + xi_r_surf * dP_dR_surf
    return np.array([core_bc, surf_bc])
```

```python
ell = 1
omega = 10
```

```python
xi_r_core = x[0]**(ell-1)
Pp_core   = x[0]**ell

res = integrate.solve_ivp(
    fun=cowling,
    t_span=(x[0], x[-1]),
    y0=[xi_r_core, Pp_core],
    vectorized=True,
    t_eval=x)
```

```python
y_init = np.ones((2, x.size))
res = integrate.solve_bvp(cowling, cowling_bcs, x, y_init,
                          max_nodes=10000, tol=1e-3)
```

Full set of equations
---

Search for non-trivial eigenfrequencies $\omega$ to the two-point boundary value problem:
\begin{equation}
    \frac{\text{d}\xi_r}{\text{d}r}
    =
    -\left(
        \frac{2}{r}
        +
        \frac{1}{\Gamma_1 P}
        \frac{\text{d}P}{\text{d}r}
    \right)
    \xi_r
    +
    \frac{1}{\rho c^2}
    \left(
        \frac{S_\ell^2}{\omega^2}
        -
        1
    \right)
    P'
    +
    \frac{\ell(\ell+1)}{\omega^2 r^2}
    \Phi'
\end{equation}
\begin{equation}
    \frac{\text{d}P'}{\text{d}r}
    =
    \rho
    \left(
        \omega^2
        -
        N^2
    \right)
    \xi_r
    +
    \frac{1}{\Gamma_1 P}
    \frac{\text{d}P}{\text{d}r}
    P'
    -
    \rho
    \frac{\text{d}\Phi'}{\text{d}r}
\end{equation}
\begin{equation}
    \frac{1}{r^2}
    \frac{\text{d}}{\text{d}r} \left(
        r^2
        \frac{\text{d}\Phi'}{\text{d}r}
    \right)
    =
    4\pi G
    \left(
        \frac{P'}{c^2}
        +
        \frac{\rho \xi_r}{g}
        N^2
    \right)
    +
    \frac{\ell(\ell+1)}{r^2}
    \Phi'
\end{equation}
subject to the boundary conditions
\begin{equation}
    \xi_r \simeq \ell \xi_h \qquad \text{for }r \rightarrow 0\text{ when }\ell > 0
\end{equation}
\begin{equation}
    \frac{\text{d}\Phi'}{\text{d}r}
    +
    \frac{\ell+1}{r}
    \Phi'
    =
    0\qquad\text{at }r=R
\end{equation}
\begin{equation}
    \delta P
    =
    P'
    +
    \xi_r
    \frac{\text{d}P}{\text{d}r}
    =
    0
    \qquad\text{at }r=R
\end{equation}

```python
# TODO
```


# Comparison of W'balance algorithms

## Initialization

```python
from athletic_pandas.models import Athlete, WorkoutDataFrame

%matplotlib inline
```

## Introduction

In this article a comparison is made of the different W'balance algorithms that are circulating. It is assumed that the reader is familiar with power duration models, the 2-parameter critical power model and the W'balance concept. If you are not familiar with these, Jones et al. (2017)1 is a good primer. If that article is too complicated then this article will probably be too complicated as well, sorry about that... The article is probably not complete and also not intended to judge or validate any of the algorithms. The algorithms that are discussed are the original (integral) Skiba2 algorithm, an optimization (approximation) of the Skiba (integral) algorithm by Dave Waterworth3 and the Froncioni/Skiba/Clarke (differential) algorithm4. All the algorithms are implemented in the Python library [athletic_pandas](https://github.com/aartgoossens/athletic_pandas).

## Integral algorithm

The integral algorithm is the best known algorithm to calculate W'balance and has been scientifically validated5. The formula's for the algorithm are:

\begin{equation}
W'_{bal}(t) = W' - \sum_{u=0}^t W'_{exp}(u) \cdot e^{-\frac{t-u}{\tau_{W'}}}
\end{equation}

\begin{equation}
\tau_{W'} = 546 \cdot e^{-0.01 \cdot D_{CP}}+316
\end{equation}

\begin{equation}
W'_{exp}(t) =
    \begin{cases}
    0 & \text{where } P(t) < CP \\
    P(t) - CP & \text{else}
    \end{cases}
\end{equation}

Where $W’_{bal}(t)$ is equal to $W'_bal$ at time *t*, **W’**  is the amount of available energy above CP , **t**  the time for which $W'_{bal}$ is calculated, **u** the iterator of the summation, $W’_{exp}(t)$  amount of energy above CP that is used at time u (*expended*), **e**  the Euler number and **$\tau_{W’}$** a time constant that describes the recovery speed. The numbers 546, -0.01 and 316 are determined in Skiba's original article and do not change between persons. $D_{CP}$ is the difference between CP and the average power of the intervals in which the power was below CP. $D_{CP}$ can be calculated dynamically (the average until time t) or calculated once for the entire workout and used as a static value. Skiba recommends using a static value for $D_{CP}${citation needed}.

### Waterworth optimization of integral algorithm

The original integral algorithm is quite expensive to compute, even on fast computers, since the summation has to be run for every time t again. Mathematician Dave Waterworth helped core developer of GoldenCheetah Mark Liversedge to develop an optimization of the Skiba algorithm3. This reformulation is an approximation of the Skiba algorithm so results can vary a little in extreme cases, especially when $\tau_{W'}$ is very low. A comparison of these two algorithms is shown later in this article.

\begin{equation}
S(t) = \sum_0^t W'_{exp}(t) \cdot e^{\frac{t}{\tau_{W'}}}
\end{equation}
\begin{equation}
W'_{bal}(t) = S(t) \cdot e^\frac{t}{\tau_{W'}}
\end{equation}

## Differential algorithm

The differential algorithm was developed by Skiba et al.4 to cover some of the drawbacks of the original (integral) algorithm, namely he fact that it was developed for cycle-ergometer exercise specifically and that it contained coeffients that have to be estimated. At the same time Andy Froncioni was developing a similar approach. The resulting algorithm is a combined effort of Froncioni and the authors of the the cited article4. The differential algorithm is the default algorithm for the calculation of W'balance in [GoldenCheetah](http://www.goldencheetah.org/).
This algorithm describes a W'balance recovery that is similar to the integral algorithm but where the speed is only dependent on the power under CP (DCP) and the difference between W'balance and W' remaining (i.e. slower recovery if W' is almost completely recovered).

\begin{equation}
W'_{bal}(t) =
    \sum_0^t (CP - P(t)) \cdot
    \begin{cases}
    1 & \text{where } P(t)>CP\\
    {\frac{W' - W'_{bal}(t-1)}{W'}} & \text{else}
    \end{cases}
\end{equation}

## Comparison

As an example I will create a workout for an athlete (CP=300 Watt, W'=20 kJ) which starts with a warming up of 10 minutes at 100 Watt, followed by 2 times 5 times 1 minute at 400 Watt with 1 minute rest at 100 Watt and 4 minutes rest between the two sets and ending with a cooling down of 10 minutes at 100 Watt. The power is plotted below.

```python
warming_up = [100] * 600
intervals = ([400]*60 + [100]*60)*5 + [100]*240 + ([400]*60 + [100]*60)*5
cooling_down = [100] * 600

wdf = WorkoutDataFrame(dict(
    power=warming_up + intervals + cooling_down
))
wdf.athlete = Athlete(cp=350, w_prime=20000)
```

```python
fig_power = wdf.power.plot.area()
fig_power.set_ylabel('power (Watt)')
fig_power.set_xlabel('time (seconds)');
```

```python
wdf = wdf.assign(
    w_balance_skiba=wdf.compute_w_prime_balance('skiba'),
    w_balance_waterworth=wdf.compute_w_prime_balance('waterworth'),
    w_balance_froncioni_skiba_clarke=wdf.compute_w_prime_balance('froncioni-skiba-clarke'),
)
```

I will start with comparing the two versions of the integral algorithm. First the plot showing $W'_{bal}$ for both algorithms. This plot shows that the difference between these to algorithms is very small, with the Waterworth plot covering the original plot almost completely.

```python
fig_skiba_waterworth = wdf.loc[:, ['w_balance_skiba', 'w_balance_waterworth']].plot(ylim=0)
fig_skiba_waterworth.set_ylabel('W\'balance (Joule)')
fig_skiba_waterworth.set_xlabel('time (seconds)');
```

When the residual plot for these two algorithms is plotted it is obvious that the algorithms are almost identical with the maximum difference equal to 5.46 nanojoule...

```python
residuals = wdf.w_balance_skiba - wdf.w_balance_waterworth
fig_residuals = residuals.plot()
fig_residuals.set_xlabel('time (seconds)')
residuals.max()
```

Comparison of the integral algorithm with the differential algorithm reveals large differences between these two algorithms in the plot below. Both the expenditure and the recovery of $W'_{bal}$ are faster for the differential algorithm. The difference in the expenditure is especially striking because one would expect that it is linear and therefore identical for both algorithms. However, the difference can be explained by the fact that the integral algorithm assumes that although there is a netto decrease in $W'_{bal}$ for intervals where $P>CP$, there is also recovery of previously expended $W'$ during those intervals.

The difference in the recovery of $W'_{bal}$ is a consequence of how the recovery is modeled. For the integral algorithm this is done with the term $e^{-\frac{t-u}{\tau_{W'}}}$ in the equation, where $\tau_{W'}$ regulates the speed of recovery. My expectation is that for different values of $\tau_{W'}$ (or different values for the constants numbers 546, -0.01 and 316) the recovery can be changed to similar speed as the differential model. Similarly, the recovery speed in the differential model is regulated by the term $\frac{W' - W'_{bal}(t-1)}{W'}$ and it is possible to change the recovery speed by multiplying this term by e.g. a factor $\alpha$: $\alpha*\frac{W' - W'_{bal}(t-1)}{W'}$. Although this goes against one of the main reasons to develop the differential algorithm (to get rid of coefficients that have to be determined), I will try to fit this modified algorithm to the integral algorithm in a later article as a proof of concept.

```python
fig_skiba_froncioni = wdf.loc[:, ['w_balance_skiba', 'w_balance_froncioni_skiba_clarke']].plot()
fig_skiba_froncioni.set_ylabel('W\'balance (Joule)')
fig_skiba_froncioni.set_xlabel('time (seconds)');
```

## Conclusion

From the three algorithms that were compared, there were no differences between the original integral algorithm and the optimization of this algorithm by Waterworth. There were however big differences between both versions of the inegral algorithm and the differential algorithm, with the differential algorithm showing faster expenditure and recovery of $W_{bal}$. It would be interesting to see if these differences can be minimized by adding a model parameter to the differential algorithm and fitting it to the integral algorithm.

## References

1. Jones, A. M., & Vanhatalo, A. (2017). The ‘Critical Power’Concept: Applications to Sports Performance with a Focus on Intermittent High-Intensity Exercise. Sports Medicine, 47(1), 65-78.
2. Skiba, P. F., Chidnok, W., Vanhatalo, A., & Jones, A. M. (2012). Modeling the expenditure and reconstitution of work capacity above critical power. Medicine and science in sports and exercise, 44(8), 1526-1532.
3. http://markliversedge.blogspot.nl/2014/10/wbal-optimisation-by-mathematician.html
4. Skiba, P. F., Fulford, J., Clarke, D. C., Vanhatalo, A., & Jones, A. M. (2015). Intramuscular determinants of the ability to recover work capacity above critical power. European journal of applied physiology, 115(4), 703-713.
5. Skiba, P. F., Jackman, S., Clarke, D., Vanhatalo, A., & Jones, A. M. (2014). Effect of work and recovery durations on W'reconstitution during intermittent exercise. Medicine and science in sports and exercise, 46(7), 1433-1440.

## Exporting images

```python
import numpy as np
figures = [fig_power, fig_skiba_waterworth, fig_residuals, fig_skiba_froncioni]
figure_names = ['fig_power', 'fig_skiba_waterworth', 'fig_residuals', 'fig_skiba_froncioni']
for fig, name in zip(figures, figure_names):
    if hasattr(fig, 'savefig'):
        f = fig
    elif isinstance(fig, np.ndarray):
        f = fig[0].get_figure()
    else:
        f = fig.get_figure()

    f.savefig(f'{name}.png', dpi=600)

```

```python

```


# Table of Contents

Кратчайшее введение в Python для математики

Что это?

Всё взять и запустить!

Что-что, простите?

Картинка для привлечения внимания

Базовый Python

Арифметика

Структуры данных

Списки

Кортежи

Словари

Множества

Управляющие конструкции

Проверка условий

Циклы

Цикл for

Цикл while

Математические библиотеки

numpy

scipy

Линейная алгебра

Интегрирование и решение дифференциальных уравнений

sympy

matplotlib

Scatter plot

Полярные координаты

Векторные поля и ОДУ

Линии уровня (contour plot)

Виджеты

# Кратчайшее введение в Python для математики
*Илья Щуров, НИУ ВШЭ.*

Документ распространяется по лицензии [CC BY-SA 4.0 Unported](https://creativecommons.org/licenses/by-sa/4.0/deed.ru). Все фрагменты кода в этом блокноте переданы в [общественное достояние](https://creativecommons.org/publicdomain/zero/1.0/). Исходные коды доступны на [github](https://github.com/ischurov/odebook/mathandpython.ipynb).

## Что это?

Этот документ предназначен для тех, кто хочет быстро начать использовать Python при решении математических и околоматематических задач. В нём предполагается, что вы уже обладаете базовыми навыками программирования, но не знаете Python. Если таких навыков нет, вы, возможно, сможете использовать отдельные рецепты отсюда, но вряд ли получите ту свободу, которую даёт знание универсального языка программирования.

Если вы никогда раньше не программировали — или наоборот, хотите освоить базовый Python более фундаментально, а уже потом переходить к его математическим приложениям — я рекомендую интерактивный курс [Pythontutor.ru](http://pythontutor.ru/) (там есть визуализатор пошагового выполнения кода и задачи с автоматической проверкой) или мой [курс по Python в ВШЭ](http://math-info.hse.ru/s15/m) (там есть видеолекции, ко всему прочему).

По каждому разделу приводятся ссылки, с помощью которых вы можете подробнее узнать о данной теме.

## Всё взять и запустить!
Самый простой способ запустить *Python* — зайти на http://tmpnb.org/ (в IE может не работать, лучше использовать Firefox или Chrome) и выбрать *New → Python 3*. Откроется notebook, состоящий из ячеек. Если в ячейку ввести код и нажать *Shift + Enter*, он выполнится.

Чуть сложнее: [скачать Anaconda](http://continuum.io/downloads), установить, найти в меню «Пуск» или его аналоге *Jupyter Notebook* или *IPython Notebook* и запустить. (Под Mac OS это Anaconda Launcher.) Откроется окно браузера, такое же, как при открытии http://tmpnb.org/.

### Что-что, простите?

Немного терминологии, чтобы не запутаться.

- **Python** — это язык программирования. Он бывает двух основных модификаций — Python 2 и Python 3. Конкретная версия имеет обозначение через точку - например, текущая (на начало 2016 года) версия Python 3 имеет номер 3.5, а Python 2 — 2.7. Мы будем использовать Python 3. Отличия в синтаксисе между 2-й и 3-й версиями минимальны, но есть. С точки зрения обучения, неважно, что использовать — переключиться с одного на другой — дело получаса.
- **Anaconda** — это дистрибутив, включающий в себя Python и всякие другие полезные для нас штуки, в том числе множество научных библиотек, которыми мы будем пользоваться.
- **Jupyter** — это среда, с помощью которой можно работать с Python в интерактивном режиме: ввели команду — получили результат. Раньше она называлась **IPython Notebook**, но сейчас она умеет работать с другими языками и её переименовали в Jupyter.
- **Блокнотами (notebook)** называются документы, получающиеся при такой интерактивной работе. Они состоят из ячеек с кодом, результатами выполнения кода и дополнительными комментариями. Этот документ также является блокнотом. Блокноты имеют расширение ipynb.

### Картинка для привлечения внимания
Подробнее о картинках [см. ниже](#matplotlib).

```python
import matplotlib.pyplot as plt
%matplotlib inline
%config InlineBackend.figure_format = 'svg'
import numpy as np
r = np.linspace(0,200,100)
ax = plt.subplot(111, projection='polar')
ax.plot(r, r, color='b', linewidth=1.5);
```

## Базовый Python
Этот раздел содержит шпаргалку по базовым возможностям Python. Вы можете его пропустить (сразу перейти к [разделу numpy](#numpy)) и обращаться к нему по мере необходимости, или кратко просмотреть, чтобы узнать, чем Python отличается от других языков.

### Арифметика

```python
n = 10 # целое число (int)
x = 0.12 # число с плавающей точкой (float)
n * x # Результат выполнения последней команды будет выведем автоматически.
```

    1.2

```python
type(n) # int — целое
```

    int

```python
z = 1 + 2j # комплексное число, j — это мнимая единица
z ** 2 # возведение в степень — две звёздочки, а не крышечка; крышечка это побитный XOR
```

    (-3+4j)

```python
print(5 / 2)  # деление в числах с плавающей точкой
print(5 // 2) # целочисленное деление
print(5 % 2)  # взятие остатка
```

    2.5
    2
    1

```python
from math import sqrt
# импорт одной функции из модуля (библиотеки)

sqrt(4)
```

    2.0

```python
import math
# другой способ импорта

math.sin(math.pi)
```

    1.2246467991473532e-16

```python
import math as m
# то же, что и предыдущий, но короче

m.sin(m.pi)
```

    1.2246467991473532e-16

Подробнее: [конспект](http://nbviewer.ipython.org/github/ischurov/pythonhse/blob/master/Lecture%201.ipynb), [видео](http://www.youtube.com/watch?v=5Y5tKPKhurA).

### Структуры данных
#### Списки

```python
my_list = [4, 10, 1, 3]
# список (что-то вроде динамического массива)

print(my_list[2])
# нумерация начинается с нуля
```

    1

```python
my_list[3] = 99
my_list
```

    [4, 10, 1, 99]

```python
my_list.append(100)
my_list
```

    [4, 10, 1, 99, 100]

```python
my_list + [2, 3, 4] # конкатенация
```

    [4, 10, 1, 99, 100, 2, 3, 4]

```python
my_list # не изменился
```

    [4, 10, 1, 99, 100]

```python
my_list.extend([2, 3, 4])
my_list
```

    [4, 10, 1, 99, 100, 2, 3, 4]

```python
my_list[2:5] # срез (slice); первый элемент включается, последний не включается
```

    [1, 99, 100]

```python
min(my_list)
```

    1

```python
max(my_list)
```

    100

```python
sum(my_list)
```

    223

```python
sorted(my_list)
```

    [1, 2, 3, 4, 4, 10, 99, 100]

```python
my_list # список не изменился
```

    [4, 10, 1, 99, 100, 2, 3, 4]

```python
my_list.sort()
my_list # а теперь изменился
```

    [1, 2, 3, 4, 4, 10, 99, 100]

Подробнее: [конспект](http://nbviewer.ipython.org/github/ischurov/pythonhse/blob/master/Lecture%202.ipynb), [видео](https://www.youtube.com/watch?v=kBu3g-ITjY4).

#### Кортежи
Кортеж — это неизменяемый список.

```python
my_tuple = (12, 8, 3)
my_tuple[1]
```

    8

```python
my_tuple[1] = 10
```

#### Словари

```python
my_dict = {'Alice': 5, 'Bob': 3, 'Claudia': 4}
my_dict['Alice']
```

    5

```python
my_dict['Bob'] = 4
my_dict
```

    {'Alice': 5, 'Bob': 4, 'Claudia': 4}

Подробнее: [конспект](http://nbviewer.ipython.org/github/ischurov/pythonhse/blob/master/Lecture%205.ipynb), [видео](http://www.youtube.com/watch?v=z8bu_b5BboI).

#### Множества

```python
A = {9, 2, 5, 3, 10}
B = {2, 10, 12, 15}
9 in A
```

    True

```python
A | B # объединение
```

    {2, 3, 5, 9, 10, 12, 15}

```python
A & B # пересечение
```

    {2, 10}

### Управляющие конструкции
#### Проверка условий

```python
x = 10
if x > 8:
    print("x is rather big")
else:
    print("x is very small")
    print("Could you increase it?")
print("x =", x)
```

    x is rather big
    x = 10

Блок, относящийся к управляющей конструкции, выделяется отступом. Закончился отступ — закончился и блок. Никаких фигурных скобок или конструкций `begin-end` в Python не предусмотрено.

```python
x = 15
if x > 10 and x % 2 == 0:
    print("x is big and even")
else:
    print("either x is not so big or it is not even")
```

    either x is not so big or it is not even

Подробнее: [конспект](http://nbviewer.jupyter.org/github/ischurov/pythonhse/blob/master/Lecture%203.ipynb#%D0%9F%D1%80%D0%BE%D0%B2%D0%B5%D1%80%D0%BA%D0%B0-%D1%83%D1%81%D0%BB%D0%BE%D0%B2%D0%B8%D0%B9).

### Циклы

#### Цикл `for`

```python
my_list = [8, 9, 12]
for x in my_list:
    print(x)
    print("Let's go to the next x")
```

    8
    Let's go to the next x
    9
    Let's go to the next x
    12
    Let's go to the next x

```python
for x in range(5):
    print(x)
```

    0
    1
    2
    3
    4

```python
list(range(2, 8))
```

    [2, 3, 4, 5, 6, 7]

```python
# посчитаем факториал
s = 1
n = 15
for x in range(1, n + 1):
    s = s * x
print(s)
```

    1307674368000

```python
# хотя конечно проще так:
from math import factorial
factorial(15)
```

    1307674368000

```python
for i, x in enumerate(my_list):
    print("my_list[{0}] = {1}".format(i, x))
```

    my_list[0] = 8
    my_list[1] = 9
    my_list[2] = 12

```python
other_list = [10, 12, 13]
# zip — застёжка-молния, состёгивает два или несколько списков
for x, y in zip(my_list, other_list):
    print("x = {}, y = {}".format(x, y))
    print("x + y =", x + y)
```

    x = 8, y = 10
    x + y = 18
    x = 9, y = 12
    x + y = 21
    x = 12, y = 13
    x + y = 25

Подробнее: [конспект](http://nbviewer.jupyter.org/github/ischurov/pythonhse/blob/master/Lecture%202.ipynb#%D0%A6%D0%B8%D0%BA%D0%BB-for), [про enumerate](http://nbviewer.jupyter.org/github/ischurov/pythonhse/blob/master/Lecture%203.ipynb#%D0%9D%D1%83%D0%BC%D0%B5%D1%80%D0%B0%D1%86%D0%B8%D1%8F-%D1%8D%D0%BB%D0%B5%D0%BC%D0%B5%D0%BD%D1%82%D0%BE%D0%B2-%D1%81%D0%BF%D0%B8%D1%81%D0%BA%D0%B0), [про zip](http://nbviewer.jupyter.org/github/ischurov/pythonhse/blob/master/Lecture%205.ipynb#%D0%A1%D0%BE%D0%B7%D0%B4%D0%B0%D0%BD%D0%B8%D0%B5-%D1%81%D0%BB%D0%BE%D0%B2%D0%B0%D1%80%D0%B5%D0%B9-%D0%B8-%D1%84%D1%83%D0%BD%D0%BA%D1%86%D0%B8%D1%8F-zip%28%29).

#### Цикл `while`

```python
# найдем последнее число Фибоначчи, меньшее 1000
a = 1
b = 1
while b < 1000:
    c = a + b
    a = b
    b = c
    # можно было бы так: a, b = b, a + b
print(a)
```

    987

```python
# найдем предпоследнее число Фибоначчи, меньшее 1000
a = 1
b = 1
while True: # выполнять всегда
    c = a + b
    if c > 1000:
        break
    a = b
    b = c
print(a)
```

    610

Подробнее: [while](http://nbviewer.jupyter.org/github/ischurov/pythonhse/blob/master/Lecture%203.ipynb#%D0%A6%D0%B8%D0%BA%D0%BB-while).

## Математические библиотеки
### numpy
`numpy` — это библиотека для эффективной работы с массивами. Массивы `numpy` называются `numpy.array` или `numpy.ndarray` (это почти одно и то же) и похожи на списки, но работают быстрее. По своей концепции они похожи на MATLAB.

```python
import numpy as np
x = np.array([4, 3, 10, 3])
```

```python
x[2]
```

    10

```python
y = np.array([10, 12, 3, 15])
x + y # поэлементное сложение
```

    array([14, 15, 13, 18])

```python
x * y # и умножение тоже
```

    array([40, 36, 30, 45])

```python
x.dot(y) # скалярное произведение
```

    151

```python
x @ y # так тоже можно
```

    151

```python
A = np.array([[1, 2], [3, 4]]) # матрица
u = np.array([[1, 0]])
A @ u.T # умножение матрицы на вектор
```

    array([[1],
           [3]])

```python
math.sin(x)
```

```python
np.sin(x) # поэлементное применение
```

    array([-0.7568025 ,  0.14112001, -0.54402111,  0.14112001])

```python
x
```

    array([ 4,  3, 10,  3])

```python
x[x<10] # выбрать все элементы x, меньшие 10
```

    array([4, 3, 3])

`numpy` позволяет в большинстве случаев обходиться без циклов (которые в Python довольно медленные), заменяя их на поэлементные операции над списками.

Подробнее: [конспект](http://nbviewer.jupyter.org/github/ischurov/pythonhse/blob/master/Lecture%2011.ipynb), [видео](http://www.youtube.com/watch?v=A84rlgoVnMY).

### scipy
Всякая разная математика.

#### Линейная алгебра

Решим систему уравнений

\begin{equation}
    \begin{pmatrix}
    3 & 4\\
    4 & -3
    \end{pmatrix}
    \begin{pmatrix}
    x\\
    y
    \end{pmatrix}
    =
    \begin{pmatrix}
    10\\
    5
    \end{pmatrix}
\end{equation}

```python
from scipy.linalg import solve
solve(np.array([[3, 4], [4, -3]]), np.array([10, 5]).T) # решить систему линейных уравнений
```

    array([ 2.,  1.])

Подробнее: [документация](http://docs.scipy.org/doc/scipy/reference/linalg.html) (англ.)

#### Интегрирование и решение дифференциальных уравнений

Посчитаем $\int_0^1 x^2 \; dx$.

```python
from scipy.integrate import quad
def f(x): # так мы определили функцию f(x)=x**2
    return x**2
quad(f, 0, 1)
```

    (0.33333333333333337, 3.700743415417189e-15)

Решим дифференциальное уравнение $\dot x = x$.

```python
from scipy.integrate import odeint
T = np.linspace(0, 1, 10) # равномерное разбиение отрезка [0, 1] с помощью 10 точек
def f(x, t):
    return x
odeint(f, 1, T)
```

    array([[ 1.        ],
           [ 1.11751906],
           [ 1.24884886],
           [ 1.39561243],
           [ 1.55962349],
           [ 1.742909  ],
           [ 1.94773405],
           [ 2.17663003],
           [ 2.43242551],
           [ 2.7182819 ]])

Подробнее: [документация](http://docs.scipy.org/doc/scipy/reference/integrate.html) (англ.)

Решим систему
\begin{equation}
\dot x = y,\quad \dot y = - x
\end{equation}

```python
def f(X, t):
    # x = X[0], y = X[1]
    return [X[1], -X[0]]
T = np.linspace(0, 2 * m.pi, 10)
odeint(f, [1, 0], T)
```

    array([[  1.00000000e+00,   0.00000000e+00],
           [  7.66044451e-01,  -6.42787586e-01],
           [  1.73648228e-01,  -9.84807729e-01],
           [ -4.99999898e-01,  -8.66025431e-01],
           [ -9.39692552e-01,  -3.42020255e-01],
           [ -9.39692654e-01,   3.42020020e-01],
           [ -5.00000115e-01,   8.66025338e-01],
           [  1.73648045e-01,   9.84807790e-01],
           [  7.66044373e-01,   6.42787736e-01],
           [  1.00000004e+00,   1.47816225e-07]])

### sympy
Символьная математика.

```python
import sympy as sp
from sympy import init_printing
init_printing(use_latex = 'mathjax')
```

```python
x, y, z = sp.symbols('x y z')
sp.expand((x + y)**10)
```

$$x^{10} + 10 x^{9} y + 45 x^{8} y^{2} + 120 x^{7} y^{3} + 210 x^{6} y^{4} + 252 x^{5} y^{5} + 210 x^{4} y^{6} + 120 x^{3} y^{7} + 45 x^{2} y^{8} + 10 x y^{9} + y^{10}$$

```python
sp.exp(-x**2 / 2).diff(x)
```

$$- x e^{- \frac{x^{2}}{2}}$$

```python
sp.sin(x).series()
```

$$x - \frac{x^{3}}{6} + \frac{x^{5}}{120} + \mathcal{O}\left(x^{6}\right)$$

```python
sp.exp(x**2 + x**3).series()
```

$$1 + x^{2} + x^{3} + \frac{x^{4}}{2} + x^{5} + \mathcal{O}\left(x^{6}\right)$$

```python
sp.integrate(sp.sin(x) ** 10)
```

$$\frac{63 x}{256} - \frac{1}{10} \sin^{9}{\left (x \right )} \cos{\left (x \right )} - \frac{9}{80} \sin^{7}{\left (x \right )} \cos{\left (x \right )} - \frac{21}{160} \sin^{5}{\left (x \right )} \cos{\left (x \right )} - \frac{21}{128} \sin^{3}{\left (x \right )} \cos{\left (x \right )} - \frac{63}{256} \sin{\left (x \right )} \cos{\left (x \right )}$$

```python
sp.exp(x**10).diff(x).subs({x:1})
```

$$10 e$$

```python
print(sp.exp(x**10).diff(x).subs({x:1}).evalf(n=1000))
```

    27.18281828459045235360287471352662497757247093699959574966967627724076630353547594571382178525166427427466391932003059921817413596629043572900334295260595630738132328627943490763233829880753195251019011573834187930702154089149934884167509244761460668082264800168477411853742345442437107539077744992069551702761838606261331384583000752044933826560297606737113200709328709127443747047230696977209310141692836819025515108657463772111252389784425056953696770785449969967946864454905987931636889230098793127736178215424999229576351482208269895193668033182528869398496465105820939239829488793320362509443117301238197068416140397019837679320683282376464804295311802328782509819455815301756717361332069811250996181881593041690351598888519345807273866738589422879228499892086805825749279610484198444363463244968487560233624827041978623209002160990235304369941849146314093431738143640546253152096183690888707016768396424378140592714563549061303107208510383750510115747704171898610687396965521267154688957035035

```python
M = sp.Matrix([[x, 1], [1, x]])
M
```

$$\left[\begin{matrix}x & 1\\1 & x\end{matrix}\right]$$

```python
sp.Matrix([[x, 1], [1, x]]).eigenvects()
```

$$\left [ \left ( x - 1, \quad 1, \quad \left [ \left[\begin{matrix}-1\\1\end{matrix}\right]\right ]\right ), \quad \left ( x + 1, \quad 1, \quad \left [ \left[\begin{matrix}1\\1\end{matrix}\right]\right ]\right )\right ]$$

Подробнее: [документация](http://docs.sympy.org/latest/tutorial/index.html) (англ.)

### matplotlib
Картинки. Основная библиотека — `matplotlib.pyplot` — очень похожа на MATLAB и работает в тесной связке с `numpy` и другими библиотеками.

```python
%matplotlib inline
# иначе картинки не будут рисоваться
%config InlineBackend.figure_format = 'svg'
# вывод в SVG для пущей красивости
import matplotlib.pyplot as plt
plt.plot([0, 1, 2, 3], [0, 1, 4, 9])
```

    [<matplotlib.lines.Line2D at 0x108575b00>]

```python
x = np.linspace(-4, 4)
plt.plot(x, x**2)
```

    [<matplotlib.lines.Line2D at 0x10867c4e0>]

```python
plt.plot(x, np.sin(x**2))
```

    [<matplotlib.lines.Line2D at 0x10877be80>]

```python
x = np.linspace(-4, 4, 1000) # возьмём точек побольше
plt.plot(x, np.sin(x**2))
```

    [<matplotlib.lines.Line2D at 0x10887f198>]

```python
plt.plot(np.sin(x))
plt.plot(np.cos(x))
```

    [<matplotlib.lines.Line2D at 0x1088894a8>]

```python
plt.plot(x, 1/x)
```

    [<matplotlib.lines.Line2D at 0x108a6bdd8>]

```python
plt.ylim(-4, 4)
plt.plot(x, 1/x, label='$y = 1/x$')
plt.plot(x, np.zeros_like(x))
plt.legend()
```

    <matplotlib.legend.Legend at 0x108b70908>

```python
plt.figure(figsize=(6, 6)) # квадратненько
x = np.linspace(-1.5, 1.5, 100)
y = x**2
plt.plot(x, y, label='$y = x^2$')
plt.plot(y, x, label='$x = y^2$')
plt.xlabel("$x$", fontsize=20)
plt.ylabel("$y$", fontsize=20)
plt.legend()
```

    <matplotlib.legend.Legend at 0x108d16908>

#### Scatter plot

```python
from scipy.stats import norm
x = norm.rvs(size = 500)
y = x + norm.rvs(size = 500)
plt.scatter(x, y)
```

    <matplotlib.collections.PathCollection at 0x108c6b1d0>

#### Полярные координаты

```python
r = np.linspace(0, 3.0, 10000)
theta = 2 * np.pi * np.exp(r)

ax = plt.subplot(111, projection='polar')
ax.plot(theta, r, color='r', linewidth=1)
```

    [<matplotlib.lines.Line2D at 0x10936b438>]

#### Векторные поля и ОДУ

Векторное поле дифференциального уравнения:

$$\dot x=-0.1x+y,\quad \dot y = -x - 0.1y$$

```python
plt.figure(figsize=(6,6))
plt.xlabel("$x$", fontsize=20)
plt.ylabel("$y$", fontsize=20)
x, y = np.mgrid[-3:3:0.5, -3:3:0.5]
plt.quiver(x, y, -0.1 * x + y, -x - 0.1 * y)
```

    <matplotlib.quiver.Quiver at 0x109378860>

Фазовый портрет того же уравнения.

```python
plt.figure(figsize=(6,6))
plt.xlabel("$x$", fontsize=20)
plt.ylabel("$y$", fontsize=20)

y, x = np.mgrid[-3:3:21j, -3:3:21j] # 21j здесь означает, что нужна 21 точка

# Обратите внимание: y и x идут в обратном порядке!

plt.streamplot(x, y, -0.1 * x + y, -x - 0.1 * y)
```

    <matplotlib.streamplot.StreamplotSet at 0x10f9e8a58>

Несколько решений того же уравнения, найденные с помощью численного интегрирования вручную.

```python
def f(X, t):
    return np.array([[-0.1, 1], [-1, -0.1]] @ X)
T = np.linspace(0, 10*m.pi, 1000)
inits = [[1, 0], [0, 1], [1, 1]]
plt.figure(figsize=(6,6))
plt.xlim(-1, 1)
plt.ylim(-1, 1)
plt.xlabel("$x$", fontsize=20)
plt.ylabel("$y$", fontsize=20)
for init in inits:
    traj = odeint(f, init, T)
    plt.plot(traj[:, 0], traj[:, 1])
```

#### Линии уровня (contour plot)

Линии уровня функции $z=xy$.

```python
x, y = np.mgrid[-3:3:0.01, -3:3:0.01]
z = x * y
plt.contour(x, y, z, 20, cmap='gnuplot')
```

    <matplotlib.contour.QuadContourSet at 0x10a42df28>

Касп (он же «ласточкин хвост») $x^2 - y^3 = 0$.

```python
import matplotlib
matplotlib.rc('font', family='Arial') # иначе русские буквы не сработают
x, y = np.mgrid[-1:1:0.001, 0:1:0.001]
z = x**2 - y**3
plt.contour(x, y, z, levels=[0])
plt.title("Ласточкин хвост")
```

    <matplotlib.text.Text at 0x10a73e710>

Подробнее: [pyplot tutorial](http://matplotlib.org/users/pyplot_tutorial.html) (англ.)

### Виджеты
Виджеты позволяют добавить интерактивности: создают элементы управления (например, слайдеры), с помощью которых вы можете настраивать параметры вызываемых функций и сразу получать результат. Виджеты работают только если вы загрузили блокнот и свой IPython Notebook или в tmpnb. Если вы просто читаете эту страничку в Интернете, скорее всего, вы ничего интересного не увидите.

```python
from ipywidgets import interact, interactive, fixed, FloatSlider
import ipywidgets as widgets
```

```python
@interact(a=FloatSlider(min=0, max=10, value=1, step=1e-3),
          b=FloatSlider(min=0, max=10, value=1, step=1e-3))
def plot_sin(a, b):
    x = np.linspace(-4,4,300)
    plt.ylim(-2,2)
    plt.plot(np.sin(a*x)*b)
```

Подробнее: [виджеты](http://nbviewer.jupyter.org/github/ipython/ipywidgets/blob/master/examples/Index.ipynb) (англ.)


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

from pole_zero_plot import pole_zero_plot

```

## Definición

La [transformada $z$](https://en.wikipedia.org/wiki/Z-transform) permite representar una señal discreta $x[k]$ en el dominio de las frecuencias. La función base para la transformación es $z^{-k}$ con $z \in \mathbb{C}$

### Transformada bilateral
La transformada $z$ bilateral se define como

\begin{equation}
X(z) = \sum_{k = -\infty}^{\infty} x[k] \, z^{-k}
\end{equation}

donde $X(z) = \mathcal{Z} \{ x[k] \}$ es la transformada Z de $x[k]$.

La variable $z$ puede ser interpretada como una [frecuencia compleja](../discrete_signals/standard_signals.ipynb#Complex-Exponential-Signal) $z = e^{\Sigma + j \Omega}$ con $\Sigma, \Omega \in \mathbb{R}$.

La existencia de $X(z) = \mathcal{Z} \{ x[k] \}$ depende de la señal $x[k]$ y los valores $z$. Los valores de $z$ que hacen que la transformada $z$ converja forman la ROC (región de convergencia).

La transformada inversa $z$ es:

\begin{equation}
x[k] = \frac{1}{2 \pi j} \int_{ }^{ } X(z) \, z^{k-1} \; dz
\end{equation}

### Transformada de un lado

En las señales causales se cumple que $x[k] = 0$ para $k <0$, por lo cual la transformada se convierte en:

\begin{equation}
X(z) = \sum_{k = -\infty}^{\infty} x[k] \cdot \epsilon[k] \, z^{-k} = \sum_{k = 0}^{\infty} x[k] \, z^{-k}
\end{equation}

\begin{equation}
X(z) = \sum_{k = 0}^{\infty} x[k] \, z^{-k}
\end{equation}

Así como la transformada de Laplace se usa para resolver ecuacioes diferenciales, la transforada $z$ se usa para resolver ecuaciones en diferencias.

### Señales de duración finita

Dada una señal $x[k]$ de duración finita, $x[k] = 0$ para $\{k : k < M_1 \wedge k \geq M_2\}$ con $M_1 < M_2$, por lo cual

\begin{equation}
\begin{split}
X(z) &= \sum_{k = -\infty}^{\infty} x[k] \cdot \, z^{-k}
\\
&= \sum_{k=M_1}^{M_2 - 1} x[k] \, z^{-k}
\\
&= x[M_1] \, z^{-M_1} + x[M_1 + 1] \, z^{- (M_1 + 1)} + \dots + x[M_2 - 1] \, z^{- (M_2-1)}
\\
\end{split}
\end{equation}

La transformada $z$ de una señal de duración finita es un polinomio en $z$.

- Si la señal es causal, la ROC corresponde a $z \in \mathbb{C} \setminus \{ 0 \}$.

\begin{equation}
X(z) = x[0] + x[1] \, z^{-1} + \dots + x[M_2 - 1] \, z^{- (M_2-1)}
\end{equation}

- Si la señal es anticausal, la ROC corresponde a $z \in \mathbb{C} \setminus \{ infty \}$.

\begin{equation}
X(z) = x[M_1] \, z^{(M_1)}+ \dots + x[-2] \, z^{2} + x[-1] \, z^{1} + x[0]
\end{equation}

- Si la señal tiene parte causal y parte anticausal, la ROC corresponde a $z \in \mathbb{C} \setminus \{ infty , 0 \}$.

\begin{equation}
X(z) = x[M_1] \, z^{(M_1)} + \dots + x[0] + \dots + x[M_2 - 1] \, z^{- (M_2-1)}
\end{equation}

### Transformada del delta de Dirac

\begin{equation}
\mathcal{Z} \{ \delta[k] \} = \sum_{k = -\infty}^{\infty} \delta[k] \, z^{-k} = 1
\end{equation}

para $z \in \mathbb{C}$. La ROC corresponde a todo el plano $z$.

Como $\mathcal{Z} \{ \delta[k] \} = 1$, todas las frecuencias están presentes en la señal con igual peso.

```python

k = sym.symbols('k', integer=True)
z = sym.symbols('z', complex=True)

X = sym.summation(sym.KroneckerDelta(k, 0) * z**(-k), (k, -sym.oo, sym.oo))
X
```

### Transformada de un pulso causal

Suponga que $x[k] = \text{rect}_N[k]$ es una señal causal rectangular de duración $N$.

\begin{equation}
\begin{split}
\mathcal{Z} \{ \text{rect}_N[k] \} &= \sum_{k=0}^{N-1} z^{-k}
\\
&= 1 + z^{-1} + \dots + z^{-(N - 1)}
\\
&= 1 + \frac{1}{z^{1}} + \dots + \frac{1}{z^{N-1}}
\\
\end{split}
\end{equation}

con $z \in \mathbb{C} \setminus \{ 0 \}$.

Observe que la sumatoria resultante puede reescribirse como

\begin{equation}
\mathcal{Z} \{ \text{rect}_N[k] \} =  \begin{cases}
\frac{1 - z^{-N}}{1 - z^{-1}} & \text{for } z \neq 1 \\
N & \text{for } z = 1
\end{cases}
\end{equation}

### Transformada de una Exponencial Compleja y causal

La transformada $X(z) = \mathcal{Z} \{ x[k] \}$ de una señal exponencial compleja y causal

\begin{equation}
x[k] = \epsilon[k] \cdot z_0^k
\end{equation}

con frecuencia compleja $z_0 \in \mathbb{C}$ se obtiene de la expresión integral de la transfomada $z$

\begin{equation}
X(z) = \sum_{k=0}^{\infty} z_0^k \cdot z^{-k} = \sum_{k=0}^{\infty} \left( \frac{z_0}{z} \right)^k = \frac{z}{z - z_0}
\end{equation}

Lo anterior ya que la sumatoria resultante es una [serie geométrica](https://en.wikipedia.org/wiki/Geometric_series). Esta transformada converge si $\left| \frac{z_0}{z} \right| < 1$, es decir, la ROC es

\begin{equation}
|z| > |z_0|
\end{equation}

Así, la transformada $z$ de la señal causal exponencial compleja es:

\begin{equation}
\mathcal{Z} \{ \epsilon[k] \cdot z_0^k \} = \frac{z}{z - z_0} \qquad \text{for } |z| > |z_0|
\end{equation}

```python
z0 = sym.symbols('z0')

X = sym.summation(z0**k * z**(-k), (k, 0, sym.oo))
X
```

$\displaystyle \begin{cases} \frac{1}{1 - \frac{z_{0}}{z}} & \text{for}\: \left|{\frac{z_{0}}{z}}\right| < 1 \\\sum_{k=0}^{\infty} z^{- k} z_{0}^{k} & \text{otherwise} \end{cases}$

## Convergencia

Teniendo en cuenta que la transformada $z$ es una serie infinita, es una condición necesaria pero no suficiente para su convergencia que las normas de los elementos que la conforman sean sumables.

\begin{equation}
\sum_{k = -\infty}^{\infty} | x[k] \cdot z^{- k} | = \sum_{k = -\infty}^{\infty} | x[k] | \cdot | z |^{- k}  < \infty
\end{equation}

Observe que la ROC se determina entonces por los valores de $|z|$, por lo cual se generan "anillos" en el plano $z$ que pueden incluir $z=0$ o $z=\infty$. Como $z = e^{\Sigma} \cdot e^{j \Omega}$, la fase $\Omega$ de $z$ no tiene efectos sobre la convergencia.

Puede observarse que la transformada $z$ de la exponencial compleja y causal tiene una ROC en forma de $|z| > z_0$. En términos generales, las ROC se grafican a continuación.

## Transformada de Laplace de una señal muestreada

Suponga una señal muestreada $x_\text{s}(t)$,

\begin{equation}
x_\text{s}(t) = \sum_{k = -\infty}^{\infty} x(k T) \cdot \delta(t - k T) = \sum_{k = -\infty}^{\infty} x[k] \cdot \delta(t - k T)
\end{equation}

donde $x(t)$ es una señal de tiempo continuo y $T$ el periodo de muestreo.

La transformada de Laplace de una señal muestreada es:

\begin{equation}
X_\text{s}(s) = \int_{-\infty}^{\infty} \sum_{k = -\infty}^{\infty} x[k] \cdot \delta(t - k T) \, e^{- s t} \; dt = \sum_{k = -\infty}^{\infty} x[k] \, e^{-s k T}
\end{equation}

Comparando la transformada de Laplace de una señal muestreada con la transformada $z$.

| Transformada $z$ | Transformada de Laplace |
|------------------|-------------------------|
|\begin{equation} X(z) = \sum_{k = -\infty}^{\infty} x[k] \, z^{-k} \end{equation} | \begin{equation} X_\text{s}(s) = \sum_{k = -\infty}^{\infty} x[k] \, e^{-s k T} \end{equation} |

Se observa que $X(z) = X_\text{s}(s)$ si $z^{-k} = e^{-s k T}$, es decir:

\begin{equation}
X_\text{s}(s) = X(z) \big\rvert_{z = e^{s T}}
\end{equation}

Esto implica que la representación frecuencial de la señal muestreada $X_\text{s}(s)$ es equivalente a la transformada $z$  de la señal discreta $X(z)$ con $z = e^{s T}$.

Un mapeo entre el plano $s$ y el plano $z$ se muestra a continuación.

## Mapas de polos y ceros

Como la transformada $z$ $X(z) = \mathcal{Z} \{ x[k] \}$ es una función compleja que depende de la variable compleja $z \in \mathbb{C}$, puede representarse con su magnitud $|X(z)|$ y fase $\varphi(z)$ (representación polar) o como sus partes real $\Re \{ X(z) \}$ e imaginaria $\Im \{ X(z) \}$ en el plano $z$ (representación cartesiana).

Al igual que con la transformada de Laplace, la transformada $z$ de varias señales o sistemas puede representarse como fracciones entre polinomios. Como los polinomios se pueden representar desde sus raíces, también las transformadas $z$. Las raices del numerador son llamadas *ceros* y las del denominador *polos* de $X(z)$.

\begin{equation}
X(z) = \frac{\sum_{m=0}^{M} \beta_m \, z^{-m}}{\sum_{n=0}^{N} \alpha_n \, z^{-n}} = K \cdot \frac{\prod_{\mu=0}^{Q} (z - z_{0 \mu})}{\prod_{\nu=0}^{P} (z - z_{\infty \nu})}
\end{equation}

Es frecuente ilustrar los polos y ceros en un [diagrama de polos y ceros](https://en.wikipedia.org/wiki/Pole%E2%80%93zero_plot). El círculo unitario es relevante en aplicaciones de señales y control.

La ubicación de los polos y ceros permiten interpretar la composición de la señal. Por ejemplo, la transformada  $z$ de una [señal exponencial compleja](#Transformation-of-the-Causal-Complex-Exponential-Signal) tiene un cero en $z=0$ y un polo en  $z = z_0$. Si una señal es combinación lineal de exponenciales, habrá varios polos con ubicaciones en las frecuencias de cada señal.

## Propiedades

Dadas las propiedades presentadas para la transformada de Fourier y la estructura de las transformadas de Laplace y de Fourier, se obtienen las mismas propiedades.

### Invertible
\begin{equation}
x[k] = \mathcal{Z}^{-1} \left\{ \mathcal{Z} \{ x[k] \} \right\}
\end{equation}

### Linealidad

\begin{equation}
\mathcal{Z} \{ A \cdot x_1[k] + B \cdot x_2[k] \} = A \cdot X_1(z) + B \cdot X_2(z)
\end{equation}

**Ejemplo - Transformada $z$ de una señal senoidal causal**

\begin{equation}
x[k] = sin( \Omega _0 t) \cdot \epsilon [k]
\end{equation}

con $\Omega _0 \in \mathbb{R}^+$

De acuerdo con las expresiones de Euler:
\begin{align}
\cos(\Omega_0 k) &= \frac{1}{2} \left( e^{j \Omega_0 k} + e^{-j \Omega_0 k} \right) \\
\sin(\Omega_0 k) &= \frac{1}{2j} \left( e^{j \Omega_0 k} - e^{-j \Omega_0 k} \right)
\end{align}

Así, la transformada de $sin( \Omega _0 k)$ debe ser igual a la de $\frac{1}{2j} ( e^{j \Omega_0 k} - e^{-j \Omega_0 k})$.

Dado que la transformada $z$ de una exponencial compleja decreciente y causal es :

\begin{equation}
\mathcal{Z} \{ \epsilon[k] \cdot z_0^{k} \} = \frac{z}{z - z_0}
\end{equation}

Entonces:

\begin{equation}
\mathcal{Z} \{ sin( \Omega _0 t) \} = \frac{1}{2j} \left( \frac{z}{z - e^{j \Omega_0}} - \frac{z}{z - e^{-j \Omega_0}} \right) = \frac{z \sin(\Omega_0)}{z^2 - 2z\cos(\Omega_0) + 1}
\end{equation}

ROC $|z|>1$

Aplicando el mismo razonamiento puede encontrarse la transformada del coseno.

Se define la señal en tiempo discreto

```python

k = sym.symbols('k', integer=True)
W0 = sym.symbols('Omega0', real=True)
z = sym.symbols('z', complex=True)
x = sym.sin(W0 * k)*sym.Heaviside(k)
x
```

Se define la transformada $z$

```python
Xnum = z*sym.sin(W0)
Xden = z**2 - 2*z*sym.cos(W0) + 1
X = Xnum / Xden
X
```

Se encuentran los ceros

```python
ceros = sym.roots(Xnum,z)
ceros
```

Se encuentran los polos

```python
polos = sym.roots(Xden,z)
polos
```

se grafica el mapa de polos y ceros

```python
X2 = X.subs(W0, 8)
pole_zero_plot(sym.roots(sym.denom(X2), z), sym.roots(sym.numer(X2), z))
```

### Lista de propiedades

A continuación se listan propiedades y teoremas:

|   | $x[k]$ | $X(z) = \mathcal{Z} \{ x[k] \}$ | Región de convergencia ROC |
|:---|:---:|:---:|:---:|
| Linealidad | $A \, x_1[k] + B \, x_2[k]$ | $A \, X_1(z) + B \, X_2(z)$ | $\supseteq ROC\{x_1\} \cap ROC\{x_2\}$ |
| Señales reales | $x[k] = x^*[k]$ | $X(z) = X^*(z^*)$ | |
| Convolución | $x[k] * h[k]$ | $X(z) \cdot H(z)$ | $\supseteq \text{ROC}\{x[k]\} \cap \text{ROC}\{h(t)\}$ |
| Desplazamiento | $x[k - \kappa]$ | $z^{- \kappa} \cdot X(z)$ | $\text{ROC}\{x[k]\}$ |
| Modulación | $z_0^{k}\cdot x[k]$ | $X(\frac{z}{z_0})$ | $s: s - \Re \{s_0\} \in \text{ROC}\{x(t)\}$ |

donde $A, B, z_0 \in \mathbb{C}$, $a \in \mathbb{R} \setminus \{0\}$ y $\kappa \in \mathbb{R}$.

## Algunas transformadas $z$

A continuación se listan las transformadas $z$ de funciones usadas a menudo:

| $x[k]$                          | $X(z) = \mathcal{Z} \{ x[k] \}$ | Región de Convergencia ROC |
|:-------------------------------:|:-------------------------------:|:------------------------:|
| $\delta[k]$                     | $1$                             | $\mathbb{C}$             |
| $\epsilon[k]$                   | $\frac{z}{z-1}$                 | $|z| > 1$                |
| $k \epsilon[k]$                 | $\frac{z}{(z-1)^2}$             | $\|z| > 1$               |
| $z_0^{k} \epsilon[k]$           | $\frac{z}{z - z_0}$             | $|z| > |z_0|$            |
| $\sin(\Omega_0 k) \epsilon[k]$  | $\frac{z\sin(\Omega_0)}{z^2 + 2zcos(\Omega_0) + 1}$ | $|z|>1$ |
| $\cos(\Omega_0 k) \epsilon[k]$  | $\frac{z^2 - z\cos(\Omega_0)}{z^2 + 2zcos(\Omega_0) + 1}$ | $|z|>1$            |

## Función de transferencia

Al igual que con la transformada de Laplace, la transformada $z$ permite modelar sistemas LTI como funciones racionales entre polinomios.

**Ejemplo**

Suponga el siguiente modelo para un sistema de tiempo discreto cuya entrada es $x[k]$ y salida $y[k]$.

\begin{equation}
y[k] - y[k-1] + \frac{1}{2} y[k-2] = x[k]
\end{equation}

\begin{equation}
y[k] = y[k-1] - \frac{1}{2} y[k-2] + x[k]
\end{equation}

Aplicando la transformada $z$ a la ecuación se tiene

\begin{equation}
Y(z) - Y(z)z^{-1} + \frac{1}{2} Y(z)z^{-2} = X(z)
\end{equation}

Puede encontrarse una expresión para la salida en el dominio $z$ como

\begin{equation}
Y(z) = \frac{X(z)}{1 - z^{-1} + \frac{1}{2}z^{-2}}
\end{equation}

Así, la función de transferencia es:

\begin{equation}
H(z)= \frac{Y(z)}{X(z)} = \frac{1}{1 - z^{-1} + \frac{1}{2}z^{-2}}
\end{equation}

Para ilustrar, se grafica la respuesa frecuencial del sistema en tiempo discreto $H(e^{j \Omega}) = H(z) \vert_{z = e^{j \Omega}}$.

```python
# define variables and transfer function
z = sym.symbols('z', complex=True)
W = sym.symbols('Omega', real=True)
H = 1 / (1 - z**(-1) + sym.Rational(1, 2)*z**(-2))

# plot transfer function
sym.plot(sym.Abs(H.subs(z, sym.exp(sym.I*W))), (W, -0*sym.pi, 1*sym.pi),
         ylim=(0, 3), xlabel=r'$\Omega$', ylabel=r'$|H(e^{j \Omega})|$')
```

    <sympy.plotting.plot.Plot at 0x23c9a726748>

```python
H
```

```python
H1 = 2* z**2 / ((2* z**2) - (2*z) + 1)
pole_zero_plot(sym.roots(sym.denom(H1), z), sym.roots(sym.numer(H1), z))
```

Observe que la respuesta en frecuencia del sistema discreto es periódica.

## Aproximaciones

Así como hay equivalencia entre los dominios $s$ y $z$, puede aproximarse la derivada de una función a partir de muestras. Analice la siguiente gráfica.

La razón de cambio aproximada a partir de las muestras en $x+h$ y en $x$ corresponde a $\frac{f(x+h)-f(x)}{h}$. Estas muestras están separadas por $h$.

En el caso de señales en tiempo discreto, la separación temporal entre muestras es $T_\text{s}$. Además, debido a restricciones de causalidad, se suele aproximar con información del pasado, por lo cual se hace la siguiente aproximación:

\begin{equation}
\frac{df}{dt}\big\rvert_{t = k \cdot T_\text{s}} \approx \frac{f[k]-f[k-1]}{T_\text{s}}
\end{equation}

```python

```