Skip to content

Instantly share code, notes, and snippets.

@marcionicolau
Created March 4, 2016 03:41
Show Gist options
  • Save marcionicolau/f139705b2a456deb3c4b to your computer and use it in GitHub Desktop.
Save marcionicolau/f139705b2a456deb3c4b to your computer and use it in GitHub Desktop.
FFT R Examples
xs <- seq(-2*pi,2*pi,pi/100)
wave.1 <- sin(3*xs)
wave.2 <- sin(10*xs)
par(mfrow = c(1, 2))
plot(xs,wave.1,type="l",ylim=c(-1,1)); abline(h=0,lty=3)
plot(xs,wave.2,type="l",ylim=c(-1,1)); abline(h=0,lty=3)
wave.3 <- 0.5 * wave.1 + 0.25 * wave.2
plot(xs,wave.3,type="l"); title("Eg complex wave"); abline(h=0,lty=3)
wave.4 <- wave.3
wave.4[wave.3>0.5] <- 0.5
plot(xs,wave.4,type="l",ylim=c(-1.25,1.25)); title("overflowed, non-linear complex wave"); abline(h=0,lty=3)
repeat.xs <- seq(-2*pi,0,pi/100)
wave.3.repeat <- 0.5*sin(3*repeat.xs) + 0.25*sin(10*repeat.xs)
plot(xs,wave.3,type="l"); title("Repeating pattern")
points(repeat.xs,wave.3.repeat,type="l",col="red"); abline(h=0,v=c(-2*pi,0),lty=3)
plot.fourier <- function(fourier.series, f.0, ts) {
w <- 2*pi*f.0
trajectory <- sapply(ts, function(t) fourier.series(t,w))
plot(ts, trajectory, type="l", xlab="time", ylab="f(t)"); abline(h=0,lty=3)
}
# An eg
plot.fourier(function(t,w) {sin(w*t)}, 1, ts=seq(0,1,1/100))
acq.freq <- 100 # data acquisition frequency (Hz)
time <- 6 # measuring time interval (seconds)
ts <- seq(0,time,1/acq.freq) # vector of sampling time-points (s)
f.0 <- 1/time # fundamental frequency (Hz)
dc.component <- 0
component.freqs <- c(3,10) # frequency of signal components (Hz)
component.delay <- c(0,0) # delay of signal components (radians)
component.strength <- c(.5,.25) # strength of signal components
f <- function(t,w) {
dc.component +
sum( component.strength * sin(component.freqs*w*t + component.delay))
}
plot.fourier(f,f.0,ts)
component.delay <- c(pi/2,0) # delay of signal components (radians)
plot.fourier(f,f.0,ts)
dc.component <- -2
plot.fourier(f,f.0,ts)
fft(c(1,1,1,1)) / 4 # to normalize
fft(1:4) / 4
1:4/4
# cs is the vector of complex points to convert
convert.fft <- function(cs, sample.rate=1) {
cs <- cs / length(cs) # normalize
distance.center <- function(c)signif( Mod(c), 4)
angle <- function(c)signif( 180*Arg(c)/pi, 3)
df <- data.frame(cycle = 0:(length(cs)-1),
freq = 0:(length(cs)-1) * sample.rate / length(cs),
strength = sapply(cs, distance.center),
delay = sapply(cs, angle))
df
}
convert.fft(fft(1:4))
# returns the x.n time series for a given time sequence (ts) and
# a vector with the amount of frequencies k in the signal (X.k)
get.trajectory <- function(X.k,ts,acq.freq) {
N <- length(ts)
i <- complex(real = 0, imaginary = 1)
x.n <- rep(0,N) # create vector to keep the trajectory
ks <- 0:(length(X.k)-1)
for(n in 0:(N-1)) { # compute each time point x_n based on freqs X.k
x.n[n+1] <- sum(X.k * exp(i*2*pi*ks*n/N)) / N
}
x.n * acq.freq
}
plot.frequency.spectrum <- function(X.k, xlimits=c(0,length(X.k))) {
plot.data <- cbind(0:(length(X.k)-1), Mod(X.k))
# TODO: why this scaling is necessary?
plot.data[2:length(X.k),2] <- 2*plot.data[2:length(X.k),2]
plot(plot.data, t="h", lwd=2, main="",
xlab="Frequency (Hz)", ylab="Strength",
xlim=xlimits, ylim=c(0,max(Mod(plot.data[,2]))))
}
# Plot the i-th harmonic
# Xk: the frequencies computed by the FFt
# i: which harmonic
# ts: the sampling time points
# acq.freq: the acquisition rate
plot.harmonic <- function(Xk, i, ts, acq.freq, color="red") {
Xk.h <- rep(0,length(Xk))
Xk.h[i+1] <- Xk[i+1] # i-th harmonic
harmonic.trajectory <- get.trajectory(Xk.h, ts, acq.freq=acq.freq)
points(ts, harmonic.trajectory, type="l", col=color)
}
X.k <- fft(c(4,0,0,0)) # get amount of each frequency k
time <- 4 # measuring time interval (seconds)
acq.freq <- 100 # data acquisition frequency (Hz)
ts <- seq(0,time-1/acq.freq,1/acq.freq) # vector of sampling time-points (s)
x.n <- get.trajectory(X.k,ts,acq.freq) # create time wave
plot(ts,x.n,type="l",ylim=c(-2,4),lwd=2)
abline(v=0:time,h=-2:4,lty=3); abline(h=0)
plot.harmonic(X.k,1,ts,acq.freq,"red")
plot.harmonic(X.k,2,ts,acq.freq,"green")
plot.harmonic(X.k,3,ts,acq.freq,"blue")
acq.freq <- 100 # data acquisition (sample) frequency (Hz)
time <- 6 # measuring time interval (seconds)
ts <- seq(0,time-1/acq.freq,1/acq.freq) # vector of sampling time-points (s)
f.0 <- 1/time
dc.component <- 1
component.freqs <- c(3,7,10) # frequency of signal components (Hz)
component.delay <- c(0,0,0) # delay of signal components (radians)
component.strength <- c(1.5,.5,.75) # strength of signal components
f <- function(t,w) {
dc.component +
sum( component.strength * sin(component.freqs*w*t + component.delay))
}
plot.fourier(f,f.0,ts=ts)
w <- 2*pi*f.0
trajectory <- sapply(ts, function(t) f(t,w))
head(trajectory,n=30)
X.k <- fft(trajectory) # find all harmonics with fft()
plot.frequency.spectrum(X.k, xlimits=c(0,20))
x.n <- get.trajectory(X.k,ts,acq.freq) / acq.freq # TODO: why the scaling?
plot(ts,x.n, type="l"); abline(h=0,lty=3)
points(ts,trajectory,col="red",type="l") # compare with original
plot.show <- function(trajectory, time=1, harmonics=-1, plot.freq=FALSE) {
acq.freq <- length(trajectory)/time # data acquisition frequency (Hz)
ts <- seq(0,time-1/acq.freq,1/acq.freq) # vector of sampling time-points (s)
X.k <- fft(trajectory)
x.n <- get.trajectory(X.k,ts, acq.freq=acq.freq) / acq.freq
if (plot.freq)
plot.frequency.spectrum(X.k)
max.y <- ceiling(1.5*max(Mod(x.n)))
if (harmonics[1]==-1) {
min.y <- floor(min(Mod(x.n)))-1
} else {
min.y <- ceiling(-1.5*max(Mod(x.n)))
}
plot(ts,x.n, type="l",ylim=c(min.y,max.y))
abline(h=min.y:max.y,v=0:time,lty=3)
points(ts,trajectory,pch=19,col="red") # the data points we know
if (harmonics[1]>-1) {
for(i in 0:length(harmonics)) {
plot.harmonic(X.k, harmonics[i], ts, acq.freq, color=i+1)
}
}
}
trajectory <- 4:1
plot.show(trajectory, time=2)
trajectory <- c(rep(1,5),rep(2,6),rep(3,7))
plot.show(trajectory, time=2, harmonics=0:3, plot.freq=TRUE)
trajectory <- c(1:5,2:6,3:7)
plot.show(trajectory, time=1, harmonics=c(1,2))
set.seed(101)
acq.freq <- 200
time <- 1
w <- 2*pi/time
ts <- seq(0,time,1/acq.freq)
trajectory <- 3*rnorm(101) + 3*sin(3*w*ts)
plot(trajectory, type="l")
X.k <- fft(trajectory)
plot.frequency.spectrum(X.k,xlimits=c(0,acq.freq/2))
trajectory1 <- trajectory + 25*ts # let's create a linear trend
plot(trajectory1, type="l")
trend <- lm(trajectory1 ~ts)
detrended.trajectory <- trend$residuals
plot(detrended.trajectory, type="l")
# plot(diff(trajectory1), type = 'l')
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment