Repository: pyfar/pyfar (python)

Issue:
refactoring signal normalization
## Description

signal type and normalization might be hard to understand and should be simplified

## Suggestion

- distinguish only by normalization
- `None` will be a new normalization, which does exactly nothing
- The `signal_type` will be deleted
- The getter for the `signal_type` will get a deprecated warning

Pull request:
Refactor signal type and FFT norm handling
### Which issue(s) are closed by this pull request?

Closes #53 

### Changes proposed in this pull request:

- Use FFT norm to specify the signal type
- Deprecate the signal type properties



Patch:
diff --git a/examples/pyfar_demo.ipynb b/examples/pyfar_demo.ipynb
index 74825a3f..5b9925be 100644
--- a/examples/pyfar_demo.ipynb
+++ b/examples/pyfar_demo.ipynb
@@ -10,7 +10,6 @@
     "\n",
     "## Contents\n",
     "[Signals](#signals)\n",
-    "- [Signal types](#signal_types)\n",
     "- [FFT normalization](#fft_normalization)\n",
     "- [Accessing Signal data](#accessing_signal_data)\n",
     "- [Iterating Signals](#accessing_signal_data)\n",
@@ -30,7 +29,6 @@
     "[Plotting](#plotting)\n",
     "- [Line plots](#line_plots)\n",
     "- [Plane plots](#plane_plots) TODO\n",
-    "- [Balloon plots](#plane_plots) TODO\n",
     "\n",
     "[DSP](#dsp)\n",
     "- [Filtering](#filtering)\n",
@@ -82,36 +80,17 @@
     "fs = 44100\n",
     "x = np.zeros(44100)\n",
     "x[0] = 1\n",
-    "x_energy = Signal(x, fs, signal_type='energy')\n",
+    "x_energy = Signal(x, fs)\n",
     "\n",
     "# show information\n",
     "x_energy"
    ]
   },
-  {
-   "source": [
-    "## Signal types<a class=\"anchor\" id=\"signal_types\"></a>\n",
-    "\n",
-    "There are two different *signal types*: `'energy'` and `'power'`. Energy signals are finite signals with a finite energy. The most common example for an energy signal is an impulse response. Power signals are finite sections of infinte audio signals. They have infinite energy but finite power. Examples for power signals are environmental noise or sine tones. It is important to distinguish between the two and some functions have signal type specific behaviour. You will come acros this in the sections [FFT Normalization](#fft_normalization), [Arithmetic operations](#arithmetic_operations), and [Plotting](#plotting). Lets also create a power signal"
-   ],
-   "cell_type": "markdown",
-   "metadata": {}
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "x = np.sin(2 * np.pi * 1000 * np.arange(441) / fs)\n",
-    "x_power = Signal(x, fs, signal_type='power')"
-   ]
-  },
   {
    "source": [
     "## FFT Normalization<a class=\"anchor\" id=\"fft_normalization\"></a>\n",
     "\n",
-    "The spectral content of power signals can be expectd in different ways, referred to as FFT normalizations. Pyfar knows the four normalizations 'amplitude', 'rms', 'power', and 'psd' (cf. [Ahrens, et al. 2020](http://www.aes.org/e-lib/browse.cfm?elib=20838)). In addition the normalization 'unitary' only applies the weighting for the single sided spectrum (Eq. 8 in Ahrens et al. 2020). Let's check out the default for 'power' Signals"
+    "The spectral content of signals can be inspected in different ways, referred to as FFT normalizations. Pyfar knows the four normalizations `'amplitude'`, `'rms'`, `'power'`, and `'psd'` (cf. [Ahrens, et al. 2020](http://www.aes.org/e-lib/browse.cfm?elib=20838)). Two additional normalizations are available. `'unitary'` only applies the weighting for the single sided spectrum (Eq. 8 in Ahrens et al. 2020). `'none'` applies no normalization, which is usefull for signals with finite energy such as impulse responses. The default normalization is `'none'`. Let's create a signal with a different normalization"
    ],
    "cell_type": "markdown",
    "metadata": {}
@@ -122,12 +101,13 @@
    "metadata": {},
    "outputs": [],
    "source": [
-    "x_power.fft_norm"
+    "x = np.sin(2 * np.pi * 1000 * np.arange(441) / fs)\n",
+    "x_power = Signal(x, fs, fft_norm='rms')"
    ]
   },
   {
    "source": [
-    "The normalization can be changed in the way. In this case the spectral data of the signal is converted internally using `pyfar.fft.normalization()`"
+    "The normalization can be changed. In this case the spectral data of the signal is converted internally using `pyfar.fft.normalization()`"
    ],
    "cell_type": "markdown",
    "metadata": {}
@@ -142,22 +122,6 @@
     "x_power.fft_norm"
    ]
   },
