---
title: "Getting started with a simple example"
output: rmarkdown::html_vignette
bibliography: data/references.bib
link-citations: true
vignette: >
  %\VignetteIndexEntry{Getting started with a simple example}
  %\VignetteEngine{knitr::rmarkdown}
  %\VignetteEncoding{UTF-8}
---

```{r, include = FALSE}
knitr::opts_chunk$set(
  collapse = TRUE,
  comment = "#>",
  fig.width = 7
)
```

```{r setup}
library(rhosa)
```

This is a simple example, based on the outline at Figure 1 of [@villa_cross-frequency_2010], which
demonstrates how to use rhosa's functions to find an obscure relationship
between two frequencies in some time series imitated by a generative model.

With four cosinusoidal waves having arbitrarily different phases (`omega_a`,
`omega_b`, `omega_c`, and `omega_d`), but sharing a couple of frequencies
(`f_1` and `f_2`), we define function `D(t)` to simulate a pair of time series:
`v` and `w`. We make them noisy by adding an independent random variate that
follows the standard normal distribution.

```{r init}
set.seed(1)
f_1 <- 0.35
f_2 <- 0.2
D <- function(t) {
    omega_a <- runif(1, min = 0, max = 2 * pi)
    omega_b <- runif(1, min = 0, max = 2 * pi)
    omega_c <- runif(1, min = 0, max = 2 * pi)
    omega_d <- runif(1, min = 0, max = 2 * pi)
    wave_a <- function(t) cos(2 * pi * f_1 * t + omega_a)
    wave_b <- function(t) cos(2 * pi * f_2 * t + omega_b)
    wave_c <- function(t) cos(2 * pi * f_1 * t + omega_c)
    wave_d <- function(t) cos(2 * pi * f_2 * t + omega_d)
    curve_v <- function(t) wave_a(t) + wave_b(t) + wave_a(t) * wave_b(t)
    curve_w <- function(t) wave_c(t) + wave_d(t) + wave_c(t) * wave_b(t)
    data.frame(v = curve_v(t) + rnorm(length(t)),
               w = curve_w(t) + rnorm(length(t)))
}
```

Both `v` and `w` are oscillatory in principle:

```{r ts, fig.cap = "v and w."}
data <- D(seq_len(2048))
with(data, {
    plot(seq_len(100), head(v, 100), type = "l", col = "green", ylim = c(-3, 3), xlab = "t", ylab = "value")
    lines(seq_len(100), head(w, 100), col = "orange")
})
```

It is noteworthy that the power spectrum densities of `v` and `w` are basically
identical as shown in their spectral density estimation:

```{r psd, fig.cap = "Spectral density estimation via periodograms.", fig.show = "hold"}
with(data, {
    spectrum(v, main = "v", col = "green")
    spectrum(w, main = "w", col = "orange")
})
```

On the other hand, their bispectra are different. More specifically, we are
going to see that their bicoherence at some pairs of frequencies are
different. rhosa's `bicoherence` function allows us to estimate the
magnitude-squared bicoherence from samples.

```{r bc}
x <- replicate(100, D(seq_len(128)), simplify = FALSE)
m_v <- do.call(cbind, Map(function(d) {d$v}, x))
m_w <- do.call(cbind, Map(function(d) {d$w}, x))

library(rhosa)

bc_v <- bicoherence(m_v, window_function = 'hamming')
bc_w <- bicoherence(m_w, window_function = 'hamming')
```

In the above code, we take 100 samples of the same length for a smoother result.
The `bicoherence` function accepts a matrix whose column represents a sample
sequence, and returns a data frame. Note that an optional argument to
`bicoherence` is given for requesting tapering with Hamming
[window function](https://en.wikipedia.org/wiki/Window_function).

```{r plot_bicoherence}
library(ggplot2)

plot_bicoherence <- function(bc) {
    ggplot(bc, aes(f1, f2)) +
        geom_raster(aes(fill = value)) +
        scale_fill_gradient(limits = c(0, 10)) +
        coord_fixed()
}
```

The axis `f1` and `f2` represent normalized frequencies in unit cycles/sample of
range `[0, 1)`. Frequency pairs of bright points in the following plot of `bc_v`
indicate the existence of some quadratic phase coupling, as expected:

```{r viz_bc_v, fig.cap = "v's estimated magnitude-squared bicoherence."}
plot_bicoherence(bc_v)
```

In contrast, `bc_w` has no peaks at frequency pair `(f_1, f_2) = (0.35, 0.2)`, etc.:

```{r viz_bc_w, fig.cap = "w's estimated magnitude-squared bicoherence."}
plot_bicoherence(bc_w)
```

## References

