class SPCore::Signal

Store signal data and provide some useful methods for working with (testing and analyzing) the data.

@author James Tunnell

Constants

ARG_SPECS

Used to process hashed arguments in initialize.

Attributes

data[R]
sample_rate[R]

Public Class Methods

new(hashed_args) click to toggle source

A new instance of Signal.

@param [Hash] hashed_args Hashed arguments. Required keys are :data and

:sample_rate. See ARG_SPECS for more details.
# File lib/spcore/util/signal.rb, line 22
def initialize hashed_args
  hash_make hashed_args, Signal::ARG_SPECS
end

Public Instance Methods

*(other)
Alias for: multiply
+(other)
Alias for: add
-(other)
Alias for: subtract
/(other)
Alias for: divide
[](arg) click to toggle source

Access signal data.

# File lib/spcore/util/signal.rb, line 57
def [](arg)
  @data[arg]
end
abs() click to toggle source

Operate on copy of the Signal object with the absolute value function.

# File lib/spcore/util/signal.rb, line 353
def abs
  self.clone.abs!
end
abs!() click to toggle source

Operate on the signal data (in place) with the absolute value function.

# File lib/spcore/util/signal.rb, line 347
def abs!
  @data = @data.map {|x| x.abs }
  return self
end
add(other) click to toggle source

Add value, values in array, or values in other signal to the current data values, and return a new Signal object with the results. @param other Can be Numeric (add same value to all data values), Array, or Signal.

# File lib/spcore/util/signal.rb, line 439
def add(other)
  clone.add! other
end
Also aliased as: +
add!(other) click to toggle source

Add value, values in array, or values in other signal to the current data values, and update the current data with the results. @param other Can be Numeric (add same value to all data values), Array, or Signal.

# File lib/spcore/util/signal.rb, line 415
def add!(other)
  if other.is_a?(Numeric)
    @data.each_index do |i|
      @data[i] += other
    end
  elsif other.is_a?(Signal)
    raise ArgumentError, "other.data.size #{other.size} is not equal to data.size #{@data.size}" if other.data.size != @data.size
    @data.each_index do |i|
      @data[i] += other.data[i]
    end
  elsif other.is_a?(Array)
    raise ArgumentError, "other.size #{other.size} is not equal to data.size #{@data.size}" if other.size != @data.size
    @data.each_index do |i|
      @data[i] += other[i]
    end
  else
    raise ArgumentError, "other is not a Numeric, Signal, or Array"
  end
  return self
end
append(other) click to toggle source

Add data in array or other signal to the end of current data.

# File lib/spcore/util/signal.rb, line 408
def append other
  clone.append! other
end
append!(other) click to toggle source

Add data in array or other signal to the end of current data.

# File lib/spcore/util/signal.rb, line 398
def append! other
  if other.is_a?(Array)
    @data = @data.concat other
  elsif other.is_a?(Signal)
    @data = @data.concat other.data
  end
  return self
end
bandpass(left_cutoff, right_cutoff, order) click to toggle source

Run a discrete bandpass filter over the signal data (using DualSincFilter). Return result in a new Signal object.

# File lib/spcore/util/signal.rb, line 123
def bandpass left_cutoff, right_cutoff, order
  self.clone.bandpass! left_cutoff, right_cutoff, order
end
bandpass!(left_cutoff, right_cutoff, order) click to toggle source

Run a discrete bandpass filter over the signal data (using DualSincFilter). Modifies current object.

# File lib/spcore/util/signal.rb, line 110
def bandpass! left_cutoff, right_cutoff, order
  filter = DualSincFilter.new(
    :sample_rate => @sample_rate,
    :order => order,
    :left_cutoff_freq => left_cutoff,
    :right_cutoff_freq => right_cutoff
  )
  @data = filter.bandpass(@data)
  return self
end
bandstop(left_cutoff, right_cutoff, order) click to toggle source

Run a discrete bandstop filter over the signal data (using DualSincFilter). Return result in a new Signal object.

# File lib/spcore/util/signal.rb, line 142
def bandstop left_cutoff, right_cutoff, order
  self.clone.bandstop! left_cutoff, right_cutoff, order
end
bandstop!(left_cutoff, right_cutoff, order) click to toggle source

Run a discrete bandstop filter over the signal data (using DualSincFilter). Modifies current object.