-  {
-   "source": [
-    "Energy Signals can only have the FFT normalization 'unitary'. In this case no normalization is applied, not even Eq. (8) in Ahrens et al. (2020)."
-   ],
-   "cell_type": "markdown",
-   "metadata": {}
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "x_energy.fft_norm"
-   ]
-  },
   {
    "source": [
     "## Accessing Signal data<a class=\"accessing_signal_data\" id=\"signals\"></a>\n",
@@ -179,7 +143,7 @@
   },
   {
    "source": [
-    "Please note that the frequency data of `'power'` signals depends on the Signal's `fft_norm`. Internally, the data are stored either in the `'time'` or `'freq'` domain. It is tranformed every time you access it without changing the internal state. In some cases it might be more efficient to store the data in a specif domain to avoid additional Fourier Transforms. Lets check out the current domain"
+    "Please note that the frequency data of signals depends on the Signal's `fft_norm`. Internally, the data are stored either in the `'time'` or `'freq'` domain. It is tranformed every time you access it without changing the internal state. In some cases it might be more efficient to store the data in a specif domain to avoid additional Fourier Transforms. Lets check out the current domain"
    ],
    "cell_type": "markdown",
    "metadata": {}
@@ -389,10 +353,6 @@
     "## Plane plots<a class=\"anchor\" id=\"plane_plots\"></a> [TODO]\n",
     "\n",
     "\n",
-    "**808 - Found but not ready yet**\n",
-    "\n",
-    "## Balloon plots<a class=\"anchor\" id=\"balloon_plots\"></a> [TODO]\n",
-    "\n",
     "**808 - Found but not ready yet**\n"
    ],
    "cell_type": "markdown",
@@ -690,7 +650,8 @@
  "metadata": {
   "kernelspec": {
    "name": "python3",
-   "display_name": "Python 3"
+   "display_name": "Python 3",
+   "language": "python"
   },
   "language_info": {
    "codemirror_mode": {
diff --git a/pyfar/fft.py b/pyfar/fft.py
index 45efb548..46c01f99 100644
--- a/pyfar/fft.py
+++ b/pyfar/fft.py
@@ -126,7 +126,7 @@ def rfftfreq(n_samples, sampling_rate):
     return fft_lib.rfftfreq(n_samples, d=1/sampling_rate)
 
 
-def rfft(data, n_samples, sampling_rate, signal_type, fft_norm):
+def rfft(data, n_samples, sampling_rate, fft_norm):
     """
     Calculate the FFT of a real-valued time-signal. The function returns only
     the right-hand side of the axis-symmetric spectrum. The normalization
@@ -146,8 +146,6 @@ def rfft(data, n_samples, sampling_rate, signal_type, fft_norm):
         The number of samples
     sampling_rate : number
         sampling rate in Hz
-    signal_type : 'energy', 'power'
-        see pyfar.Signal for more information
     fft_norm : 'unitary', 'amplitude', 'rms', 'power', 'psd'
         See documentaion of pyfar.fft.normalization.
 
@@ -162,13 +160,13 @@ def rfft(data, n_samples, sampling_rate, signal_type, fft_norm):
     # DFT
     spec = fft_lib.rfft(data, n=n_samples, axis=-1)
     # Normalization
-    spec = normalization(spec, n_samples, sampling_rate, signal_type, fft_norm,
+    spec = normalization(spec, n_samples, sampling_rate, fft_norm,
                          inverse=False, single_sided=True)
 
     return spec
 
 
-def irfft(spec, n_samples, sampling_rate, signal_type, fft_norm):
+def irfft(spec, n_samples, sampling_rate, fft_norm):
     """
     Calculate the IFFT of a axis-symmetric Fourier spectum. The function
     takes only the right-hand side of the spectrum and returns a real-valued
@@ -190,8 +188,6 @@ def irfft(spec, n_samples, sampling_rate, signal_type, fft_norm):
         of samples.
     sampling_rate : number
         sampling rate in Hz
-    signal_type : 'energy', 'power'
-        see pyfar.Signal for more information
     fft_norm : 'unitary', 'amplitude', 'rms', 'power', 'psd'
         See documentaion of pyfar.fft.normalization.
 
@@ -203,7 +199,7 @@ def irfft(spec, n_samples, sampling_rate, signal_type, fft_norm):
     """
 
     # Inverse normalization
-    spec = normalization(spec, n_samples, sampling_rate, signal_type, fft_norm,
+    spec = normalization(spec, n_samples, sampling_rate, fft_norm,
                          inverse=True, single_sided=True)
     # Inverse DFT
     data = fft_lib.irfft(spec, n=n_samples, axis=-1)
@@ -211,8 +207,8 @@ def irfft(spec, n_samples, sampling_rate, signal_type, fft_norm):
     return data
 
 
-def normalization(spec, n_samples, sampling_rate, signal_type,
-                  fft_norm="unitary", inverse=False, single_sided=True):
+def normalization(spec, n_samples, sampling_rate, fft_norm='none',
+                  inverse=False, single_sided=True, window=None):
     """
     Normalize spectrum of power signal.
 
@@ -232,12 +228,10 @@ def normalization(spec, n_samples, sampling_rate, signal_type,
         number of samples of the corresponding time signal
     sampling_rate : number
         sampling rate of the corresponding time signal in Hz
-    signal_type : 'energy', 'power'
-        Normalization is only applied if signal_type == 'power'. See
-        pyfar.Signal for more information
     fft_norm : string, optional
-        'unitary' - Multiplied single sided spectra by factor two for power
-                    signals. Do nothing for energy signals.
+        'none' - Do not apply any normalization
+        'unitary' - Multiplied single sided spectra by factor two
+                    (except for 0 Hz and half the sampling rate)
         'amplitude' - as in _[2] Eq. (4)
         'rms' - as in _[2] Eq. (10)
         'power' - as in _[2] Eq. (5)
@@ -249,6 +243,11 @@ def normalization(spec, n_samples, sampling_rate, signal_type,
         rate or a both sided (full) spectrum. If `single_sided==True` the
         normalization according to _[2] Eq. (8) is applied for power signals.
         The default is True.
+    window : None, array like
+        window that was applied to the time signal before performing the FFT.
+        window must be an array like with `n_samples` and affects the
+        normalization as in _[2] Eqs. (11-13). The default is None, which
+        denotes that no window was applied.
 
     Returns
     -------
@@ -263,44 +262,62 @@ def normalization(spec, n_samples, sampling_rate, signal_type,
            May 2020, p. e-Brief 600.
     """
 
+    # check if normalization should be applied
+    if fft_norm == 'none':
+        return spec
+
     # check input
     if not isinstance(spec, np.ndarray):
         raise ValueError("Input 'spec' must be a numpy array.")
-    if signal_type not in ['energy', 'power']:
-        raise ValueError(("signal_type must be 'energy' or 'power' "
-                          f"but is '{signal_type}'"))
-
-    # nothing to do for energy signals
-    if signal_type == 'energy':
-        return spec
+    if window is not None:
+        if len(window) != n_samples:
+            raise ValueError((f"window must be {n_samples} long "
+                              f"but is {len(window)} long."))
 
     n_bins = spec.shape[-1]
     norm = np.ones(n_bins)
 
     # account for type of normalization
     if fft_norm == "amplitude":
-        # Equation 4 in Ahrens et al. 2020
-        norm /= n_samples
+        if window is None:
+            # Equation 4 in Ahrens et al. 2020
+            norm /= n_samples
+        else:
+            # Equation 11 in Ahrens et al. 2020
+            norm /= np.sum(window)
     elif fft_norm == 'rms':
-        # Equation 10 in Ahrens et al. 2020
         if not single_sided:
             raise ValueError(
                 "'rms' normalization does only exist for single-sided spectra")
-        norm /= n_samples
+        if window is None:
+            # Equation 10 in Ahrens et al. 2020
+            norm /= n_samples
+        else:
+            # Equation 11 in Ahrens et al. 2020
+            norm /= np.sum(window)
         if _is_odd(n_samples):
             norm[1:] /= np.sqrt(2)
         else:
             norm[1:-1] /= np.sqrt(2)
     elif fft_norm == 'power':
-        # Equation 5 in Ahrens et al. 2020
-        norm /= n_samples**2
+        if window is None:
+            # Equation 5 in Ahrens et al. 2020
+            norm /= n_samples**2
+        else:
+            # Equation 12 in Ahrens et al. 2020
+            norm /= np.sum(window)**2
         # the phase is kept for being able to switch between normalizations
         # altoug the power spectrum does usually not have phase information,
         # i.e., spec = np.abs(spec)**2
         if not inverse:
             spec *= np.abs(spec)
     elif fft_norm == 'psd':
-        norm /= (n_samples * sampling_rate)
+        if window is None:
+            # Equation 6 in Ahrens et al. 2020
+            norm /= (n_samples * sampling_rate)
+        else:
+            # Equation 13 in Ahrens et al. 2020
+            norm /= (np.sum(window)**2 * sampling_rate)
         # the phase is kept for being able to switch between normalizations
         # altoug the power spectrum does usually not have phase information,
         # i.e., spec = np.abs(spec)**2
diff --git a/pyfar/signal.py b/pyfar/signal.py
index 63a49cd2..d7b6283c 100644
--- a/pyfar/signal.py
+++ b/pyfar/signal.py
@@ -29,30 +29,6 @@ class Signal(Audio):
     time and frequency domain. Equally spaced samples or frequency bins,
     respectively.
 
-    Attributes
-    ----------
-    data : ndarray, double
-        Raw data of the signal in the frequency or time domain
-    sampling_rate : double
-        Sampling rate in Hertz
-    n_samples : int, optional
-        Number of samples of the time signal. Required if domain is 'freq'. The
-        default is None.
-    domain : 'time', 'freq', optional
-        Domain of data. The default is 'time'
-    signal_type : 'energy', 'power', optional
-        Energy signals are finite and have finite energy. An example for an
-        energy signal is an impulse response. Power signals are infinite and
-        have infinite energy. Examples are noise and sine signals. The default
-        is 'energy'
-    fft_norm : 'unitary', 'amplitude', 'rms', 'power', 'psd', optional
-        The kind of Discrete Fourier Transform (DFT) normalization. See
-        pyfar.fft.normalization for more information. The normalization is
-        only applied to power signals. The default is 'unitary' for energy
-        signals and 'rms' for power signals.
-    dtype : string, optional
-        Raw data type of the signal. The default is float64
-
     """
     def __init__(
             self,
@@ -60,7 +36,6 @@ class Signal(Audio):
             sampling_rate,
             n_samples=None,
             domain='time',
-            signal_type='energy',
             fft_norm=None,
             dtype=np.double,
             comment=None):
@@ -77,19 +52,21 @@ class Signal(Audio):
             The default is None.
         domain : 'time', 'freq', optional
             Domain of data. The default is 'time'
-        signal_type : 'energy', 'power', optional
-            Energy signals are finite and have finite energy. An example for an
-            energy signal is an impulse response. Power signals are infinite
-            and have infinite energy. Examples are noise and sine signals. The
-            default is 'energy'
-        fft_norm : 'unitary', 'amplitude', 'rms', 'power', 'psd', optional
+        fft_norm : 'none', 'unitary', 'amplitude', 'rms', 'power', 'psd'
             The kind of Discrete Fourier Transform (DFT) normalization. See
-            pyfar.fft.normalization for more information. The normalization is
-            only applied to power signals. The default is 'unitary' for energy
-            signals and 'rms' for power signals.
+            pyfar.fft.normalization and _[1] for more information. The
+            normalization is only applied to power signals. The default is
+            'none', which is typically used to energy signals, such as impulse
+            responses.
         dtype : string, optional
             Raw data type of the signal. The default is float64
 
+        References
+        ----------
+        .. [1] J. Ahrens, C. Andersson, P. Höstmad, and W. Kropp, “Tutorial on
+               Scaling of the Discrete Fourier Transform and the Implied
+               Physical Units of the Spectra of Time-Discrete Signals,” Vienna,
+               Austria, May 2020, p. e-Brief 600.
         """
 
         Audio.__init__(self)
@@ -97,10 +74,6 @@ class Signal(Audio):
         self._dtype = dtype
 
         self._VALID_SIGNAL_TYPE = ["power", "energy"]
-        if (signal_type in self._VALID_SIGNAL_TYPE) is True:
-            self._signal_type = signal_type
-        else:
-            raise ValueError("Not a valid signal type ('power'/'energy')")
 
         self._VALID_SIGNAL_DOMAIN = ["time", "freq"]
         if domain in self._VALID_SIGNAL_DOMAIN:
@@ -121,12 +94,12 @@ class Signal(Audio):
             self._n_samples = n_samples
             self._data = np.atleast_2d(np.asarray(data, dtype=np.complex))
 
-        self._VALID_FFT_NORMS = ["unitary", "amplitude", "rms", "power", "psd"]
+        self._VALID_FFT_NORMS = [
+            "none", "unitary", "amplitude", "rms", "power", "psd"]
         if fft_norm is None:
-            fft_norm = 'unitary' if signal_type == 'energy' else 'rms'
+            fft_norm = 'none'
         if fft_norm in self._VALID_FFT_NORMS:
             self._fft_norm = fft_norm
-            self.fft_norm = fft_norm
         else:
             raise ValueError(("Invalid FFT normalization. Has to be "
                               f"{', '.join(self._VALID_FFT_NORMS)}, but found "
@@ -151,13 +124,13 @@ class Signal(Audio):
                 # and need to do an inverse Fourier Transform
                 self.time = fft.irfft(
                     self._data, self.n_samples, self._sampling_rate,
-                    self._signal_type, self._fft_norm)
+                    self._fft_norm)
             elif new_domain == 'freq':
                 # If the new domain should be freq, we had sampled time data
                 # and need to do a Fourier Transform
                 self.freq = fft.rfft(
                     self._data, self.n_samples, self._sampling_rate,
-                    self._signal_type, self._fft_norm)
+                    self._fft_norm)
 
     @property
     def n_samples(self):
@@ -226,33 +199,18 @@ class Signal(Audio):
     @property
     def signal_type(self):
         """The signal type."""
-        return self._signal_type
+        if self.fft_norm == 'none':
+            stype = 'energy'
+        elif self.fft_norm in [
+                "unitary", "amplitude", "rms", "power", "psd"]:
+            stype = 'energy'
+        else:
+            raise ValueError("No valid fft norm set.")
+        return stype
 
     @signal_type.setter
     def signal_type(self, value):
-        # check if we do anything
-        if value == self._signal_type:
-            return
-
-        # check input
-        if value not in self._VALID_SIGNAL_TYPE:
-            raise ValueError("Not a valid signal type ('power'/'energy')")
-        if value == 'energy' and self._fft_norm != 'unitary':
-            raise ValueError(("Signal type can only be set to 'energy' if "
-                              "fft_norm is 'unitary'"))
-
-        # normalize or de-normalize spectrum
-        if self._domain == 'freq' and value == 'energy':
-            inverse = True
-        if self._domain == 'freq' and value == 'power':
-            inverse = False
-
-        self._data = fft.normalization(
-            self._data, self._n_samples, self._sampling_rate,
-            'power', self._fft_norm, inverse)
-
-        # set new signal type
-        self._signal_type = value
+        raise DeprecationWarning("Deprecated, use fft_norm instead.")
 
     @property
     def fft_norm(self):
@@ -275,20 +233,17 @@ class Signal(Audio):
             raise ValueError(("Invalid FFT normalization. Has to be "
                               f"{', '.join(self._VALID_FFT_NORMS)}, but found "
                               f"'{value}'"))
-        if self._signal_type == 'energy' and value != 'unitary':
-            raise ValueError(
-                "If signal_type is 'energy', fft_norm must be 'unitary'.")
 
         # apply new normalization if Signal is in frequency domain
         if self._fft_norm != value and self._domain == 'freq':
             # de-normalize
             self._data = fft.normalization(
                 self._data, self._n_samples, self._sampling_rate,
-                self._signal_type, self._fft_norm, inverse=True)
+                self._fft_norm, inverse=True)
             # normalize
             self._data = fft.normalization(
                 self._data, self._n_samples, self._sampling_rate,
-                self._signal_type, value, inverse=False)
+                value, inverse=False)
 
         self._fft_norm = value
 
@@ -365,7 +320,6 @@ class Signal(Audio):
             data,
             sampling_rate=self.sampling_rate,
             domain=self.domain,
-            signal_type=self.signal_type,
             fft_norm=self.fft_norm,
             dtype=self.dtype)
 
@@ -399,8 +353,8 @@ class Signal(Audio):
             raise ValueError("The sampling rates do not match.")
         if self.n_samples != other.n_samples:
             raise ValueError("The number of samples does not match.")
-        if self.signal_type != other.signal_type:
-            raise ValueError("The signal types do not match.")
+        if self.fft_norm != other.fft_norm:
+            raise ValueError("The FFT norms do not match.")
 
     def __iter__(self):
         """Iterator for signals. The actual iteration is handled through
@@ -420,7 +374,7 @@ class SignalIterator(object):
             sampling_rate=signal.sampling_rate,
             n_samples=signal.n_samples,
             domain=signal.domain,
-            signal_type=signal.signal_type,
+            fft_norm=signal.fft_norm,
             dtype=signal.dtype)
 
     def __next__(self):
@@ -453,9 +407,8 @@ def add(data: tuple, domain='freq'):
         Result of the operation as numpy array, if `data` contains only array
         likes and numbers. Result as Signal object if `data`contains a Signal.
         The `Signal.domain` is set by the input parameter `domain`. The
-        `Signal.signal_type` is 'energy' if `data` contains only energy
-        Signals and 'power' otherwise. The `Signal.fft_norm` is taken from the
-        first signal in `data`.
+        `Signal.fft_norm` is `None` if all FFT norms are None. Otherwise the
+        first FFT norm that is not None is taken.
 
     """
     return _arithmetic(data, domain, _add)
@@ -481,9 +434,8 @@ def subtract(data: tuple, domain='freq'):
         Result of the operation as numpy array, if `data` contains only array
         likes and numbers. Result as Signal object if `data`contains a Signal.
         The `Signal.domain` is set by the input parameter `domain`. The
-        `Signal.signal_type` is 'energy' if `data` contains only energy
-        Signals and 'power' otherwise. The `Signal.fft_norm` is taken from the
-        first signal in `data`.
+        `Signal.fft_norm` is `None` if all FFT norms are None. Otherwise the
+        first FFT norm that is not None is taken.
 
     """
     return _arithmetic(data, domain, _subtract)
@@ -509,9 +461,8 @@ def multiply(data: tuple, domain='freq'):
         Result of the operation as numpy array, if `data` contains only array
         likes and numbers. Result as Signal object if `data`contains a Signal.
         The `Signal.domain` is set by the input parameter `domain`. The
-        `Signal.signal_type` is 'energy' if `data` contains only energy
-        Signals and 'power' otherwise. The `Signal.fft_norm` is taken from the
-        first signal in `data`.
+        `Signal.fft_norm` is `None` if all FFT norms are None. Otherwise the
+        first FFT norm that is not None is taken.
 
     """
     return _arithmetic(data, domain, _multiply)
@@ -537,9 +488,8 @@ def divide(data: tuple, domain='freq'):
         Result of the operation as numpy array, if `data` contains only array
         likes and numbers. Result as Signal object if `data`contains a Signal.
         The `Signal.domain` is set by the input parameter `domain`. The
-        `Signal.signal_type` is 'energy' if `data` contains only energy
-        Signals and 'power' otherwise. The `Signal.fft_norm` is taken from the
-        first signal in `data`.
+        `Signal.fft_norm` is `None` if all FFT norms are None. Otherwise the
+        first FFT norm that is not None is taken.
 
     """
     return _arithmetic(data, domain, _divide)
@@ -565,9 +515,8 @@ def power(data: tuple, domain='freq'):
         Result of the operation as numpy array, if `data` contains only array
         likes and numbers. Result as Signal object if `data`contains a Signal.
         The `Signal.domain` is set by the input parameter `domain`. The
-        `Signal.signal_type` is 'energy' if `data` contains only energy
-        Signals and 'power' otherwise. The `Signal.fft_norm` is taken from the
-        first signal in `data`.
+        `Signal.fft_norm` is `None` if all FFT norms are None. Otherwise the
+        first FFT norm that is not None is taken.
 
     """
     return _arithmetic(data, domain, _power)
@@ -577,7 +526,7 @@ def _arithmetic(data: tuple, domain: str, operation: Callable):
     """Apply arithmetic operations."""
 
     # check input and obtain meta data of new signal
-    sampling_rate, n_samples, signal_type, fft_norm = \
+    sampling_rate, n_samples, fft_norm = \
         _assert_match_for_arithmetic(data, domain)
 
     # apply arithmetic operation
@@ -592,10 +541,10 @@ def _arithmetic(data: tuple, domain: str, operation: Callable):
         # apply desried fft normalization
         if domain == 'freq':
             result = fft.normalization(result, n_samples, sampling_rate,
-                                       signal_type, fft_norm)
+                                       fft_norm)
 
         result = Signal(
-            result, sampling_rate, n_samples, domain, signal_type, fft_norm)
+            result, sampling_rate, n_samples, domain, fft_norm=fft_norm)
 
     return result
 
@@ -621,12 +570,9 @@ def _assert_match_for_arithmetic(data: tuple, domain: str):
     n_samples : number, None
         Number of samples of the signals. None, if no signal is contained in
         `data`
-    signal_type : str, None
-        'energy' if all signaly are of type energy. 'power' if any power signal
-        is contained in `data`. None if no signal is contained in `data`
     fft_norm : str, None
-        FFT norm of the first signal in `data`. None if no signal is contained
-        in `data`.
+        FFT norm of the first signal in `data`, if all FFT norms are None.
+        Otherwise the first FFT norm that is not None is taken.
 
     """
 
@@ -641,7 +587,6 @@ def _assert_match_for_arithmetic(data: tuple, domain: str):
     # check input types and meta data
     sampling_rate = None
     n_samples = None
-    signal_type = None
     fft_norm = None
     for d in data:
         # check or store meta data of signals
@@ -649,7 +594,6 @@ def _assert_match_for_arithmetic(data: tuple, domain: str):
             if sampling_rate is None:
                 sampling_rate = d.sampling_rate
                 n_samples = d.n_samples
-                signal_type = d.signal_type
                 fft_norm = d.fft_norm
             else:
                 if sampling_rate != d.sampling_rate:
@@ -658,8 +602,8 @@ def _assert_match_for_arithmetic(data: tuple, domain: str):
                     raise ValueError("The number of samples does not match.")
             # if there is a power signal, the returned signal will be a power
             # signal
-            if d.signal_type == "power":
-                signal_type = "power"
+            if d.fft_norm != 'none' and fft_norm == 'none':
+                fft_norm = d.fft_norm
         # check type of non signal input
         else:
             dtypes = ['int8', 'int16', 'int32', 'int64',
@@ -673,7 +617,7 @@ def _assert_match_for_arithmetic(data: tuple, domain: str):
                 raise ValueError(
                     "Complex input can not be applied in the time domain.")
 
-    return sampling_rate, n_samples, signal_type, fft_norm
+    return sampling_rate, n_samples, fft_norm
 
 
 def _get_arithmetic_data(data, n_samples, domain):
@@ -704,11 +648,11 @@ def _get_arithmetic_data(data, n_samples, domain):
         elif domain == "freq":
             data_out = data.freq.copy()
 
-            if data.signal_type == 'power':
+            if data.fft_norm != 'none':
                 # remove current fft normalization
                 data_out = fft.normalization(
                     data_out, n_samples, data.sampling_rate,
-                    'power', data.fft_norm, inverse=True)
+                    data.fft_norm, inverse=True)
 
         else:
             raise ValueError(


Test patch:
diff --git a/tests/test_fft.py b/tests/test_fft.py
index 6c2cb6d2..953a0eeb 100644
--- a/tests/test_fft.py
+++ b/tests/test_fft.py
@@ -85,10 +85,9 @@ def test_fft_orthogonality_sine_even_np(fft_lib_np):
     times = np.arange(0, num_samples) / samplingrate
 
     signal_time = 1 * np.cos(2 * np.pi * frequency * times)
-    signal_spec = fft.rfft(
-        signal_time, num_samples, samplingrate, 'power', 'rms')
+    signal_spec = fft.rfft(signal_time, num_samples, samplingrate, 'rms')
     transformed_signal_time = fft.irfft(
-        signal_spec, num_samples, samplingrate, 'power', 'rms')
+        signal_spec, num_samples, samplingrate, 'rms')
 
     npt.assert_allclose(signal_time, transformed_signal_time, rtol=1e-10)
 
@@ -104,10 +103,9 @@ def test_fft_orthogonality_sine_even_fftw(fft_lib_pyfftw):
     times = np.arange(0, num_samples) / samplingrate
 
     signal_time = 1 * np.cos(2 * np.pi * frequency * times)
-    signal_spec = fft.rfft(
-        signal_time, num_samples, samplingrate, 'power', 'rms')
+    signal_spec = fft.rfft(signal_time, num_samples, samplingrate, 'rms')
     transformed_signal_time = fft.irfft(
-        signal_spec, num_samples, samplingrate, 'power', 'rms')
+        signal_spec, num_samples, samplingrate, 'rms')
 
     npt.assert_allclose(signal_time, transformed_signal_time, rtol=1e-10)
 
@@ -124,9 +122,9 @@ def test_fft_orthogonality_sine_odd_np(fft_lib_np):
 
     signal_time = 1 * np.cos(2 * np.pi * frequency * times)
     signal_spec = fft.rfft(
-        signal_time, num_samples, samplingrate, 'power', 'rms')
+        signal_time, num_samples, samplingrate, 'rms')
     transformed_signal_time = fft.irfft(
-        signal_spec, num_samples, samplingrate, 'power', 'rms')
+        signal_spec, num_samples, samplingrate, 'rms')
 
     npt.assert_allclose(signal_time, transformed_signal_time, rtol=1e-10)
 
@@ -142,10 +140,9 @@ def test_fft_orthogonality_sine_odd_fftw(fft_lib_pyfftw):
     times = np.arange(0, num_samples) / samplingrate
 
     signal_time = 1 * np.cos(2 * np.pi * frequency * times)
-    signal_spec = fft.rfft(
-        signal_time, num_samples, samplingrate, 'power', 'rms')
+    signal_spec = fft.rfft(signal_time, num_samples, samplingrate, 'rms')
     transformed_signal_time = fft.irfft(
-        signal_spec, num_samples, samplingrate, 'power', 'rms')
+        signal_spec, num_samples, samplingrate, 'rms')
 
     npt.assert_allclose(signal_time, transformed_signal_time, rtol=1e-10)
 
@@ -155,10 +152,9 @@ def test_fft_orthogonality_noise_even_np(fft_lib_np):
     np.random.seed(450)
     samplingrate = 40e3
     signal_time = np.random.normal(0, 1, n_samples)
-    signal_spec = fft.rfft(
-        signal_time, n_samples, samplingrate, 'power', 'rms')
+    signal_spec = fft.rfft(signal_time, n_samples, samplingrate, 'rms')
     transformed_signal_time = fft.irfft(
-        signal_spec, n_samples, samplingrate, 'power', 'rms')
+        signal_spec, n_samples, samplingrate, 'rms')
 
     npt.assert_allclose(signal_time, transformed_signal_time, rtol=1e-8)
 
@@ -168,10 +164,9 @@ def test_fft_orthogonality_noise_even_fftw(fft_lib_pyfftw):
     np.random.seed(450)
     samplingrate = 40e3
     signal_time = np.random.normal(0, 1, n_samples)
-    signal_spec = fft.rfft(
-        signal_time, n_samples, samplingrate, 'power', 'rms')
+    signal_spec = fft.rfft(signal_time, n_samples, samplingrate, 'rms')
     transformed_signal_time = fft.irfft(
-        signal_spec, n_samples, samplingrate, 'power', 'rms')
+        signal_spec, n_samples, samplingrate, 'rms')
 
     npt.assert_allclose(signal_time, transformed_signal_time, rtol=1e-8)
 
