---
title: "Fourier transforms of a few common signals"
subtitle: "Slides generated using python, plotly and ioslides"
author: "Marc Wouts"
output: 
  ioslides_presentation:
    widescreen: true
    smaller: true
editor_options: 
  chunk_output_type: console
jupyter:
  kernelspec:
    display_name: Python 3
    language: python
    name: python3
  language_info:
    codemirror_mode:
      name: ipython
      version: 3
    file_extension: .py
    mimetype: text/x-python
    name: python
    nbconvert_exporter: python
    pygments_lexer: ipython3
    version: 3.6.6
  main_language: python
  nbrmd_formats: ipynb,Rmd
---

```{r setup, include=FALSE, active="Rmd"}
knitr::opts_chunk$set(echo = FALSE, fig.width = 10, fig.height = 5)

library(reticulate)
reticulate::use_python('C:/Users/Marco/AppData/Local/conda/conda/envs/python3/python.exe')
library(jsonlite)
pyplot <- function() plotly::as_widget(
  jsonlite::fromJSON(
    reticulate::py$fig, simplifyVector=FALSE))
```

```{python echo=FALSE, active="ipynb", eval=FALSE}
import plotly.offline as offline
import json

offline.init_notebook_mode()

def pyplot():
    offline.iplot(json.loads(fig), show_link=False)
```

## Fourier transforms of a few common signals

In this presentation we describe the Fourier coefficients of a few common signals. We illustrate how irregularities (discontinuities) in the signal correspond to a slow decay of weights on larger harmonics.

This presentation was made with

> - [ioslides by RStudio](https://rmarkdown.rstudio.com/ioslides_presentation_format.html)
> - python's numpy for fast Fourier transforms and inverses
> - python's version of plotly
> - the reticulate package for executing python in RStudio

The presentation can be compiled to HTML, interactive slides using either Rstudio, or the command line instruction 
`R -e 'rmarkdown::render("ioslides_presentation_featuring_plotly_python.Rmd")'`

Alternatively, and that's the point of the `nbrmd` package, this presentation can be edited directly in Jupyter.

## Python includes

```{python echo=TRUE}
import json
import plotly
import plotly.graph_objs as go
```

```{python echo=TRUE}
import numpy as np
from numpy.fft import fft, ifft
import math
eps = 1e-3
```

```{python echo=TRUE}
def plot_signal_and_fft(signal, name, N=20, asFigure=False):
    f = fft(signal)
    N = min(N, len(signal) / 2)
    x = np.arange(-N, N)
    y = np.concatenate((f[-N:], f[:N]))
    f[N:len(f) - N] = 0
    signal_reconstructed = ifft(f).real
    data = [go.Scatter(x=np.arange(-len(signal), len(signal)),
                       y=np.concatenate((signal, signal)),
                       name='Discrete signal'),
            go.Scatter(x=np.arange(-len(signal), len(signal)),
                       y=np.concatenate(
                           (signal_reconstructed, signal_reconstructed)),
                       name='Signal reconstructed from truncated FFT'),
            go.Bar(x=x, y=y.real,
                   name='Fourier transform (real part)',
                   xaxis='x2', yaxis='y2'),
            go.Bar(x=x, y=y.imag,
                   name='Fourier transform (imaginary part)',
                   xaxis='x2', yaxis='y2')]
    layout = go.Layout(title='Fourier transform for {}'.format(name),
                       barmode='stack',
                       xaxis=dict(domain=[0, .45]),
                       xaxis2=dict(domain=[.55, 1]),
                       yaxis=dict(title='amplitude'),
                       yaxis2=dict(anchor='x2'),
                       legend=dict(orientation='h'))
    fig = dict(data=data, layout=layout)
    return json.dumps(fig, cls=plotly.utils.PlotlyJSONEncoder)
```

## Sinusoidal wave

The Fourier of a sinusoidal is 100% imaginary, and has positive value on the main frequency only.

```{python echo=TRUE}
x = np.arange(0, 2 * math.pi, eps)
fig = plot_signal_and_fft(np.sin(x), 'sinus')
```

```{r active="Rmd"}
pyplot()
```

```{python echo=FALSE, active="ipynb", eval=FALSE}
pyplot()
```


## Cosinusoidal wave

The Fourier of a cosinus is 100% real, and has positive value on the main frequency only.

```{python echo=TRUE}
fig = plot_signal_and_fft(np.cos(x), 'cos')
```

```{r active="Rmd"}
pyplot()
```

```{python echo=FALSE, active="ipynb", eval=FALSE}
pyplot()
```

## Triangular wave

The triangle wave has a few harmonics, but they strength decrease rather quickly. The signal reconstructed from 20 harmonics matches very well the original signal.

```{python echo=TRUE}
x = np.arange(-1, 1, eps)
y = np.abs(x) - .5
fig = plot_signal_and_fft(y, 'triangle')
```

```{r active="Rmd"}
pyplot()
```

```{python echo=FALSE, active="ipynb", eval=FALSE}
pyplot()
```

## Square signal

The signal is discontinuous and as such, the Fourier coefficient decrease slowly. A truncated Fourier series corresponds to a continuous signal that matches only approximately the original signal.

```{python echo=TRUE}
y = np.concatenate((np.ones(100), -np.ones(100)))
fig = plot_signal_and_fft(y, 'square')
```

```{r active="Rmd"}
pyplot()
```

```{python echo=FALSE, active="ipynb", eval=FALSE}
pyplot()
```

## Sawtooth signal

This signal is also discontinuous and again, the Fourier coefficient decrease slowly. A truncated Fourier series corresponds to a continuous signal that matches only approximately the original signal.

```{python echo=TRUE}
x = np.arange(0, 1, eps)
y = np.abs(x) - .5
fig = plot_signal_and_fft(y, 'sawtooth')
```

```{r active="Rmd"}
pyplot()
```

```{python echo=FALSE, active="ipynb", eval=FALSE}
pyplot()
```

## Two columns slide {.columns-2}

```{r results='asis', active="Rmd"}
cat(stringi::stri_rand_lipsum(3), sep='\n\n')
```

## Unequal columns {.smaller}

<div style="float: left; width: 30%;">
```{r results='asis', active="Rmd"}
cat(stringi::stri_rand_lipsum(1), sep='\n\n')
```
</div>
<div style="float: right; width: 70%;">
```{r results='asis', active="Rmd"}
cat(stringi::stri_rand_lipsum(2), sep='\n\n')
```
</div>

## Sawtooth signal in two columns

<div style="float: left; width: 35%;">
This signal is also discontinuous and again, the Fourier coefficient decrease slowly. A truncated Fourier series corresponds to a continuous signal that matches only approximately the original signal.

```{python echo=TRUE}
x = np.arange(0, 1, eps)
y = np.abs(x) - .5
fig = plot_signal_and_fft(y, 'sawtooth')
```
</div>

<div style="float: right; width: 60%;">
```{r active="Rmd", fig.width=5}
pyplot()
```

```{python echo=FALSE, active="ipynb", eval=FALSE}
pyplot()
```
</div>