# File lib/spcore/util/signal.rb, line 129
def bandstop! left_cutoff, right_cutoff, order
  filter = DualSincFilter.new(
    :sample_rate => @sample_rate,
    :order => order,
    :left_cutoff_freq => left_cutoff,
    :right_cutoff_freq => right_cutoff
  )
  @data = filter.bandstop(@data)
  return self
end
clone() click to toggle source

Produce a new Signal object with the same data.

# File lib/spcore/util/signal.rb, line 27
def clone
  new = Signal.new(:data => @data.clone, :sample_rate => @sample_rate)
  new.instance_variable_set(:@frequency_domain, @frequency_domain)
  return new
end
correlation(feature, zero_padding = 0) click to toggle source

Apply Statistics.correlation to the signal data (as the image).

# File lib/spcore/util/signal.rb, line 312
def correlation feature, zero_padding = 0
  Statistics.correlation @data, feature, zero_padding
end
count() click to toggle source

Size of the signal data.

# File lib/spcore/util/signal.rb, line 47
def count
  @data.size
end
derivative() click to toggle source

Applies Calculus.derivative on the signal data, and returns a new Signal object with the result.

# File lib/spcore/util/signal.rb, line 547
def derivative
  return Signal.new(:sample_rate => @sample_rate, :data => Calculus.derivative(@data))
end
divide(other) click to toggle source

Divide value, values in array, or values in other signal into the current data values, and return a new Signal object with the results. @param other Can be Numeric (divide same all data values by the same value),

Array, or Signal.
# File lib/spcore/util/signal.rb, line 536
def divide(other)
  clone.divide! other
end
Also aliased as: /
divide!(other) click to toggle source

Divide value, values in array, or values in other signal into the current data values, and update the current data with the results. @param other Can be Numeric (divide same all data values by the same value),

Array, or Signal.
# File lib/spcore/util/signal.rb, line 511
def divide!(other)
  if other.is_a?(Numeric)
    @data.each_index do |i|
      @data[i] /= other
    end
  elsif other.is_a?(Signal)
    raise ArgumentError, "other.data.size #{other.size} is not equal to data.size #{@data.size}" if other.data.size != @data.size
    @data.each_index do |i|
      @data[i] /= other.data[i]
    end
  elsif other.is_a?(Array)
    raise ArgumentError, "other.size #{other.size} is not equal to data.size #{@data.size}" if other.size != @data.size
    @data.each_index do |i|
      @data[i] /= other[i]
    end
  else
    raise ArgumentError, "other is not a Numeric, Signal, or Array"
  end
  return self
end
downsample_discrete(downsample_factor, filter_order) click to toggle source

Decrease the sample rate of signal data by the given factor using discrete downsampling method. Return result in a new Signal object. @param [Fixnum] downsample_factor Decrease the sample rate by this factor. @param [Fixnum] filter_order The filter order for the discrete lowpass filter.

# File lib/spcore/util/signal.rb, line 178
def downsample_discrete downsample_factor, filter_order
  return self.clone.downsample_discrete!(downsample_factor, filter_order)
end
downsample_discrete!(downsample_factor, filter_order) click to toggle source

Decrease the sample rate of signal data by the given factor using discrete downsampling method. Modifies current object. @param [Fixnum] downsample_factor Decrease the sample rate by this factor. @param [Fixnum] filter_order The filter order for the discrete lowpass filter.

# File lib/spcore/util/signal.rb, line 168
def downsample_discrete! downsample_factor, filter_order
  @data = DiscreteResampling.downsample @data, @sample_rate, downsample_factor, filter_order
  @sample_rate /= downsample_factor
  return self
end
duration() click to toggle source

Signal duration in seconds.

# File lib/spcore/util/signal.rb, line 52
def duration
  return @data.size.to_f / @sample_rate
end
energy() click to toggle source

Calculate the energy in current signal data.

# File lib/spcore/util/signal.rb, line 291
def energy
  return @data.inject(0.0){|sum,x| sum + (x * x)}
end
envelope(as_signal = true) click to toggle source

Apply Features.envelope to the signal data, and return either a new Signal object or the raw envelope data. @param [True/False] as_signal If true, return envelope data in a new signal

object. Otherwise, return raw envelope data.
Set to true by default.
# File lib/spcore/util/signal.rb, line 372
def envelope as_signal = true
  env_data = Features.envelope @data
  
  if as_signal
    return Signal.new(:sample_rate => @sample_rate, :data => env_data)
  else
    return env_data
  end
end
extrema() click to toggle source

Apply Features.extrema to the signal data.