@@ -181,10 +176,9 @@ def test_fft_orthogonality_noise_odd_np(fft_lib_np):
     np.random.seed(450)
     samplingrate = 40e3
     signal_time = np.random.normal(0, 1, n_samples)
-    signal_spec = fft.rfft(
-        signal_time, n_samples, samplingrate, 'power', 'rms')
+    signal_spec = fft.rfft(signal_time, n_samples, samplingrate, 'rms')
     transformed_signal_time = fft.irfft(
-        signal_spec, n_samples, samplingrate, 'power', 'rms')
+        signal_spec, n_samples, samplingrate, 'rms')
 
     npt.assert_allclose(signal_time, transformed_signal_time, rtol=1e-8)
 
@@ -194,10 +188,9 @@ def test_fft_orthogonality_noise_odd_fftw(fft_lib_pyfftw):
     np.random.seed(450)
     samplingrate = 40e3
     signal_time = np.random.normal(0, 1, n_samples)
-    signal_spec = fft.rfft(
-        signal_time, n_samples, samplingrate, 'power', 'rms')
+    signal_spec = fft.rfft(signal_time, n_samples, samplingrate, 'rms')
     transformed_signal_time = fft.irfft(
-        signal_spec, n_samples, samplingrate, 'power', 'rms')
+        signal_spec, n_samples, samplingrate, 'rms')
 
     npt.assert_allclose(signal_time, transformed_signal_time, rtol=1e-8)
 
