How many things would you attempt if you knew you could not fail?

Taking this Robert Frost’s verse as a dare, I am attempting to write a blog. It will likely be a collection of most random stuff. It might fail. But it will certainly be about the things that I find terribly cool, and it will certainly very often be about R. The two don’t necessarily exclude each other, by the way.

So given the above stated sentiment, I though I might as well kick the thing off with something completly random. As it happens, ‘Do I Wanna Know?’ by Arctic Monkeys came up on my Spotify playlist, and the next thing I know — I’ve just spent half an hour recrating the album artwork in R. But bear with me, if you will, it is more cool than it sounds at first.

Do I Wanna Know?

For those unfamiliar with the said song… come on, how can you not know this song? Now is the perfect time to google it and watch the music video. Then, we’ll try and recreate those fancy graphics from the begining of the video, with the iconic sunglasses that also feature on the AM album cover.

Double Sideband Suppressed Carrier Amplitude Modulation (DSB-SC AM)

My starting point was that this fancy graph must be a combination of sinusoids with changing amplitudes. As usually, some people way more clever than myself have explained it online, and indeed, it is an amplitude modulated sine wave. Precisely, it is a signal produced by the specific Double Sideband Suppressed Carrier Amplitude Modulation (DSB-SC AM).

OK, word by word.

Amplitude modulation referes to the fact that the amplitude of a high frequency carrier signal is modulated by a low frequency baseband signal.
Double sideband means that the frequencies produced by amplitude modulation are symmetrically spaced above and below the carrier frequency.
And suppressed referes to the fact that carrier level is reduced to the lowest practical level (ideally, it is completely suppressed).
Googling also lets you know that in practice, this is used for shifting the spectra of waves (e.g. sound), which makes it possible to transmit them through antenna of practical dimensions.

And here’s the function that produces the desired signal.

AMfunction <- function(x,h=20,L=1,l=1,s=0.1,f=0,g=1) {
# baseband - a low frequency signal
E <- function(x,s,f,l) {
s + exp(f*(-1)*x^2/0.4) * (sin(l*x))^2 + 0.35*exp(-1/2*(x/0.4)^2)
}
# carrier - a high frequency sinusoid
H <- function(x,h,L) {
L*cos(h*x)
}
# a small Gaussian to create the elevation for the letter M
G <- function(x) {
exp(-1/2*((x-0.15)/0.1)^2)
}
# by multiplying, low frequency sinusoid becomes the envelope 
# of the high frequency carrier;
# the envelope modulates the amplitude of the carrier;
E(x,s,f,l)*H(x,h,L)*(1-1/2*G(x)*g)+1/6*G(x)*g
}

Bam, just like that? There are actually three functions, which I’ll break down now.

Baseband, E()

E() is the baseband, a low frequency signal. It defines the ‘outer’ range within which the actual signal will be. There are three important parts of the equation:

  • sine is the main part that defines the range for the signal, aka the sunglasses-like pattern, with the setting the frequency value; multiplying the sine wave with gaussian effectively superimposes normal distribution on the sine wave (setting to 0 precludes this)
  • the second element is gaussian that elevates the central part of the sinusoid, aka the AM letters
  • s defines vertical shift

Here’s an example of how changing the aparameters affects the resulting sine wave. For simplicity, the plots are shown without the gaussian that elevates the central part of the sinusoid.

Carrier, H()

H() is the carrier, a high frequency sinusoid. It’s frequency is set by , and its amplitude by . In order to obtain the desired AM artwork, this frequency should be some 20 times the frequency of the baseband.

Modification, G()

G() is a small Gaussian that creates the elevation for the letter M in the middle of the graph.


So, back in our AMfunction(), these are the parameters you can modify:

  • h, the frequency of a high-frequency carrier
  • L, the amplitude of a high-frequency carrier
  • l, the frequency of a low-frequency baseband
  • s, the vertical shift of a low-frequency baseband
  • f, factor which controls superimosing gaussian to a low-frequncy baseband, setting it to 0 effectively removes any scaling, while setting it to 1 scales the envelope to normal distribution
  • g, factor introduced for scaling the gaussian which makes the M letter in the middle of the graph

Plotting the AM graph

Now let’s plot our graph for , using the default values of parameters.

x <- runif(10000,-1,1)*pi
y <- AMfunction(x)
df <- data.frame(x=x,y=y)
require(ggplot2)
ggplot(df,aes(x,y)) + 
    geom_line() + 
	theme_void()

Looking good, eh? The fun part starts now — lets make it move. The gganimate package amazingly revamped by Thomas Lin Pedersen makes this possible (the package is not yet on CRAN, but you can get it from GitHub).

First, I’ll just make the transition between the simple horizontal line at , and the amplitude modulated sine wave. The transition_states and transition_length are the required arguments specifying relative length for animation states and transitions between them, respectively.

df <- data.frame(x=x, y0=0, y1=y)
require(data.table)
df_melted <- melt(df,id.vars="x",measure.vars=c("y0","y1"))
require(gganimate)
am <- ggplot(df_melted,aes(x,value)) +  
    geom_line() +  
    theme_void() +  
    transition_states(variable,transition_length=1,state_length=1)    
animate(am, length=1, width=1000, height=400)

Changing the parameters to produce the other type of graph seen in the video.

y <- AMfunction(x,s=0,l=0.01,L=3,g=0,f=1)
df <- data.frame(x=x, y=y)
ggplot(df, aes(x,y)) + geom_line() + theme_void()

We can then combine the two AM graphs with simple horizontal line in a single animation.

df <- data.frame(x=x, y0=0, y1=y, y2=0, y3=AMfunction(x))
df_melted <- melt(df,id.vars="x",measure.vars=c("y0","y1","y2","y3"))
am <- ggplot(df_melted,aes(x,value)) + 
    geom_line() +  
    theme_void() +  
    transition_states(variable,transition_length=1,state_length=0.5)  
animate(am, length=1, width=1000, height=400)

Combining the two AM graphs with different simple curves, we can come close to recreating the animations seen in the video. Here’s how close I got. I challange you to do better, and share your ideas in the comments below.

References

The function I used is modified from the following Quora answer.
The animation is brought to you by gganimate.