# File lib/spcore/util/signal.rb, line 317
def extrema
  return Features.extrema(@data)
end
fft_full() click to toggle source

Return the full output of forward FFT on the signal data.

# File lib/spcore/util/signal.rb, line 252
def fft_full
  frequency_domain.fft_full
end
fft_half() click to toggle source

Return the first half of the the forward FFT on the signal data.

# File lib/spcore/util/signal.rb, line 257
def fft_half
  frequency_domain.fft_half
end
freq_magnitudes() click to toggle source

Run FFT on signal data to find magnitude of frequency components. @return [Hash] contains frequencies mapped to magnitudes.

# File lib/spcore/util/signal.rb, line 263
def freq_magnitudes
  freq_magnitudes = {}
  
  fft_half.each_index do |i|
    freq = frequency_domain.idx_to_freq(i)
    freq_magnitudes[freq] = fft_half[i]
  end
  
  return freq_magnitudes
end
freq_peaks() click to toggle source

Apply FrequencyDomain.peaks to the signal and return the result.

# File lib/spcore/util/signal.rb, line 275
def freq_peaks
  return frequency_domain.peaks
end
frequency_domain(fft_format = FrequencyDomain::FFT_MAGNITUDE_DECIBEL) click to toggle source
# File lib/spcore/util/signal.rb, line 240
def frequency_domain fft_format = FrequencyDomain::FFT_MAGNITUDE_DECIBEL
  if @frequency_domain.nil?
    @frequency_domain = FrequencyDomain.new(
      :time_data => @data,
      :sample_rate => @sample_rate,
      :fft_format => fft_format
    )
  end
  return @frequency_domain
end
fundamental(opts) click to toggle source

Return the lowest frequency of the signal harmonic series.

# File lib/spcore/util/signal.rb, line 286
def fundamental opts
  return harmonic_series(opts).min
end
harmonic_series(opts = {}) click to toggle source

Apply FrequencyDomain.harmonic_series to the signal frequency peaks and return the result.

# File lib/spcore/util/signal.rb, line 281
def harmonic_series opts = {}
  return frequency_domain.harmonic_series(opts)
end
highpass(cutoff_freq, order) click to toggle source

Run a discrete highpass filter over the signal data (using SincFilter). Return result in a new Signal object.

# File lib/spcore/util/signal.rb, line 104
def highpass cutoff_freq, order
  self.clone.highpass! cutoff_freq, order
end
highpass!(cutoff_freq, order) click to toggle source

Run a discrete highpass filter over the signal data (using SincFilter). Modifies current object.

# File lib/spcore/util/signal.rb, line 96
def highpass! cutoff_freq, order
  filter = SincFilter.new(:sample_rate => @sample_rate, :order => order, :cutoff_freq => cutoff_freq)
  @data = filter.highpass(@data)
  return self
end
integral() click to toggle source

Applies Calculus.integral on the signal data, and returns a new Signal object with the result.

# File lib/spcore/util/signal.rb, line 553
def integral
  return Signal.new(:sample_rate => @sample_rate, :data => Calculus.integral(@data))
end
keep_frequencies(freq_range) click to toggle source

Removes all but the given range of frequencies from the signal, using frequency domain filtering. Modifes a clone of the current object, returning the clone.

# File lib/spcore/util/signal.rb, line 579
def keep_frequencies freq_range
  return self.clone.keep_frequencies!(freq_range)
end
keep_frequencies!(freq_range) click to toggle source

Removes all but the given range of frequencies from the signal, using frequency domain filtering. Modifes and returns the current object.

# File lib/spcore/util/signal.rb, line 572
def keep_frequencies! freq_range
  modify_freq_content freq_range, :keep
end
lowpass(cutoff_freq, order) click to toggle source

Run a discrete lowpass filter over the signal data (using SincFilter). Return result in a new Signal object.

# File lib/spcore/util/signal.rb, line 90
def lowpass cutoff_freq, order
  self.clone.lowpass! cutoff_freq, order
end
lowpass!(cutoff_freq, order) click to toggle source

Run a discrete lowpass filter over the signal data (using SincFilter). Modifies current object.

# File lib/spcore/util/signal.rb, line 82
def lowpass! cutoff_freq, order
  filter = SincFilter.new(:sample_rate => @sample_rate, :order => order, :cutoff_freq => cutoff_freq)
  @data = filter.lowpass(@data)
  return self
end
maxima() click to toggle source

Apply Features.maxima to the signal data.

