Created
March 4, 2016 03:41
-
-
Save marcionicolau/f139705b2a456deb3c4b to your computer and use it in GitHub Desktop.
FFT R Examples
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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