@@ -213,8 +206,7 @@ def test_fft_parsevaL_theorem_sine_even_np(fft_lib_np):
     times = np.arange(0, num_samples) / samplingrate
 
     signal_time = 1 * np.cos(2 * np.pi * frequency * times)
-    signal_spec = fft.rfft(
-        signal_time, num_samples, samplingrate, 'power', 'rms')
+    signal_spec = fft.rfft(signal_time, num_samples, samplingrate, 'rms')
 
     e_time = np.mean(np.abs(signal_time)**2)
     e_freq = np.sum(np.abs(signal_spec)**2)
@@ -233,8 +225,7 @@ def test_fft_parsevaL_theorem_sine_even_fftw(fft_lib_pyfftw):
     times = np.arange(0, num_samples) / samplingrate
 
     signal_time = 1 * np.cos(2 * np.pi * frequency * times)
-    signal_spec = fft.rfft(
-        signal_time, num_samples, samplingrate, 'power', 'rms')
+    signal_spec = fft.rfft(signal_time, num_samples, samplingrate, 'rms')
 
     e_time = np.mean(np.abs(signal_time)**2)
     e_freq = np.sum(np.abs(signal_spec)**2)
@@ -253,8 +244,7 @@ def test_fft_parsevaL_theorem_sine_odd_np(fft_lib_np):
     times = np.arange(0, num_samples) / samplingrate
 
     signal_time = 1 * np.cos(2 * np.pi * frequency * times)