# File lib/spcore/util/signal.rb, line 337
def maxima
  return Features.maxima(@data)
end
mean() click to toggle source

Apply Statistics.mean to the signal data.

# File lib/spcore/util/signal.rb, line 302
def mean
  Statistics.mean @data
end
minima() click to toggle source

Apply Features.minima to the signal data.

# File lib/spcore/util/signal.rb, line 327
def minima
  return Features.minima(@data)
end
multiply(other) click to toggle source

Multiply value, values in array, or values in other signal with the current data values, and return a new Signal object with the results. @param other Can be Numeric (multiply all data values by the same value),

Array, or Signal.
# File lib/spcore/util/signal.rb, line 503
def multiply(other)
  clone.multiply! other
end
Also aliased as: *
multiply!(other) click to toggle source

Multiply value, values in array, or values in other signal with the current data values, and update the current data with the results. @param other Can be Numeric (multiply all data values by the same value),

Array, or Signal.
# File lib/spcore/util/signal.rb, line 478
def multiply!(other)
  if other.is_a?(Numeric)
    @data.each_index do |i|
      @data[i] *= other
    end
  elsif other.is_a?(Signal)
    raise ArgumentError, "other.data.size #{other.size} is not equal to data.size #{@data.size}" if other.data.size != @data.size
    @data.each_index do |i|
      @data[i] *= other.data[i]
    end
  elsif other.is_a?(Array)
    raise ArgumentError, "other.size #{other.size} is not equal to data.size #{@data.size}" if other.size != @data.size
    @data.each_index do |i|
      @data[i] *= other[i]
    end
  else
    raise ArgumentError, "other is not a Numeric, Signal, or Array"
  end
  return self
end
negative_minima() click to toggle source

Apply Features.negative_minima to the signal data.

# File lib/spcore/util/signal.rb, line 332
def negative_minima
  return Features.negative_minima(@data)
end
normalize(level = 1.0) click to toggle source

reduce all samples to the given level

# File lib/spcore/util/signal.rb, line 363
def normalize level = 1.0
  self.clone.normalize! level
end
normalize!(level = 1.0) click to toggle source

reduce all samples to the given level

# File lib/spcore/util/signal.rb, line 358
def normalize! level = 1.0
  self.divide!(@data.max / level)
end
outer_extrema() click to toggle source

Apply Features.outer_extrema to the signal data.

# File lib/spcore/util/signal.rb, line 322
def outer_extrema
  return Features.outer_extrema(@data)
end
plot_1d() click to toggle source

Plot the signal data against sample numbers.

# File lib/spcore/util/signal.rb, line 62
def plot_1d
  plotter = Plotter.new(:title => "Signal: values vs. sample number", :xtitle => "sample number", :ytitle => "sample value")
  plotter.plot_1d "signal data" => @data
end
plot_2d() click to toggle source

Plot the signal data against time.

# File lib/spcore/util/signal.rb, line 68
def plot_2d
  plotter = Plotter.new(:title => "Signal: values vs. time", :xtitle => "time (sec)", :ytitle => "sample value")
  
  data_vs_time = {}
  sp = 1.0 / @sample_rate
  @data.each_index do |i|
    data_vs_time[i * sp] = @data[i]
  end
    
  plotter.plot_2d "signal data" => data_vs_time
end
positive_maxima() click to toggle source

Apply Features.positive_maxima to the signal data.

# File lib/spcore/util/signal.rb, line 342
def positive_maxima
  return Features.positive_maxima(@data)
end
prepend(other) click to toggle source

Add data in array or other signal to the beginning of current data.

# File lib/spcore/util/signal.rb, line 393
def prepend other
  clone.prepend! other
end
prepend!(other) click to toggle source

Add data in array or other signal to the beginning of current data.

# File lib/spcore/util/signal.rb, line 383
def prepend! other
  if other.is_a?(Array)
    @data = other.concat @data
  elsif other.is_a?(Signal)
    @data = other.data.concat @data  
  end
  return self
end
remove_frequencies(freq_range) click to toggle source

Removes the given range of frequencies from the signal, using frequency domain filtering. Modifes a clone of the current object, returning the clone.

# File lib/spcore/util/signal.rb, line 566
def remove_frequencies freq_range
  return self.clone.remove_frequencies!(freq_range)
end
remove_frequencies!(freq_range) click to toggle source

Removes all but the given range of frequencies from the signal, using frequency domain filtering. Modifes and returns the current object.

