diff --git a/bob/pad/face/extractor/FFTFeatures.py b/bob/pad/face/extractor/FFTFeatures.py
new file mode 100644
index 0000000000000000000000000000000000000000..889db74f6c32f5b115aff3089d2cdcb7b7574afe
--- /dev/null
+++ b/bob/pad/face/extractor/FFTFeatures.py
@@ -0,0 +1,83 @@
+#!/usr/bin/env python
+# encoding: utf-8
+
+import numpy
+
+from bob.bio.base.extractor import Extractor
+
+import logging
+logger = logging.getLogger("bob.pad.face")
+
+
+class FFTFeatures(Extractor, object):
+  """
+  Compute the Frequency Spectrum of the given signal.
+
+  The computation is made using numpy's rfft routine 
+
+  **Parameters:**
+
+  framerate: int
+    The sampling frequency of the signal (i.e the framerate ...) 
+
+  nfft: int
+    Number of points to compute the FFT
+
+  debug: boolean
+    Plot stuff
+  """
+  def __init__(self, framerate=25, nfft=256, debug=False, **kwargs):
+
+    super(FFTFeatures, self).__init__(**kwargs)
+    
+    self.framerate = framerate
+    self.nfft = nfft
+    self.debug = debug
+
+
+  def __call__(self, signal):
+    """
+    Compute the frequency spectrum for the given signal.
+
+    **Parameters:**
+
+    signal: numpy.array 
+      The signal
+
+    **Returns:**
+
+      freq: numpy.array 
+       the frequency spectrum 
+    """
+    # sanity check
+    if signal.ndim == 1:
+      if numpy.isnan(numpy.sum(signal)):
+        return
+    if signal.ndim == 2 and (signal.shape[1] == 3):
+      if numpy.isnan(numpy.sum(signal[:, 1])):
+        return
+
+    output_dim = int((self.nfft / 2) + 1)
+    
+    # get the frequencies
+    f = numpy.fft.fftfreq(self.nfft) * self.framerate
+   
+    # we have a single pulse signal
+    if signal.ndim == 1:
+      fft = abs(numpy.fft.rfft(signal, n=self.nfft))
+
+    # we have 3 pulse signal (Li's preprocessing)
+    # in this case, return the signal corresponding to the green channel
+    if signal.ndim == 2 and (signal.shape[1] == 3):
+      ffts = numpy.zeros((3, output_dim))
+      for i in range(3):
+        ffts[i] = abs(numpy.fft.rfft(signal[:, i], n=self.nfft))
+      fft = ffts[1]
+      
+    if self.debug: 
+      from matplotlib import pyplot
+      pyplot.plot(f, fft, 'k')
+      pyplot.title('Power spectrum of the signal')
+      pyplot.show()
+
+    return fft
diff --git a/bob/pad/face/extractor/NormalizeLength.py b/bob/pad/face/extractor/NormalizeLength.py
new file mode 100644
index 0000000000000000000000000000000000000000..21a42ff302b4b0334ff1f0850a2b16f94d490213
--- /dev/null
+++ b/bob/pad/face/extractor/NormalizeLength.py
@@ -0,0 +1,98 @@
+#!/usr/bin/env python
+# encoding: utf-8
+
+import numpy
+
+from bob.bio.base.extractor import Extractor
+
+import logging
+logger = logging.getLogger("bob.pad.face")
+
+
+class NormalizeLength(Extractor, object):
+  """
+  Normalize the length of feature vectors, such that 
+  they all have the same dimensions
+
+  **Parameters:**
+
+  length: int
+    The final length of the final feature vector 
+
+  requires_training: boolean
+    This extractor actually may requires "training".
+    The goal here is to retrieve the length of the shortest sequence
+
+  debug: boolean
+    Plot stuff
+  """
+  def __init__(self, length=-1, debug=False, requires_training=True, **kwargs):
+
+    super(NormalizeLength, self).__init__(requires_training=requires_training, **kwargs)
+    
+    self.length = length
+    self.debug = debug
+
+  def __call__(self, signal):
+    """
+    Normalize the length of the signal 
+
+    **Parameters:**
+
+    signal: numpy.array 
+      The signal
+
+    **Returns:**
+
+      signal: numpy.array 
+       the signal with the provided length 
+    """
+    # we have a single pulse signal
+    if signal.ndim == 1:
+      signal = signal[:self.length]
+
+    # we have 3 pulse signal (Li's preprocessing)
+    # in this case, return the signal corresponding to the green channel
+    if signal.ndim == 2 and (signal.shape[1] == 3):
+      signal = signal[:self.length, 1]
+    
+    if numpy.isnan(numpy.sum(signal)):
+      return
+
+    if signal.shape[0] < self.length:
+      logger.debug("signal shorter than training shape: {} vs {}".format(signal.shape[0], self.length))
+      import sys
+      sys.exit()
+      tmp = numpy.zeros((self.length), dtype=signal.dtype)
+      tmp[:, signal.shape[0]]
+      signal = tmp
+
+    if self.debug: 
+      from matplotlib import pyplot
+      pyplot.plot(signal, 'k')
+      pyplot.title('Signal truncated')
+      pyplot.show()
+
+    return signal
+
+  def train(self, training_data, extractor_file):
+    """
+    This function determines the shortest length across the training set.
+    It will be used to normalize the length of all the sequences.
+
+    **Parameters:**
+
+    training_data : [object] or [[object]]
+      A list of *preprocessed* data that can be used for training the extractor.
+      Data will be provided in a single list, if ``split_training_features_by_client = False`` was specified in the constructor,
+      otherwise the data will be split into lists, each of which contains the data of a single (training-)client.
+
+    extractor_file : str
+      The file to write.
+      This file should be readable with the :py:meth:`load` function.
+    """
+    self.length = 100000 
+    for i in range(len(training_data)):
+      if training_data[i].shape[0] < self.length:
+        self.length = training_data[i].shape[0]
+    logger.info("Signals will be truncated to {} dimensions".format(self.length))
diff --git a/bob/pad/face/extractor/__init__.py b/bob/pad/face/extractor/__init__.py
index 9ff0c47a7ae57c69b784a9511d19212f6c65d80f..1cbc4e4a45b17442bf173657a0e85c7224d76fd9 100644
--- a/bob/pad/face/extractor/__init__.py
+++ b/bob/pad/face/extractor/__init__.py
@@ -7,6 +7,8 @@ from .FrameDiffFeatures import FrameDiffFeatures
 
 from .FrequencySpectrum import FrequencySpectrum
 from .FreqFeatures import FreqFeatures
+from .NormalizeLength import NormalizeLength
+from .FFTFeatures import FFTFeatures 
 
 def __appropriate__(*args):
     """Says object was actually declared here, and not in the import module.