-    signal_spec = fft.rfft(
-        signal_time, num_samples, samplingrate, 'power', 'rms')
+    signal_spec = fft.rfft(signal_time, num_samples, samplingrate, 'rms')
 
     e_time = np.mean(np.abs(signal_time)**2)
     e_freq = np.sum(np.abs(signal_spec)**2)
@@ -273,8 +263,7 @@ def test_fft_parsevaL_theorem_sine_odd_fftw(fft_lib_pyfftw):
     times = np.arange(0, num_samples) / samplingrate
 
     signal_time = 1 * np.cos(2 * np.pi * frequency * times)
-    signal_spec = fft.rfft(
-        signal_time, num_samples, samplingrate, 'power', 'rms')
+    signal_spec = fft.rfft(signal_time, num_samples, samplingrate, 'rms')
 
     e_time = np.mean(np.abs(signal_time)**2)
     e_freq = np.sum(np.abs(signal_spec)**2)
@@ -287,8 +276,7 @@ def test_fft_parsevaL_theorem_noise_even_np(fft_lib_np):
     np.random.seed(450)
     samplingrate = 40e3
     noise_time = np.random.normal(0, 1, n_samples)
-    noise_spec = fft.rfft(
-        noise_time, n_samples, samplingrate, 'power', 'rms')
+    noise_spec = fft.rfft(noise_time, n_samples, samplingrate, 'rms')
 
     e_time = np.mean(np.abs(noise_time)**2)
     e_freq = np.sum(np.abs(noise_spec)**2)
@@ -301,8 +289,7 @@ def test_fft_parsevaL_theorem_noise_even_fftw(fft_lib_pyfftw):
     np.random.seed(450)
     samplingrate = 40e3
     noise_time = np.random.normal(0, 1, n_samples)
-    noise_spec = fft.rfft(
-        noise_time, n_samples, samplingrate, 'power', 'rms')
+    noise_spec = fft.rfft(noise_time, n_samples, samplingrate, 'rms')
 
     e_time = np.mean(np.abs(noise_time)**2)
     e_freq = np.sum(np.abs(noise_spec)**2)
@@ -315,8 +302,7 @@ def test_fft_parsevaL_theorem_noise_odd_np(fft_lib_np):
     np.random.seed(450)
     samplingrate = 40e3
     noise_time = np.random.normal(0, 1, n_samples)
-    noise_spec = fft.rfft(
-        noise_time, n_samples, samplingrate, 'power', 'rms')
+    noise_spec = fft.rfft(noise_time, n_samples, samplingrate, 'rms')
 
     e_time = np.mean(np.abs(noise_time)**2)
     e_freq = np.sum(np.abs(noise_spec)**2)
@@ -334,17 +320,17 @@ def test_is_not_odd():
     assert not fft._is_odd(num)
 
 
-def test_normalization_energy_signal():
+def test_normalization_None():
     spec_single = np.array([1, 1, 1])
     N = 4       # time signal with even number of samples
     fs = 40     # arbitrary sampling frequency for psd normalization
 
-    spec_out = fft.normalization(spec_single.copy(), N, fs, "energy",
-                                 "rms", inverse=False)
+    spec_out = fft.normalization(spec_single.copy(), N, fs,
+                                 'none', inverse=False)
     npt.assert_allclose(spec_out, spec_single, atol=1e-15)
 
-    spec_out = fft.normalization(spec_out, N, fs, "energy",
-                                 "rms", inverse=True)
+    spec_out = fft.normalization(spec_out, N, fs,
+                                 'none', inverse=True)
     npt.assert_allclose(spec_out, spec_single, atol=1e-15)
 
 
@@ -378,12 +364,12 @@ def test_normalization_single_sided_single_channel_even_samples():
 
     for normalization in truth:
         print(f"Assesing normalization: '{normalization}'")