# File lib/spcore/util/signal.rb, line 559
def remove_frequencies! freq_range
  modify_freq_content freq_range, :remove
end
resample_discrete(upsample_factor, downsample_factor, filter_order) click to toggle source

Change the sample rate of signal data by the given up/down factors, using discrete upsampling and downsampling methods. Return result in a new Signal object. @param [Fixnum] upsample_factor Increase the sample rate by this factor. @param [Fixnum] downsample_factor Decrease the sample rate by this factor. @param [Fixnum] filter_order The filter order for the discrete lowpass filter.

# File lib/spcore/util/signal.rb, line 199
def resample_discrete upsample_factor, downsample_factor, filter_order
  return self.clone.resample_discrete!(upsample_factor, downsample_factor, filter_order)
end
resample_discrete!(upsample_factor, downsample_factor, filter_order) click to toggle source

Change the sample rate of signal data by the given up/down factors, using discrete upsampling and downsampling methods. Modifies current object. @param [Fixnum] upsample_factor Increase the sample rate by this factor. @param [Fixnum] downsample_factor Decrease the sample rate by this factor. @param [Fixnum] filter_order The filter order for the discrete lowpass filter.

# File lib/spcore/util/signal.rb, line 187
def resample_discrete! upsample_factor, downsample_factor, filter_order
  @data = DiscreteResampling.resample @data, @sample_rate, upsample_factor, downsample_factor, filter_order
  @sample_rate *= upsample_factor
  @sample_rate /= downsample_factor
  return self
end
resample_hybrid(upsample_factor, downsample_factor, filter_order) click to toggle source

Change the sample rate of signal data by the given up/down factors, using polynomial upsampling and discrete downsampling. Return result as a new Signal object. @param [Fixnum] upsample_factor Increase the sample rate by this factor. @param [Fixnum] downsample_factor Decrease the sample rate by this factor. @param [Fixnum] filter_order The filter order for the discrete lowpass filter.

# File lib/spcore/util/signal.rb, line 236
def resample_hybrid upsample_factor, downsample_factor, filter_order
  return self.clone.resample_hybrid!(upsample_factor, downsample_factor, filter_order)
end
resample_hybrid!(upsample_factor, downsample_factor, filter_order) click to toggle source

Change the sample rate of signal data by the given up/down factors, using polynomial upsampling and discrete downsampling. Modifies current Signal object. @param [Fixnum] upsample_factor Increase the sample rate by this factor. @param [Fixnum] downsample_factor Decrease the sample rate by this factor. @param [Fixnum] filter_order The filter order for the discrete lowpass filter.

# File lib/spcore/util/signal.rb, line 224
def resample_hybrid! upsample_factor, downsample_factor, filter_order
  @data = HybridResampling.resample @data, @sample_rate, upsample_factor, downsample_factor, filter_order
  @sample_rate *= upsample_factor
  @sample_rate /= downsample_factor
  return self
end
rms() click to toggle source

Calculate signal RMS (root-mean square), also known as quadratic mean, a statistical measure of the magnitude.

# File lib/spcore/util/signal.rb, line 297
def rms
  Math.sqrt(energy / size)
end
size() click to toggle source

Size of the signal data.

# File lib/spcore/util/signal.rb, line 42
def size
  @data.size
end
std_dev() click to toggle source

Apply Statistics.std_dev to the signal data.

# File lib/spcore/util/signal.rb, line 307
def std_dev
  Statistics.std_dev @data
end
subset(range) click to toggle source

Produce a new Signal object with a subset of the current signal data. @param [Range] range Used to pick the data range.

# File lib/spcore/util/signal.rb, line 35
def subset range
  new = Signal.new(:data => @data[range], :sample_rate => @sample_rate)
  new.instance_variable_set(:@frequency_domain, @frequency_domain)
  return new
end
subtract(other) click to toggle source

Subtract value, values in array, or values in other signal from the current data values, and return a new Signal object with the results. @param other Can be Numeric (subtract same value from all data values), Array, or Signal.

# File lib/spcore/util/signal.rb, line 470
def subtract(other)
  clone.subtract! other
end
Also aliased as: -
subtract!(other) click to toggle source

Subtract value, values in array, or values in other signal from the current data values, and update the current data with the results. @param other Can be Numeric (subtract same value from all data values), Array, or Signal.