-        spec_out = fft.normalization(spec_single.copy(), N, fs, "power",
+        spec_out = fft.normalization(spec_single.copy(), N, fs,
                                      normalization, inverse=False)
         npt.assert_allclose(spec_out, truth[normalization], atol=1e-15)
 
         print(f"Assesing normalization: '{normalization}' (inverse)")
-        spec_out_inv = fft.normalization(spec_out, N, fs, "power",
+        spec_out_inv = fft.normalization(spec_out, N, fs,
                                          normalization, inverse=True)
         npt.assert_allclose(spec_out_inv, spec_single, atol=1e-15)
 
@@ -418,12 +404,12 @@ def test_normalization_single_sided_single_channel_odd_samples():
 
     for normalization in truth:
         print(f"Assesing normalization: '{normalization}'")
-        spec_out = fft.normalization(spec_single.copy(), N, fs, "power",
+        spec_out = fft.normalization(spec_single.copy(), N, fs,
                                      normalization, inverse=False)
         npt.assert_allclose(spec_out, truth[normalization], atol=1e-15)
 
         print(f"Assesing normalization: '{normalization}' (inverse)")
-        spec_out_inv = fft.normalization(spec_out, N, fs, "power",
+        spec_out_inv = fft.normalization(spec_out, N, fs,
                                          normalization, inverse=True)
         npt.assert_allclose(spec_out_inv, spec_single, atol=1e-15)
 
@@ -454,13 +440,13 @@ def test_normalization_both_sided_single_channel():
 
     for normalization in truth:
         print(f"Assesing normalization: '{normalization}'")
-        spec_out = fft.normalization(spec_single.copy(), N, fs, "power",
+        spec_out = fft.normalization(spec_single.copy(), N, fs,
                                      normalization, inverse=False,
                                      single_sided=False)
         npt.assert_allclose(spec_out, truth[normalization], atol=1e-15)
 
         print(f"Assesing normalization: '{normalization}' (inverse)")
-        spec_out_inv = fft.normalization(spec_out, N, fs, "power",
+        spec_out_inv = fft.normalization(spec_out, N, fs,
                                          normalization, inverse=True,
                                          single_sided=False)
         npt.assert_allclose(spec_out_inv, spec_single, atol=1e-15)
@@ -497,31 +483,62 @@ def test_normalization_single_sided_multi_channel_even_samples():
 
     for normalization in truth:
         print(f"Assesing normalization: '{normalization}'")
-        spec_out = fft.normalization(spec_single.copy(), N, fs, "power",
+        spec_out = fft.normalization(spec_single.copy(), N, fs,
                                      normalization, inverse=False)
         npt.assert_allclose(spec_out, np.tile(truth[normalization], tile),
                             atol=1e-15)
 
         print(f"Assesing normalization: '{normalization}' (inverse)")
-        spec_out_inv = fft.normalization(spec_out, N, fs, "power",
+        spec_out_inv = fft.normalization(spec_out, N, fs,
                                          normalization, inverse=True)
         npt.assert_allclose(spec_out_inv, spec_single, atol=1e-15)
 
 
+def test_normalization_with_window():
+    """
+    Test if the window cancels out if applying the normalization and
+    inverse normalization.
+    """
+
+    # test with window as list and numpy array
+    windows = [[1, 1, 1, 1], np.array([1, 1, 1, 1])]
+
+    fft_norms = ['unitary', 'amplitude', 'rms', 'power', 'psd']
+    for window in windows:
+        for fft_norm in fft_norms:
+            print(f"testing: {window}, {fft_norm}")
+            spec = fft.normalization(np.array([.5, 1, .5]), 4, 44100,
+                                     fft_norm, window=window)
+            spec = fft.normalization(spec, 4, 44100, fft_norm,
+                                     inverse=True, window=window)
+            npt.assert_allclose(np.array([.5, 1, .5]), spec, atol=1e-15)
+
+
+def test_normalization_with_window_value_error():
+    """
+    Test if normalization throws a ValueError if the window has the
+    wrong length.
+    """
+
+    with raises(ValueError):
+        # n_samples=5, and len(window)=5
+        fft.normalization(np.array([.5, 1, .5]), 4, 44100,
+                          'amplitude', window=[1, 1, 1, 1, 1])
+
+
 def test_normalization_exceptions():
     # try without numpy array
     with raises(ValueError):
-        fft.normalization(1, 1, 44100, 'power')
-    # try rms normalization for power signal
+        fft.normalization(1, 1, 44100, 'rms')
+    # try invalid normalization
     with raises(ValueError):
-        fft.normalization(np.array([1]), 1, 44100, 'power',
-                          'rms', single_sided=False)
+        fft.normalization(np.array([1]), 1, 44100, 'goofy')
 
 
 def test_rfft_energy_imp_even_samples(impulse):
     n_samples = 1024
     samplingrate = 40e3
-    spec = fft.rfft(impulse, n_samples, samplingrate, 'energy', 'unitary')
+    spec = fft.rfft(impulse, n_samples, samplingrate, 'none')
 
     truth = np.ones(int(n_samples/2+1), dtype=np.complex)
     npt.assert_allclose(spec, truth)
@@ -530,7 +547,7 @@ def test_rfft_energy_imp_even_samples(impulse):
 def test_rfft_energy_imp_even_samples_fftw(impulse, fft_lib_pyfftw):
     n_samples = 1024
     samplingrate = 40e3
-    spec = fft.rfft(impulse, n_samples, samplingrate, 'energy', 'unitary')
+    spec = fft.rfft(impulse, n_samples, samplingrate, 'none')
 
     truth = np.ones(int(n_samples/2+1), dtype=np.complex)
     npt.assert_allclose(spec, truth)
@@ -540,7 +557,7 @@ def test_irfft_energy_imp_even_samples_np(impulse, fft_lib_np):
     n_samples = 1024
     samplingrate = 40e3
     spec = np.ones(int(n_samples/2+1), dtype=np.complex)
-    data = fft.irfft(spec, n_samples, samplingrate, 'energy', 'unitary')
+    data = fft.irfft(spec, n_samples, samplingrate, 'none')
 
     truth = impulse
     npt.assert_allclose(data, truth)
@@ -550,7 +567,7 @@ def test_irfft_energy_imp_even_samples_np_fftw(impulse, fft_lib_pyfftw):
     n_samples = 1024
     samplingrate = 40e3
     spec = np.ones(int(n_samples/2+1), dtype=np.complex)
-    data = fft.irfft(spec, n_samples, samplingrate, 'energy', 'unitary')
+    data = fft.irfft(spec, n_samples, samplingrate, 'none')
 
     truth = impulse
     npt.assert_allclose(data, truth)
@@ -559,7 +576,7 @@ def test_irfft_energy_imp_even_samples_np_fftw(impulse, fft_lib_pyfftw):
 def test_rfft_power_imp_even_samples_np(sine, fft_lib_np):
     n_samples = 1024
     sampling_rate = 2e3
-    spec = fft.rfft(sine, n_samples, sampling_rate, 'power', 'rms')
+    spec = fft.rfft(sine, n_samples, sampling_rate, 'rms')
 
     truth = np.zeros(int(n_samples/2+1), dtype=np.complex)
     truth[int(n_samples/16)] = 1/np.sqrt(2)
@@ -570,7 +587,7 @@ def test_rfft_power_imp_even_samples_np(sine, fft_lib_np):
 def test_rfft_power_imp_even_samples_fftw(sine, fft_lib_pyfftw):
     n_samples = 1024
     sampling_rate = 2e3
-    spec = fft.rfft(sine, n_samples, sampling_rate, 'power', 'rms')
+    spec = fft.rfft(sine, n_samples, sampling_rate, 'rms')
 
     truth = np.zeros(int(n_samples/2+1), dtype=np.complex)
     truth[int(n_samples/16)] = 1/np.sqrt(2)
@@ -584,7 +601,7 @@ def test_irfft_power_imp_even_samples_np(sine, fft_lib_np):
     spec = np.zeros(int(n_samples/2+1), dtype=np.complex)
     spec[int(n_samples/16)] = 1/np.sqrt(2)
 
-    data = fft.irfft(spec, n_samples, samplingrate, 'power', 'rms')
+    data = fft.irfft(spec, n_samples, samplingrate, 'rms')
 
     truth = sine
     npt.assert_allclose(data, truth, atol=1e-10)
@@ -596,7 +613,7 @@ def test_irfft_power_imp_even_samples_fftw(sine, fft_lib_pyfftw):
     spec = np.zeros(int(n_samples/2+1), dtype=np.complex)
     spec[int(n_samples/16)] = 1/np.sqrt(2)
 
-    data = fft.irfft(spec, n_samples, samplingrate, 'power', 'rms')
+    data = fft.irfft(spec, n_samples, samplingrate, 'rms')
 
     truth = sine
     npt.assert_allclose(data, truth, atol=1e-10)
@@ -608,7 +625,7 @@ def test_irfft_power_imp_odd_samples_np(sine_odd, fft_lib_np):
     spec = np.zeros(int((n_samples+1)/2), dtype=np.complex)
     spec[int(n_samples/16)] = 1/np.sqrt(2)
 
-    data = fft.irfft(spec, n_samples, samplingrate, 'power', 'rms')
+    data = fft.irfft(spec, n_samples, samplingrate, 'rms')
 
     truth, f = sine_odd
     npt.assert_allclose(data, truth, atol=1e-10)
@@ -620,7 +637,7 @@ def test_irfft_power_imp_odd_samples_fftw(sine_odd, fft_lib_pyfftw):
     spec = np.zeros(int((n_samples+1)/2), dtype=np.complex)
     spec[int(n_samples/16)] = 1/np.sqrt(2)
 
-    data = fft.irfft(spec, n_samples, samplingrate, 'power', 'rms')
+    data = fft.irfft(spec, n_samples, samplingrate, 'rms')
 
     truth, f = sine_odd
     npt.assert_allclose(data, truth, atol=1e-10)
@@ -630,7 +647,7 @@ def test_rfft_power_imp_odd_samples_np(sine_odd, fft_lib_np):
     n_samples = 1023
     s, f = sine_odd
     sampling_rate = 40e3
-    spec = fft.rfft(s, n_samples, sampling_rate, 'power', 'rms')
+    spec = fft.rfft(s, n_samples, sampling_rate, 'rms')
 
     truth = np.zeros(int((n_samples+1)/2), dtype=np.complex)
     truth[int(n_samples/16)] = 1/np.sqrt(2)
@@ -642,7 +659,7 @@ def test_rfft_power_imp_odd_samples_fftw(sine_odd, fft_lib_pyfftw):
     n_samples = 1023
     s, f = sine_odd
     sampling_rate = 40e3
-    spec = fft.rfft(s, n_samples, sampling_rate, 'power', 'rms')
+    spec = fft.rfft(s, n_samples, sampling_rate, 'rms')
 
     truth = np.zeros(int((n_samples+1)/2), dtype=np.complex)
     truth[int(n_samples/16)] = 1/np.sqrt(2)
diff --git a/tests/test_filter_classes.py b/tests/test_filter_classes.py
index ccb92662..6a8402db 100644
--- a/tests/test_filter_classes.py
+++ b/tests/test_filter_classes.py
@@ -513,14 +513,12 @@ def test_impulse_mock(impulse_mock):
     n_samples = 1000
     sampling_rate = 2000
     amplitude = 1
-    signal_type = 'energy'
 
     signal = np.atleast_2d(np.zeros(n_samples, dtype=np.double))
     signal[:, 0] = amplitude
 
     assert impulse_mock.sampling_rate == sampling_rate
     assert impulse_mock.cshape == (1,)
-    assert impulse_mock.signal_type == signal_type
     npt.assert_allclose(impulse_mock.time, signal)
 
 
@@ -535,7 +533,6 @@ def impulse_mock():
     n_samples = 1000
     sampling_rate = 2000
     amplitude = 1
-    signal_type = 'energy'
     cshape = (1,)
     domain = 'time'
 
@@ -544,11 +541,10 @@ def impulse_mock():
 
     # create a mock object of Signal class to test independently
     signal_object = mock.Mock(
-        spec_set=Signal(signal, sampling_rate, n_samples, domain, signal_type))
+        spec_set=Signal(signal, sampling_rate, n_samples, domain))
     signal_object.time = np.atleast_2d(signal)
     signal_object.sampling_rate = sampling_rate
     signal_object.domain = domain
-    signal_object.signal_type = signal_type
     signal_object.cshape = cshape
 
     return signal_object
diff --git a/tests/test_signal.py b/tests/test_signal.py
index ac3dc021..462f14e7 100644
--- a/tests/test_signal.py
+++ b/tests/test_signal.py
@@ -21,15 +21,12 @@ def test_signal_init_default_parameter(impulse_list):
     # using all defaults
     signal = Signal(impulse_list, 44100)
     assert signal.domain == 'time'
-    assert signal.signal_type == 'energy'
-    assert signal.fft_norm == 'unitary'
+    assert signal.fft_norm == 'none'
     assert signal.comment is None
 
     # default of fft_norm depending on signal type
-    signal = Signal(impulse_list, 44100, signal_type='energy')
-    assert signal.fft_norm == 'unitary'
-    signal = Signal(impulse_list, 44100, signal_type='power')
-    assert signal.fft_norm == 'rms'
+    signal = Signal(impulse_list, 44100)
+    assert signal.fft_norm == 'none'
 
 
 def test_signal_comment():
@@ -64,13 +61,10 @@ def test_domain_setter_freq_when_freq(sine):
 
 
 def test_domain_setter_freq_when_time(sine):
-    stype = 'power'
     fft_norm = 'rms'
     samplingrate = 40e3
-    spec = np.atleast_2d(fft.rfft(sine, len(sine), samplingrate,
-                                  stype, fft_norm))
-    signal = Signal(sine, 44100, domain='time',
-                    signal_type=stype, fft_norm=fft_norm)
+    spec = np.atleast_2d(fft.rfft(sine, len(sine), samplingrate, fft_norm))
+    signal = Signal(sine, 44100, domain='time', fft_norm=fft_norm)
     domain = 'freq'
     signal.domain = domain
     assert signal.domain == domain
@@ -86,13 +80,10 @@ def test_domain_setter_time_when_time(sine):
 
 
 def test_domain_setter_time_when_freq(sine):
-    stype = 'power'
     fft_norm = 'rms'
     samplingrate = 40e3
-    spec = np.atleast_2d(fft.rfft(sine, len(sine), samplingrate,
-                                  stype, fft_norm))
-    signal = Signal(spec, 44100, domain='freq',
-                    signal_type=stype, fft_norm=fft_norm)
+    spec = np.atleast_2d(fft.rfft(sine, len(sine), samplingrate, fft_norm))
+    signal = Signal(spec, 44100, domain='freq', fft_norm=fft_norm)
     signal._data = spec
     signal._n_samples = len(sine)
     domain = 'time'
@@ -104,18 +95,10 @@ def test_domain_setter_time_when_freq(sine):
 
 def test_signal_init_val(sine):
     """Test to init Signal with complete parameters."""
-    signal = Signal(sine, 44100, domain="time",
-                    signal_type="power", fft_norm='rms')
+    signal = Signal(sine, 44100, domain="time", fft_norm='rms')
     assert isinstance(signal, Signal)
 
 
-def test_signal_init_false_signal_type(sine):
-    """Test to init Signal with invalid signal type."""
-    with pytest.raises(ValueError):
-        Signal(sine, 44100, signal_type="falsetype")
-        pytest.fail("Not a valid signal type ('power'/'energy')")
-
-
 def test_signal_init_false_coord(sine):
     """Test to init Signal with position that is not of type Coordinates."""
     coord_false = np.array([1, 1, 1])
@@ -165,9 +148,9 @@ def test_setter_time(sine, impulse):
 def test_getter_freq(sine, impulse):
     """Test if attribute freq is accessed correctly."""
     samplingrate = 44100
-    signal = Signal(sine, samplingrate, signal_type='power', fft_norm='rms')
+    signal = Signal(sine, samplingrate, fft_norm='rms')
     new_sine = sine * 2
-    spec = fft.rfft(new_sine, len(new_sine), samplingrate, 'power', 'rms')
+    spec = fft.rfft(new_sine, len(new_sine), samplingrate, 'rms')
     signal._domain = 'freq'
     signal._data = spec
     npt.assert_allclose(signal.freq, spec, atol=1e-15)
@@ -176,9 +159,8 @@ def test_getter_freq(sine, impulse):
 def test_setter_freq(sine, impulse):
     """Test if attribute freq is set correctly."""
     samplingrate = 44100
-    signal = Signal(sine, samplingrate, signal_type='energy')
-    spec = fft.rfft(impulse, len(impulse), samplingrate,
-                    signal_type='energy', fft_norm='unitary')
+    signal = Signal(sine, samplingrate)
+    spec = fft.rfft(impulse, len(impulse), samplingrate, fft_norm='unitary')
     signal.freq = spec
     assert signal.domain == 'freq'
     npt.assert_allclose(np.atleast_2d(spec), signal._data, atol=1e-15)
@@ -203,55 +185,26 @@ def test_setter_sampligrate(sine):
 def test_getter_signal_type(sine):
     """Test if attribute signal type is accessed correctly."""
     signal_type = "energy"
-    signal = Signal(sine, 44100)
+    signal = Signal(sine, 44100, fft_norm='none')
     signal._signal_type = signal_type
     npt.assert_string_equal(signal.signal_type, signal_type)
 
-
-def test_setter_signal_type(sine):
-    """Test if attribute signal type is set correctly."""
     signal_type = "energy"
-    signal = Signal(sine, 44100)
-    signal.signal_type = signal_type
-    npt.assert_string_equal(signal_type, signal._signal_type)
+    signal = Signal(sine, 44100, fft_norm='rms')
+    signal._signal_type = signal_type
+    npt.assert_string_equal(signal.signal_type, signal_type)
 
 
-def test_setter_signal_type_freq_domain_data(sine):
+def test_setter_signal_type(sine):
     """Test if attribute signal type is set correctly."""
     signal_type = "energy"
-    signal = Signal(sine, 44100, signal_type='power')
-    amplitude = np.max(np.abs(signal.freq))
-    signal.fft_norm = 'unitary'
-    signal.signal_type = signal_type
-    amplitude_new = np.max(np.abs(signal.freq))
-    npt.assert_almost_equal(amplitude, 1/np.sqrt(2), decimal=3)
-    npt.assert_almost_equal(amplitude_new, 500.1327464502182, decimal=3)
-
-
-def test_setter_signal_type_false_type(sine):
-    """Test if ValueError is raised when signal type is set incorrectly."""
     signal = Signal(sine, 44100)
-    with pytest.raises(ValueError):
-        signal.signal_type = "falsetype"
-        pytest.fail("Not a valid signal type ('power'/'energy')")
-
-
-def test_signal_type_conversion():
-    spec_energy_unitary = np.atleast_2d([1, 1, 1])
-    spec_power_unitary = np.atleast_2d([1, 2, 1])
-    signal = Signal(spec_energy_unitary, 44100, n_samples=4, domain='freq',
-                    signal_type='energy')
-
-    # changing the signal type changes the fft_norm and this the spectrum
-    signal.signal_type = 'power'
-    npt.assert_allclose(spec_power_unitary, signal.freq, atol=1e-15)
-
-    signal.signal_type = 'energy'
-    npt.assert_allclose(spec_energy_unitary, signal.freq, atol=1e-15)
+    with pytest.raises(DeprecationWarning):
+        signal.signal_type = signal_type
 
 
 def test_getter_fft_norm(sine):
-    signal = Signal(sine, 44100, signal_type='power', fft_norm='psd')
+    signal = Signal(sine, 44100, fft_norm='psd')
     assert signal.fft_norm == 'psd'
 
 
@@ -259,8 +212,9 @@ def test_setter_fft_norm(sine):
     spec_power_unitary = np.atleast_2d([1, 2, 1])
     spec_power_amplitude = np.atleast_2d([1/4, 2/4, 1/4])
 
-    signal = Signal(spec_power_unitary, 44100, n_samples=4, domain='freq',
-                    signal_type='power', fft_norm='unitary')
+    signal = Signal(
+        spec_power_unitary, 44100, n_samples=4, domain='freq',
+        fft_norm='unitary')
 
     # changing the fft_norm also changes the spectrum
     signal.fft_norm = 'amplitude'
@@ -278,11 +232,6 @@ def test_setter_fft_norm(sine):
     with pytest.raises(ValueError):
         signal.fft_norm = 'bullshit'
 
-    # setting invalid fft_norm for energy signals
-    signal = Signal(sine, 44100, signal_type='energy')
-    with pytest.raises(ValueError):
-        signal.fft_norm = 'rms'
-
 
 def test_dtype(sine):
     """Test for the getter od dtype."""
@@ -347,12 +296,12 @@ def test_magic_setitem_wrong_sr(sine, impulse):
         signal[0] = set_signal
 
 
-def test_magic_setitem_wrong_type(sine, impulse):
+def test_magic_setitem_wrong_norm(sine, impulse):
     """Test the magic function __setitem__."""
     sr = 44100
-    signal = Signal(impulse, sr, signal_type='energy', fft_norm='unitary')
-    set_signal = Signal(sine*2, sr, signal_type='power', fft_norm='unitary')
-    with pytest.raises(ValueError, match='signal types do not match'):
+    signal = Signal(impulse, sr, fft_norm='none')
+    set_signal = Signal(sine*2, sr, fft_norm='rms')
+    with pytest.raises(ValueError, match='FFT norms do not match'):
         signal[0] = set_signal
 
 
diff --git a/tests/test_signal_arithmetic.py b/tests/test_signal_arithmetic.py
index 65cea0e9..bdbe71e8 100644
--- a/tests/test_signal_arithmetic.py
+++ b/tests/test_signal_arithmetic.py
@@ -146,8 +146,8 @@ def test_assert_match_for_arithmetic():
     s = Signal([1, 2, 3, 4], 44100)
     s1 = Signal([1, 2, 3, 4], 48000)
     s2 = Signal([1, 2, 3], 44100)
-    s4 = Signal([1, 2, 3, 4], 44100, signal_type="power")
-    s5 = Signal([1, 2, 3, 4], 44100, signal_type="power", fft_norm='amplitude')
+    s4 = Signal([1, 2, 3, 4], 44100, fft_norm="rms")
+    s5 = Signal([1, 2, 3, 4], 44100, fft_norm='amplitude')
 
     # check with two signals
     signal._assert_match_for_arithmetic((s, s), 'time')
@@ -160,12 +160,11 @@ def test_assert_match_for_arithmetic():
     out = signal._assert_match_for_arithmetic((s, s), 'time')
     assert out[0] == 44100
     assert out[1] == 4
-    assert out[2] == 'energy'
+    assert out[2] == 'none'
     out = signal._assert_match_for_arithmetic((s, s4), 'time')
-    assert out[2] == 'power'
+    assert out[2] == 'rms'
     out = signal._assert_match_for_arithmetic((s5, s4), 'time')
-    assert out[2] == 'power'
-    assert out[3] == 'amplitude'
+    assert out[2] == 'amplitude'
 
     # check with only one argument
     with raises(TypeError):
@@ -197,18 +196,18 @@ def test_get_arithmetic_data_with_array():
 
 def test_get_arithmetic_data_with_signal():
     # all possible combinations of `domain`, `signal_type`, and `fft_norm`
-    meta = [['time', 'energy', 'unitary'],
-            ['freq', 'energy', 'unitary'],
-            ['time', 'power', 'unitary'],
-            ['freq', 'power', 'unitary'],
-            ['time', 'power', 'amplitude'],
-            ['freq', 'power', 'amplitude'],
-            ['time', 'power', 'rms'],
-            ['freq', 'power', 'rms'],
-            ['time', 'power', 'power'],
-            ['freq', 'power', 'power'],
-            ['time', 'power', 'psd'],
-            ['freq', 'power', 'psd']]
+    meta = [['time', None],
+            ['freq', None],
+            ['time', 'unitary'],
+            ['freq', 'unitary'],
+            ['time', 'amplitude'],
+            ['freq', 'amplitude'],
+            ['time', 'rms'],
+            ['freq', 'rms'],
+            ['time', 'power'],
+            ['freq', 'power'],
+            ['time', 'psd'],
+            ['freq', 'psd']]
 
     # reference signal - _get_arithmetic_data should return the data without
     # any normalization regardless of the input data
@@ -216,10 +215,10 @@ def test_get_arithmetic_data_with_signal():
 
     for m_in in meta:
         # create input signal with current domain, type, and norm
-        s_in = Signal([1, 0, 0], 44100, signal_type=m_in[1], fft_norm=m_in[2])
+        s_in = Signal([1, 0, 0], 44100, fft_norm=m_in[1])
         s_in.domain = m_in[0]
         for domain in ['time', 'freq']:
-            print(f"Testing from {', '.join(m_in)} to {domain}.")
+            print(f"Testing from {m_in[0]} ({m_in[1]}) to {domain}.")
 
             # get output data
             data_out = signal._get_arithmetic_data(