# File lib/spcore/util/signal.rb, line 446
def subtract!(other)
  if other.is_a?(Numeric)
    @data.each_index do |i|
      @data[i] -= other
    end
  elsif other.is_a?(Signal)
    raise ArgumentError, "other.data.size #{other.size} is not equal to data.size #{@data.size}" if other.data.size != @data.size
    @data.each_index do |i|
      @data[i] -= other.data[i]
    end
  elsif other.is_a?(Array)
    raise ArgumentError, "other.size #{other.size} is not equal to data.size #{@data.size}" if other.size != @data.size
    @data.each_index do |i|
      @data[i] -= other[i]
    end
  else
    raise ArgumentError, "other is not a Numeric, Signal, or Array"
  end
  return self
end
upsample_discrete(upsample_factor, filter_order) click to toggle source

Increase the sample rate of signal data by the given factor using discrete upsampling method. Return result in a new Signal object. @param [Fixnum] upsample_factor Increase the sample rate by this factor. @param [Fixnum] filter_order The filter order for the discrete lowpass filter.

# File lib/spcore/util/signal.rb, line 160
def upsample_discrete upsample_factor, filter_order
  return self.clone.upsample_discrete!(upsample_factor, filter_order)
end
upsample_discrete!(upsample_factor, filter_order) click to toggle source

Increase the sample rate of signal data by the given factor using discrete upsampling method. Modifies current object. @param [Fixnum] upsample_factor Increase the sample rate by this factor. @param [Fixnum] filter_order The filter order for the discrete lowpass filter.

# File lib/spcore/util/signal.rb, line 150
def upsample_discrete! upsample_factor, filter_order
  @data = DiscreteResampling.upsample @data, @sample_rate, upsample_factor, filter_order
  @sample_rate *= upsample_factor
  return self
end
upsample_polynomial(upsample_factor) click to toggle source

Increase the sample rate of signal data by the given factor using polynomial interpolation. Returns result as a new Signal object. @param [Fixnum] upsample_factor Increase the sample rate by this factor.

# File lib/spcore/util/signal.rb, line 215
def upsample_polynomial upsample_factor
  return self.clone.upsample_polynomial!(upsample_factor)
end
upsample_polynomial!(upsample_factor) click to toggle source

Increase the sample rate of signal data by the given factor using polynomial interpolation. Modifies current Signal object. @param [Fixnum] upsample_factor Increase the sample rate by this factor.

# File lib/spcore/util/signal.rb, line 206
def upsample_polynomial! upsample_factor
  @data = PolynomialResampling.upsample @data, upsample_factor
  @sample_rate *= upsample_factor
  return self
end

Private Instance Methods

modify_freq_content(freq_range, mod_type) click to toggle source
# File lib/spcore/util/signal.rb, line 585
def modify_freq_content freq_range, mod_type
  nyquist = @sample_rate / 2
  
  unless freq_range.min.between?(0, nyquist)
    raise ArgumentError, "freq_range.min #{freq_range.min} is not between 0 and #{nyquist}"
  end

  unless freq_range.max.between?(0, nyquist)
    raise ArgumentError, "freq_range.min #{freq_range.min} is not between 0 and #{nyquist}"
  end
  
  power_of_two = FFT.power_of_two?(size)
  if power_of_two
    freq_domain = FFT.forward @data
  else
    freq_domain = DFT.forward @data
  end
  
  # cutoff indices for real half
  a = ((freq_range.min * size) / @sample_rate).round
  b = ((freq_range.max * size) / @sample_rate).round
  
  window_size = b - a + 1
  window_data = RectangularWindow.new(window_size).data
      
  case mod_type
  when :keep
    new_freq_data = Array.new(size, Complex(0))
    
    window_size.times do |n|
      i = n + a
      new_freq_data[i] = freq_domain[i] * window_data[n]
    end

    window_size.times do |n|
      i = n + (size - 1 - b)
      new_freq_data[i] = freq_domain[i] * window_data[n]
    end
  when :remove
    new_freq_data = freq_domain.clone
    
    window_size.times do |n|
      i = n + a
      new_freq_data[i] = freq_domain[i] * (Complex(1.0) - window_data[n])
    end

    window_size.times do |n|
      i = n + (size - 1 - b)
      new_freq_data[i] = freq_domain[i] * (Complex(1.0) - window_data[n])
    end
  else
    raise ArgumentError, "unkown mod_type #{mod_type}"
  end
  
  if power_of_two
    data = FFT.inverse new_freq_data
  else
    data = DFT.inverse new_freq_data
  end
  
  @data = data.map {|complex| complex.real }
  return self
end