Third octave frequency spectrum with pythonCalling an external command in PythonWhat are metaclasses in Python?Is there a way to run Python on Android?Finding the index of an item given a list containing it in PythonDifference between append vs. extend list methods in PythonHow can I safely create a nested directory in Python?Does Python have a ternary conditional operator?How to get the current time in PythonHow can I make a time delay in Python?Does Python have a string 'contains' substring method?

Divine apple island

What does this horizontal bar at the first measure mean?

Can I sign legal documents with a smiley face?

Why did the EU agree to delay the Brexit deadline?

Should I install hardwood flooring or cabinets first?

Indicating multiple different modes of speech (fantasy language or telepathy)

Why has "pence" been used in this sentence, not "pences"?

Is XSS in canonical link possible?

Translation of Scottish 16th century church stained glass

Is it possible to have a strip of cold climate in the middle of a planet?

Using a siddur to Daven from in a seforim store

Folder comparison

Melting point of aspirin, contradicting sources

Are all species of CANNA edible?

Java - What do constructor type arguments mean when placed *before* the type?

Can the Supreme Court overturn an impeachment?

Can I Retrieve Email Addresses from BCC?

Is camera lens focus an exact point or a range?

What is this type of notehead called?

Reply 'no position' while the job posting is still there

Customize circled numbers

Did arcade monitors have same pixel aspect ratio as TV sets?

Would it be legal for a US State to ban exports of a natural resource?

Can somebody explain Brexit in a few child-proof sentences?



Third octave frequency spectrum with python


Calling an external command in PythonWhat are metaclasses in Python?Is there a way to run Python on Android?Finding the index of an item given a list containing it in PythonDifference between append vs. extend list methods in PythonHow can I safely create a nested directory in Python?Does Python have a ternary conditional operator?How to get the current time in PythonHow can I make a time delay in Python?Does Python have a string 'contains' substring method?













0















I am trying to get a third-octave frequency spectrum of a time signal.



The time signal is the acoustic pressure of rotational rotor noise which is harmonic. Its fundamental frequency is ff = n * N_b and for that reason, all frequencies should be multiples of ff.



Using fft I get the expected result:
Multiples of the fundamental frequency are the relevant frequencies in the spectrum.



To get the third-octave frequency spectrum I wanted to use python acoustics, but the result of the function bandpass_third_octaves is not what I expected.



I expected the peaks from the fft frequency spectrum to be simply shifted to the third-octave centre frequencies with an adjusted amplitude. At least that is what I would like to get.



I think I interpret the output of bandpass_third_octaves incorrectly. Its output is a tuple containing the third-octave frequencies and a list of arrays which are supposed to contain the amplitude values as far as I know.



I currently use the arrays' maximum value as resulting amplitude because it works better than using the sum of it. It is possible that this interpretation is my mistake.



I would appreciate any help. There is no need for me to use python acoustics. Any solution to get the third-octave frequency spectrum would be awesome.



Edit: Using the mean instead of the maximum produces better results, but I am still not completely satisfied with it.



Signal in time domain, frequency domain and supposed third octave spectrum



import matplotlib.pyplot as plt
import numpy as np
from scipy.sparse import spdiags
from scipy.signal import butter, lfilter, freqz, filtfilt, sosfilt

import acoustics.octave
#from acoustics.octave import REFERENCE

import acoustics.bands
from scipy.signal import hilbert
from acoustics.standards.iso_tr_25417_2007 import REFERENCE_PRESSURE
from acoustics.standards.iec_61672_1_2013 import (NOMINAL_OCTAVE_CENTER_FREQUENCIES,
NOMINAL_THIRD_OCTAVE_CENTER_FREQUENCIES)

try:
from pyfftw.interfaces.numpy_fft import rfft
except ImportError:
from numpy.fft import rfft


def bandpass_filter(lowcut, highcut, fs, order=8, output='sos'):
"""Band-pass filter.
:param lowcut: Lower cut-off frequency
:param highcut: Upper cut-off frequency
:param fs: Sample frequency
:param order: Filter order
:param output: Output type. 'ba', 'zpk', 'sos'. Default is 'sos'. See also :func:`scipy.signal.butter`.
:returns: Returned value depends on `output`.
A Butterworth filter is used.
.. seealso:: :func:`scipy.signal.butter`.
"""
nyq = 0.5 * fs
low = lowcut / nyq
high = highcut / nyq
output = butter(order / 2, [low, high], btype='band', output=output)
return output



def bandpass(signal, lowcut, highcut, fs, order=8, zero_phase=False):
"""Filter signal with band-pass filter.
:param signal: Signal
:param lowcut: Lower cut-off frequency
:param highcut: Upper cut-off frequency
:param fs: Sample frequency
:param order: Filter order
:param zero_phase: Prevent phase error by filtering in both directions (filtfilt)
A Butterworth filter is used. Filtering is done with second-order sections.
.. seealso:: :func:`bandpass_filter` for the filter that is used.
"""
sos = bandpass_filter(lowcut, highcut, fs, order, output='sos')
if zero_phase:
return _sosfiltfilt(sos, signal)
else:
return sosfilt(sos, signal)


class Frequencies:
"""
Object describing frequency bands.
"""

def __init__(self, center, lower, upper, bandwidth=None):

self.center = np.asarray(center)
"""
Center frequencies.
"""

self.lower = np.asarray(lower)
"""
Lower frequencies.
"""

self.upper = np.asarray(upper)
"""
Upper frequencies.
"""

self.bandwidth = np.asarray(bandwidth) if bandwidth is not None else np.asarray(self.upper) - np.asarray(
self.lower)
"""
Bandwidth.
"""

def __iter__(self):
for i in range(len(self.center)):
yield self[i]

def __len__(self):
return len(self.center)

def __str__(self):
return str(self.center)

def __repr__(self):
return "Frequencies()".format(str(self.center))

def angular(self):
"""Angular center frequency in radians per second.
"""
return 2.0 * np.pi * self.center



class OctaveBand(Frequencies):
"""Fractional-octave band spectrum.
"""

def __init__(self, center=None, fstart=None, fstop=None, nbands=None, fraction=1,
reference=acoustics.octave.REFERENCE):

if center is not None:
try:
nbands = len(center)
except TypeError:
center = [center]
center = np.asarray(center)
indices = acoustics.octave.index_of_frequency(center, fraction=fraction, ref=reference)
elif fstart is not None and fstop is not None:
nstart = acoustics.octave.index_of_frequency(fstart, fraction=fraction, ref=reference)
nstop = acoustics.octave.index_of_frequency(fstop, fraction=fraction, ref=reference)
indices = np.arange(nstart, nstop + 1)
elif fstart is not None and nbands is not None:
nstart = acoustics.octave.index_of_frequency(fstart, fraction=fraction, ref=reference)
indices = np.arange(nstart, nstart + nbands)
elif fstop is not None and nbands is not None:
nstop = acoustics.octave.index_of_frequency(fstop, fraction=fraction, ref=reference)
indices = np.arange(nstop - nbands, nstop)
else:
raise ValueError("Insufficient parameters. Cannot determine fstart and/or fstop.")

center = acoustics.octave.exact_center_frequency(None, fraction=fraction, n=indices, ref=reference)
lower = acoustics.octave.lower_frequency(center, fraction=fraction)
upper = acoustics.octave.upper_frequency(center, fraction=fraction)
bandwidth = upper - lower
nominal = acoustics.octave.nominal_center_frequency(None, fraction, indices)

super(OctaveBand, self).__init__(center, lower, upper, bandwidth)

self.fraction = fraction
"""Fraction of fractional-octave filter.
"""

self.reference = reference
"""Reference center frequency.
"""

self.nominal = nominal
"""Nominal center frequencies.
"""

def __getitem__(self, key):
return type(self)(center=self.center[key], fraction=self.fraction, reference=self.reference)

def __repr__(self):
return "OctaveBand()".format(str(self.center))




def bandpass_frequencies(x, fs, frequencies, order=8, purge=False, zero_phase=False):
""""Apply bandpass filters for frequencies
:param x: Instantaneous signal :math:`x(t)`.
:param fs: Sample frequency.
:param frequencies: Frequencies. Instance of :class:`Frequencies`.
:param order: Filter order.
:param purge: Discard bands of which the upper corner frequency is above the Nyquist frequency.
:param zero_phase: Prevent phase error by filtering in both directions (filtfilt)
:returns: Tuple. First element is an instance of :class:`OctaveBand`. The second element an array.
"""
if purge:
frequencies = frequencies[frequencies.upper < fs / 2.0]
return frequencies, np.array(
[bandpass(x, band.lower, band.upper, fs, order, zero_phase=zero_phase) for band in frequencies])




def bandpass_third_octaves(x, fs, frequencies=NOMINAL_THIRD_OCTAVE_CENTER_FREQUENCIES, order=8, purge=False,
zero_phase=False):
"""Apply 1/3-octave bandpass filters.
:param x: Instantaneous signal :math:`x(t)`.
:param fs: Sample frequency.
:param frequencies: Frequencies.
:param order: Filter order.
:param purge: Discard bands of which the upper corner frequency is above the Nyquist frequency.
:param zero_phase: Prevent phase error by filtering in both directions (filtfilt)
:returns: Tuple. First element is an instance of :class:`OctaveBand`. The second element an array.
.. seealso:: :func:`octavepass`
"""
return bandpass_fractional_octaves(x, fs, frequencies, fraction=3, order=order, purge=purge, zero_phase=zero_phase)



def bandpass_fractional_octaves(x, fs, frequencies, fraction=None, order=8, purge=False, zero_phase=False):
"""Apply 1/N-octave bandpass filters.
:param x: Instantaneous signal :math:`x(t)`.
:param fs: Sample frequency.
:param frequencies: Frequencies. Either instance of :class:`OctaveBand`, or array along with fs.
:param order: Filter order.
:param purge: Discard bands of which the upper corner frequency is above the Nyquist frequency.
:param zero_phase: Prevent phase error by filtering in both directions (filtfilt)
:returns: Tuple. First element is an instance of :class:`OctaveBand`. The second element an array.
.. seealso:: :func:`octavepass`
"""
if not isinstance(frequencies, Frequencies):
frequencies = OctaveBand(center=frequencies, fraction=fraction)
return bandpass_frequencies(x, fs, frequencies, order=order, purge=purge, zero_phase=zero_phase)



def _sosfiltfilt(sos, x, axis=-1, padtype='odd', padlen=None, method='pad', irlen=None):
"""Filtfilt version using Second Order sections. Code is taken from scipy.signal.filtfilt and adapted to make it work with SOS.
Note that broadcasting does not work.
"""
from scipy.signal import sosfilt_zi
from scipy.signal._arraytools import odd_ext, axis_slice, axis_reverse
x = np.asarray(x)

if padlen is None:
edge = 0
else:
edge = padlen

# x's 'axis' dimension must be bigger than edge.
if x.shape[axis] <= edge:
raise ValueError("The length of the input vector x must be at least " "padlen, which is %d." % edge)

if padtype is not None and edge > 0:
# Make an extension of length `edge` at each
# end of the input array.
if padtype == 'even':
ext = even_ext(x, edge, axis=axis)
elif padtype == 'odd':
ext = odd_ext(x, edge, axis=axis)
else:
ext = const_ext(x, edge, axis=axis)
else:
ext = x

# Get the steady state of the filter's step response.
zi = sosfilt_zi(sos)

# Reshape zi and create x0 so that zi*x0 broadcasts
# to the correct value for the 'zi' keyword argument
# to lfilter.
#zi_shape = [1] * x.ndim
#zi_shape[axis] = zi.size
#zi = np.reshape(zi, zi_shape)
x0 = axis_slice(ext, stop=1, axis=axis)
# Forward filter.
(y, zf) = sosfilt(sos, ext, axis=axis, zi=zi * x0)

# Backward filter.
# Create y0 so zi*y0 broadcasts appropriately.
y0 = axis_slice(y, start=-1, axis=axis)
(y, zf) = sosfilt(sos, axis_reverse(y, axis=axis), axis=axis, zi=zi * y0)

# Reverse y.
y = axis_reverse(y, axis=axis)

if edge > 0:
# Slice the actual signal from the extended signal.
y = axis_slice(y, start=edge, stop=-edge, axis=axis)

return y


rho = 1.2
a = 340
N_b = 1
R = 1
r_H = 10
A = np.pi*R**2
TA = 287
M_H = 0.3
w = M_H*a/R
n = w/(2*np.pi)

t = np.linspace(0,0.8,num=40000)
az = t*2*np.pi*n*N_b

sin = np.sin(az)
cos = np.cos(az)


#Thickness Noise

F_H = R/r_H
F_E = 0.00012875807653441588 #Bestimmt für den Propeller aus Paper
T1 = ((3-M_H*sin)*sin)/((1-M_H*sin)**3)
T2 = (M_H*(cos**2))/(10*(1-M_H*sin)**4)
T3 = 50 + 39*(M_H**2) - 45*M_H*sin - 11*(M_H**2)*(sin**2) + 12* (M_H**3) *sin - 18*(M_H**3)*(sin**3)
T_M = ((M_H**3)/12)*(-T1 + T2 * T3)

p_T = 0.5 * rho * a**2 * F_H * F_E * T_M


#Loading Noise

F_T = (TA/ (rho * a**2))**(3/2) * (1 / (60 * np.sqrt(2) * N_b))
L = 60 + 30 * M_H**2 * cos**2 - 120 * M_H * sin - 30 * M_H**3 * sin * cos**2 + 80 * M_H**2 * sin**2 + 9 * M_H**4 * sin**2 * cos**2 - 20 * M_H**3 * sin**3
L_M = cos * (1 - M_H * sin)**(-3) * L

p_L = 0.5 * rho * a**2 * F_H * F_T * L_M

#Total

p_total = p_T + p_L
plt.figure(1)
plt.plot(t, p_total)
plt.title('Signal in time domain')
plt.xlabel('time [s]')
plt.ylabel('acoustic pressure [Pa]')

#fundamental frequency
ff = n*N_b
print('ff',ff)

#Sampling frequency
T = t[1] - t[0]
f_s = 1/T
print('fs',f_s)

#Trying to get the one third octave frequency spectrum

test = bandpass_third_octaves(p_total, f_s,frequencies=NOMINAL_THIRD_OCTAVE_CENTER_FREQUENCIES,order=8,purge=False,zero_phase = True)
a_l = list()
i = 0
while i < 34:
a = max(test[1][i])
a_l.append(a)
i+=1

f = NOMINAL_THIRD_OCTAVE_CENTER_FREQUENCIES
plt.figure(2)
plt.bar(f, np.abs(a_l))
plt.title('Supposed one third octave spectrum of the time signal')
plt.xlabel('frequency [Hz]')
plt.ylabel('acoustic pressure [Pa]')
plt.xlim(0,100)

#FFT of the time signal p_total

N = p_total.size
f = np.linspace(0, 1/T, N)
f_scaled = f[:N // 2]
p_total -= np.mean(p_total)
fft = np.fft.fft(p_total)
fft_scaled = np.abs(fft)[:N // 2] * 2 / N
plt.figure(3)
plt.bar(f_scaled, fft_scaled)
plt.title('Signal in frequency domain')
plt.xlabel('frequency [Hz]')
plt.ylabel('acoustic pressure [Pa]')
plt.xlim(0,100)
plt.show()









share|improve this question




























    0















    I am trying to get a third-octave frequency spectrum of a time signal.



    The time signal is the acoustic pressure of rotational rotor noise which is harmonic. Its fundamental frequency is ff = n * N_b and for that reason, all frequencies should be multiples of ff.



    Using fft I get the expected result:
    Multiples of the fundamental frequency are the relevant frequencies in the spectrum.



    To get the third-octave frequency spectrum I wanted to use python acoustics, but the result of the function bandpass_third_octaves is not what I expected.



    I expected the peaks from the fft frequency spectrum to be simply shifted to the third-octave centre frequencies with an adjusted amplitude. At least that is what I would like to get.



    I think I interpret the output of bandpass_third_octaves incorrectly. Its output is a tuple containing the third-octave frequencies and a list of arrays which are supposed to contain the amplitude values as far as I know.



    I currently use the arrays' maximum value as resulting amplitude because it works better than using the sum of it. It is possible that this interpretation is my mistake.



    I would appreciate any help. There is no need for me to use python acoustics. Any solution to get the third-octave frequency spectrum would be awesome.



    Edit: Using the mean instead of the maximum produces better results, but I am still not completely satisfied with it.



    Signal in time domain, frequency domain and supposed third octave spectrum



    import matplotlib.pyplot as plt
    import numpy as np
    from scipy.sparse import spdiags
    from scipy.signal import butter, lfilter, freqz, filtfilt, sosfilt

    import acoustics.octave
    #from acoustics.octave import REFERENCE

    import acoustics.bands
    from scipy.signal import hilbert
    from acoustics.standards.iso_tr_25417_2007 import REFERENCE_PRESSURE
    from acoustics.standards.iec_61672_1_2013 import (NOMINAL_OCTAVE_CENTER_FREQUENCIES,
    NOMINAL_THIRD_OCTAVE_CENTER_FREQUENCIES)

    try:
    from pyfftw.interfaces.numpy_fft import rfft
    except ImportError:
    from numpy.fft import rfft


    def bandpass_filter(lowcut, highcut, fs, order=8, output='sos'):
    """Band-pass filter.
    :param lowcut: Lower cut-off frequency
    :param highcut: Upper cut-off frequency
    :param fs: Sample frequency
    :param order: Filter order
    :param output: Output type. 'ba', 'zpk', 'sos'. Default is 'sos'. See also :func:`scipy.signal.butter`.
    :returns: Returned value depends on `output`.
    A Butterworth filter is used.
    .. seealso:: :func:`scipy.signal.butter`.
    """
    nyq = 0.5 * fs
    low = lowcut / nyq
    high = highcut / nyq
    output = butter(order / 2, [low, high], btype='band', output=output)
    return output



    def bandpass(signal, lowcut, highcut, fs, order=8, zero_phase=False):
    """Filter signal with band-pass filter.
    :param signal: Signal
    :param lowcut: Lower cut-off frequency
    :param highcut: Upper cut-off frequency
    :param fs: Sample frequency
    :param order: Filter order
    :param zero_phase: Prevent phase error by filtering in both directions (filtfilt)
    A Butterworth filter is used. Filtering is done with second-order sections.
    .. seealso:: :func:`bandpass_filter` for the filter that is used.
    """
    sos = bandpass_filter(lowcut, highcut, fs, order, output='sos')
    if zero_phase:
    return _sosfiltfilt(sos, signal)
    else:
    return sosfilt(sos, signal)


    class Frequencies:
    """
    Object describing frequency bands.
    """

    def __init__(self, center, lower, upper, bandwidth=None):

    self.center = np.asarray(center)
    """
    Center frequencies.
    """

    self.lower = np.asarray(lower)
    """
    Lower frequencies.
    """

    self.upper = np.asarray(upper)
    """
    Upper frequencies.
    """

    self.bandwidth = np.asarray(bandwidth) if bandwidth is not None else np.asarray(self.upper) - np.asarray(
    self.lower)
    """
    Bandwidth.
    """

    def __iter__(self):
    for i in range(len(self.center)):
    yield self[i]

    def __len__(self):
    return len(self.center)

    def __str__(self):
    return str(self.center)

    def __repr__(self):
    return "Frequencies()".format(str(self.center))

    def angular(self):
    """Angular center frequency in radians per second.
    """
    return 2.0 * np.pi * self.center



    class OctaveBand(Frequencies):
    """Fractional-octave band spectrum.
    """

    def __init__(self, center=None, fstart=None, fstop=None, nbands=None, fraction=1,
    reference=acoustics.octave.REFERENCE):

    if center is not None:
    try:
    nbands = len(center)
    except TypeError:
    center = [center]
    center = np.asarray(center)
    indices = acoustics.octave.index_of_frequency(center, fraction=fraction, ref=reference)
    elif fstart is not None and fstop is not None:
    nstart = acoustics.octave.index_of_frequency(fstart, fraction=fraction, ref=reference)
    nstop = acoustics.octave.index_of_frequency(fstop, fraction=fraction, ref=reference)
    indices = np.arange(nstart, nstop + 1)
    elif fstart is not None and nbands is not None:
    nstart = acoustics.octave.index_of_frequency(fstart, fraction=fraction, ref=reference)
    indices = np.arange(nstart, nstart + nbands)
    elif fstop is not None and nbands is not None:
    nstop = acoustics.octave.index_of_frequency(fstop, fraction=fraction, ref=reference)
    indices = np.arange(nstop - nbands, nstop)
    else:
    raise ValueError("Insufficient parameters. Cannot determine fstart and/or fstop.")

    center = acoustics.octave.exact_center_frequency(None, fraction=fraction, n=indices, ref=reference)
    lower = acoustics.octave.lower_frequency(center, fraction=fraction)
    upper = acoustics.octave.upper_frequency(center, fraction=fraction)
    bandwidth = upper - lower
    nominal = acoustics.octave.nominal_center_frequency(None, fraction, indices)

    super(OctaveBand, self).__init__(center, lower, upper, bandwidth)

    self.fraction = fraction
    """Fraction of fractional-octave filter.
    """

    self.reference = reference
    """Reference center frequency.
    """

    self.nominal = nominal
    """Nominal center frequencies.
    """

    def __getitem__(self, key):
    return type(self)(center=self.center[key], fraction=self.fraction, reference=self.reference)

    def __repr__(self):
    return "OctaveBand()".format(str(self.center))




    def bandpass_frequencies(x, fs, frequencies, order=8, purge=False, zero_phase=False):
    """"Apply bandpass filters for frequencies
    :param x: Instantaneous signal :math:`x(t)`.
    :param fs: Sample frequency.
    :param frequencies: Frequencies. Instance of :class:`Frequencies`.
    :param order: Filter order.
    :param purge: Discard bands of which the upper corner frequency is above the Nyquist frequency.
    :param zero_phase: Prevent phase error by filtering in both directions (filtfilt)
    :returns: Tuple. First element is an instance of :class:`OctaveBand`. The second element an array.
    """
    if purge:
    frequencies = frequencies[frequencies.upper < fs / 2.0]
    return frequencies, np.array(
    [bandpass(x, band.lower, band.upper, fs, order, zero_phase=zero_phase) for band in frequencies])




    def bandpass_third_octaves(x, fs, frequencies=NOMINAL_THIRD_OCTAVE_CENTER_FREQUENCIES, order=8, purge=False,
    zero_phase=False):
    """Apply 1/3-octave bandpass filters.
    :param x: Instantaneous signal :math:`x(t)`.
    :param fs: Sample frequency.
    :param frequencies: Frequencies.
    :param order: Filter order.
    :param purge: Discard bands of which the upper corner frequency is above the Nyquist frequency.
    :param zero_phase: Prevent phase error by filtering in both directions (filtfilt)
    :returns: Tuple. First element is an instance of :class:`OctaveBand`. The second element an array.
    .. seealso:: :func:`octavepass`
    """
    return bandpass_fractional_octaves(x, fs, frequencies, fraction=3, order=order, purge=purge, zero_phase=zero_phase)



    def bandpass_fractional_octaves(x, fs, frequencies, fraction=None, order=8, purge=False, zero_phase=False):
    """Apply 1/N-octave bandpass filters.
    :param x: Instantaneous signal :math:`x(t)`.
    :param fs: Sample frequency.
    :param frequencies: Frequencies. Either instance of :class:`OctaveBand`, or array along with fs.
    :param order: Filter order.
    :param purge: Discard bands of which the upper corner frequency is above the Nyquist frequency.
    :param zero_phase: Prevent phase error by filtering in both directions (filtfilt)
    :returns: Tuple. First element is an instance of :class:`OctaveBand`. The second element an array.
    .. seealso:: :func:`octavepass`
    """
    if not isinstance(frequencies, Frequencies):
    frequencies = OctaveBand(center=frequencies, fraction=fraction)
    return bandpass_frequencies(x, fs, frequencies, order=order, purge=purge, zero_phase=zero_phase)



    def _sosfiltfilt(sos, x, axis=-1, padtype='odd', padlen=None, method='pad', irlen=None):
    """Filtfilt version using Second Order sections. Code is taken from scipy.signal.filtfilt and adapted to make it work with SOS.
    Note that broadcasting does not work.
    """
    from scipy.signal import sosfilt_zi
    from scipy.signal._arraytools import odd_ext, axis_slice, axis_reverse
    x = np.asarray(x)

    if padlen is None:
    edge = 0
    else:
    edge = padlen

    # x's 'axis' dimension must be bigger than edge.
    if x.shape[axis] <= edge:
    raise ValueError("The length of the input vector x must be at least " "padlen, which is %d." % edge)

    if padtype is not None and edge > 0:
    # Make an extension of length `edge` at each
    # end of the input array.
    if padtype == 'even':
    ext = even_ext(x, edge, axis=axis)
    elif padtype == 'odd':
    ext = odd_ext(x, edge, axis=axis)
    else:
    ext = const_ext(x, edge, axis=axis)
    else:
    ext = x

    # Get the steady state of the filter's step response.
    zi = sosfilt_zi(sos)

    # Reshape zi and create x0 so that zi*x0 broadcasts
    # to the correct value for the 'zi' keyword argument
    # to lfilter.
    #zi_shape = [1] * x.ndim
    #zi_shape[axis] = zi.size
    #zi = np.reshape(zi, zi_shape)
    x0 = axis_slice(ext, stop=1, axis=axis)
    # Forward filter.
    (y, zf) = sosfilt(sos, ext, axis=axis, zi=zi * x0)

    # Backward filter.
    # Create y0 so zi*y0 broadcasts appropriately.
    y0 = axis_slice(y, start=-1, axis=axis)
    (y, zf) = sosfilt(sos, axis_reverse(y, axis=axis), axis=axis, zi=zi * y0)

    # Reverse y.
    y = axis_reverse(y, axis=axis)

    if edge > 0:
    # Slice the actual signal from the extended signal.
    y = axis_slice(y, start=edge, stop=-edge, axis=axis)

    return y


    rho = 1.2
    a = 340
    N_b = 1
    R = 1
    r_H = 10
    A = np.pi*R**2
    TA = 287
    M_H = 0.3
    w = M_H*a/R
    n = w/(2*np.pi)

    t = np.linspace(0,0.8,num=40000)
    az = t*2*np.pi*n*N_b

    sin = np.sin(az)
    cos = np.cos(az)


    #Thickness Noise

    F_H = R/r_H
    F_E = 0.00012875807653441588 #Bestimmt für den Propeller aus Paper
    T1 = ((3-M_H*sin)*sin)/((1-M_H*sin)**3)
    T2 = (M_H*(cos**2))/(10*(1-M_H*sin)**4)
    T3 = 50 + 39*(M_H**2) - 45*M_H*sin - 11*(M_H**2)*(sin**2) + 12* (M_H**3) *sin - 18*(M_H**3)*(sin**3)
    T_M = ((M_H**3)/12)*(-T1 + T2 * T3)

    p_T = 0.5 * rho * a**2 * F_H * F_E * T_M


    #Loading Noise

    F_T = (TA/ (rho * a**2))**(3/2) * (1 / (60 * np.sqrt(2) * N_b))
    L = 60 + 30 * M_H**2 * cos**2 - 120 * M_H * sin - 30 * M_H**3 * sin * cos**2 + 80 * M_H**2 * sin**2 + 9 * M_H**4 * sin**2 * cos**2 - 20 * M_H**3 * sin**3
    L_M = cos * (1 - M_H * sin)**(-3) * L

    p_L = 0.5 * rho * a**2 * F_H * F_T * L_M

    #Total

    p_total = p_T + p_L
    plt.figure(1)
    plt.plot(t, p_total)
    plt.title('Signal in time domain')
    plt.xlabel('time [s]')
    plt.ylabel('acoustic pressure [Pa]')

    #fundamental frequency
    ff = n*N_b
    print('ff',ff)

    #Sampling frequency
    T = t[1] - t[0]
    f_s = 1/T
    print('fs',f_s)

    #Trying to get the one third octave frequency spectrum

    test = bandpass_third_octaves(p_total, f_s,frequencies=NOMINAL_THIRD_OCTAVE_CENTER_FREQUENCIES,order=8,purge=False,zero_phase = True)
    a_l = list()
    i = 0
    while i < 34:
    a = max(test[1][i])
    a_l.append(a)
    i+=1

    f = NOMINAL_THIRD_OCTAVE_CENTER_FREQUENCIES
    plt.figure(2)
    plt.bar(f, np.abs(a_l))
    plt.title('Supposed one third octave spectrum of the time signal')
    plt.xlabel('frequency [Hz]')
    plt.ylabel('acoustic pressure [Pa]')
    plt.xlim(0,100)

    #FFT of the time signal p_total

    N = p_total.size
    f = np.linspace(0, 1/T, N)
    f_scaled = f[:N // 2]
    p_total -= np.mean(p_total)
    fft = np.fft.fft(p_total)
    fft_scaled = np.abs(fft)[:N // 2] * 2 / N
    plt.figure(3)
    plt.bar(f_scaled, fft_scaled)
    plt.title('Signal in frequency domain')
    plt.xlabel('frequency [Hz]')
    plt.ylabel('acoustic pressure [Pa]')
    plt.xlim(0,100)
    plt.show()









    share|improve this question


























      0












      0








      0








      I am trying to get a third-octave frequency spectrum of a time signal.



      The time signal is the acoustic pressure of rotational rotor noise which is harmonic. Its fundamental frequency is ff = n * N_b and for that reason, all frequencies should be multiples of ff.



      Using fft I get the expected result:
      Multiples of the fundamental frequency are the relevant frequencies in the spectrum.



      To get the third-octave frequency spectrum I wanted to use python acoustics, but the result of the function bandpass_third_octaves is not what I expected.



      I expected the peaks from the fft frequency spectrum to be simply shifted to the third-octave centre frequencies with an adjusted amplitude. At least that is what I would like to get.



      I think I interpret the output of bandpass_third_octaves incorrectly. Its output is a tuple containing the third-octave frequencies and a list of arrays which are supposed to contain the amplitude values as far as I know.



      I currently use the arrays' maximum value as resulting amplitude because it works better than using the sum of it. It is possible that this interpretation is my mistake.



      I would appreciate any help. There is no need for me to use python acoustics. Any solution to get the third-octave frequency spectrum would be awesome.



      Edit: Using the mean instead of the maximum produces better results, but I am still not completely satisfied with it.



      Signal in time domain, frequency domain and supposed third octave spectrum



      import matplotlib.pyplot as plt
      import numpy as np
      from scipy.sparse import spdiags
      from scipy.signal import butter, lfilter, freqz, filtfilt, sosfilt

      import acoustics.octave
      #from acoustics.octave import REFERENCE

      import acoustics.bands
      from scipy.signal import hilbert
      from acoustics.standards.iso_tr_25417_2007 import REFERENCE_PRESSURE
      from acoustics.standards.iec_61672_1_2013 import (NOMINAL_OCTAVE_CENTER_FREQUENCIES,
      NOMINAL_THIRD_OCTAVE_CENTER_FREQUENCIES)

      try:
      from pyfftw.interfaces.numpy_fft import rfft
      except ImportError:
      from numpy.fft import rfft


      def bandpass_filter(lowcut, highcut, fs, order=8, output='sos'):
      """Band-pass filter.
      :param lowcut: Lower cut-off frequency
      :param highcut: Upper cut-off frequency
      :param fs: Sample frequency
      :param order: Filter order
      :param output: Output type. 'ba', 'zpk', 'sos'. Default is 'sos'. See also :func:`scipy.signal.butter`.
      :returns: Returned value depends on `output`.
      A Butterworth filter is used.
      .. seealso:: :func:`scipy.signal.butter`.
      """
      nyq = 0.5 * fs
      low = lowcut / nyq
      high = highcut / nyq
      output = butter(order / 2, [low, high], btype='band', output=output)
      return output



      def bandpass(signal, lowcut, highcut, fs, order=8, zero_phase=False):
      """Filter signal with band-pass filter.
      :param signal: Signal
      :param lowcut: Lower cut-off frequency
      :param highcut: Upper cut-off frequency
      :param fs: Sample frequency
      :param order: Filter order
      :param zero_phase: Prevent phase error by filtering in both directions (filtfilt)
      A Butterworth filter is used. Filtering is done with second-order sections.
      .. seealso:: :func:`bandpass_filter` for the filter that is used.
      """
      sos = bandpass_filter(lowcut, highcut, fs, order, output='sos')
      if zero_phase:
      return _sosfiltfilt(sos, signal)
      else:
      return sosfilt(sos, signal)


      class Frequencies:
      """
      Object describing frequency bands.
      """

      def __init__(self, center, lower, upper, bandwidth=None):

      self.center = np.asarray(center)
      """
      Center frequencies.
      """

      self.lower = np.asarray(lower)
      """
      Lower frequencies.
      """

      self.upper = np.asarray(upper)
      """
      Upper frequencies.
      """

      self.bandwidth = np.asarray(bandwidth) if bandwidth is not None else np.asarray(self.upper) - np.asarray(
      self.lower)
      """
      Bandwidth.
      """

      def __iter__(self):
      for i in range(len(self.center)):
      yield self[i]

      def __len__(self):
      return len(self.center)

      def __str__(self):
      return str(self.center)

      def __repr__(self):
      return "Frequencies()".format(str(self.center))

      def angular(self):
      """Angular center frequency in radians per second.
      """
      return 2.0 * np.pi * self.center



      class OctaveBand(Frequencies):
      """Fractional-octave band spectrum.
      """

      def __init__(self, center=None, fstart=None, fstop=None, nbands=None, fraction=1,
      reference=acoustics.octave.REFERENCE):

      if center is not None:
      try:
      nbands = len(center)
      except TypeError:
      center = [center]
      center = np.asarray(center)
      indices = acoustics.octave.index_of_frequency(center, fraction=fraction, ref=reference)
      elif fstart is not None and fstop is not None:
      nstart = acoustics.octave.index_of_frequency(fstart, fraction=fraction, ref=reference)
      nstop = acoustics.octave.index_of_frequency(fstop, fraction=fraction, ref=reference)
      indices = np.arange(nstart, nstop + 1)
      elif fstart is not None and nbands is not None:
      nstart = acoustics.octave.index_of_frequency(fstart, fraction=fraction, ref=reference)
      indices = np.arange(nstart, nstart + nbands)
      elif fstop is not None and nbands is not None:
      nstop = acoustics.octave.index_of_frequency(fstop, fraction=fraction, ref=reference)
      indices = np.arange(nstop - nbands, nstop)
      else:
      raise ValueError("Insufficient parameters. Cannot determine fstart and/or fstop.")

      center = acoustics.octave.exact_center_frequency(None, fraction=fraction, n=indices, ref=reference)
      lower = acoustics.octave.lower_frequency(center, fraction=fraction)
      upper = acoustics.octave.upper_frequency(center, fraction=fraction)
      bandwidth = upper - lower
      nominal = acoustics.octave.nominal_center_frequency(None, fraction, indices)

      super(OctaveBand, self).__init__(center, lower, upper, bandwidth)

      self.fraction = fraction
      """Fraction of fractional-octave filter.
      """

      self.reference = reference
      """Reference center frequency.
      """

      self.nominal = nominal
      """Nominal center frequencies.
      """

      def __getitem__(self, key):
      return type(self)(center=self.center[key], fraction=self.fraction, reference=self.reference)

      def __repr__(self):
      return "OctaveBand()".format(str(self.center))




      def bandpass_frequencies(x, fs, frequencies, order=8, purge=False, zero_phase=False):
      """"Apply bandpass filters for frequencies
      :param x: Instantaneous signal :math:`x(t)`.
      :param fs: Sample frequency.
      :param frequencies: Frequencies. Instance of :class:`Frequencies`.
      :param order: Filter order.
      :param purge: Discard bands of which the upper corner frequency is above the Nyquist frequency.
      :param zero_phase: Prevent phase error by filtering in both directions (filtfilt)
      :returns: Tuple. First element is an instance of :class:`OctaveBand`. The second element an array.
      """
      if purge:
      frequencies = frequencies[frequencies.upper < fs / 2.0]
      return frequencies, np.array(
      [bandpass(x, band.lower, band.upper, fs, order, zero_phase=zero_phase) for band in frequencies])




      def bandpass_third_octaves(x, fs, frequencies=NOMINAL_THIRD_OCTAVE_CENTER_FREQUENCIES, order=8, purge=False,
      zero_phase=False):
      """Apply 1/3-octave bandpass filters.
      :param x: Instantaneous signal :math:`x(t)`.
      :param fs: Sample frequency.
      :param frequencies: Frequencies.
      :param order: Filter order.
      :param purge: Discard bands of which the upper corner frequency is above the Nyquist frequency.
      :param zero_phase: Prevent phase error by filtering in both directions (filtfilt)
      :returns: Tuple. First element is an instance of :class:`OctaveBand`. The second element an array.
      .. seealso:: :func:`octavepass`
      """
      return bandpass_fractional_octaves(x, fs, frequencies, fraction=3, order=order, purge=purge, zero_phase=zero_phase)



      def bandpass_fractional_octaves(x, fs, frequencies, fraction=None, order=8, purge=False, zero_phase=False):
      """Apply 1/N-octave bandpass filters.
      :param x: Instantaneous signal :math:`x(t)`.
      :param fs: Sample frequency.
      :param frequencies: Frequencies. Either instance of :class:`OctaveBand`, or array along with fs.
      :param order: Filter order.
      :param purge: Discard bands of which the upper corner frequency is above the Nyquist frequency.
      :param zero_phase: Prevent phase error by filtering in both directions (filtfilt)
      :returns: Tuple. First element is an instance of :class:`OctaveBand`. The second element an array.
      .. seealso:: :func:`octavepass`
      """
      if not isinstance(frequencies, Frequencies):
      frequencies = OctaveBand(center=frequencies, fraction=fraction)
      return bandpass_frequencies(x, fs, frequencies, order=order, purge=purge, zero_phase=zero_phase)



      def _sosfiltfilt(sos, x, axis=-1, padtype='odd', padlen=None, method='pad', irlen=None):
      """Filtfilt version using Second Order sections. Code is taken from scipy.signal.filtfilt and adapted to make it work with SOS.
      Note that broadcasting does not work.
      """
      from scipy.signal import sosfilt_zi
      from scipy.signal._arraytools import odd_ext, axis_slice, axis_reverse
      x = np.asarray(x)

      if padlen is None:
      edge = 0
      else:
      edge = padlen

      # x's 'axis' dimension must be bigger than edge.
      if x.shape[axis] <= edge:
      raise ValueError("The length of the input vector x must be at least " "padlen, which is %d." % edge)

      if padtype is not None and edge > 0:
      # Make an extension of length `edge` at each
      # end of the input array.
      if padtype == 'even':
      ext = even_ext(x, edge, axis=axis)
      elif padtype == 'odd':
      ext = odd_ext(x, edge, axis=axis)
      else:
      ext = const_ext(x, edge, axis=axis)
      else:
      ext = x

      # Get the steady state of the filter's step response.
      zi = sosfilt_zi(sos)

      # Reshape zi and create x0 so that zi*x0 broadcasts
      # to the correct value for the 'zi' keyword argument
      # to lfilter.
      #zi_shape = [1] * x.ndim
      #zi_shape[axis] = zi.size
      #zi = np.reshape(zi, zi_shape)
      x0 = axis_slice(ext, stop=1, axis=axis)
      # Forward filter.
      (y, zf) = sosfilt(sos, ext, axis=axis, zi=zi * x0)

      # Backward filter.
      # Create y0 so zi*y0 broadcasts appropriately.
      y0 = axis_slice(y, start=-1, axis=axis)
      (y, zf) = sosfilt(sos, axis_reverse(y, axis=axis), axis=axis, zi=zi * y0)

      # Reverse y.
      y = axis_reverse(y, axis=axis)

      if edge > 0:
      # Slice the actual signal from the extended signal.
      y = axis_slice(y, start=edge, stop=-edge, axis=axis)

      return y


      rho = 1.2
      a = 340
      N_b = 1
      R = 1
      r_H = 10
      A = np.pi*R**2
      TA = 287
      M_H = 0.3
      w = M_H*a/R
      n = w/(2*np.pi)

      t = np.linspace(0,0.8,num=40000)
      az = t*2*np.pi*n*N_b

      sin = np.sin(az)
      cos = np.cos(az)


      #Thickness Noise

      F_H = R/r_H
      F_E = 0.00012875807653441588 #Bestimmt für den Propeller aus Paper
      T1 = ((3-M_H*sin)*sin)/((1-M_H*sin)**3)
      T2 = (M_H*(cos**2))/(10*(1-M_H*sin)**4)
      T3 = 50 + 39*(M_H**2) - 45*M_H*sin - 11*(M_H**2)*(sin**2) + 12* (M_H**3) *sin - 18*(M_H**3)*(sin**3)
      T_M = ((M_H**3)/12)*(-T1 + T2 * T3)

      p_T = 0.5 * rho * a**2 * F_H * F_E * T_M


      #Loading Noise

      F_T = (TA/ (rho * a**2))**(3/2) * (1 / (60 * np.sqrt(2) * N_b))
      L = 60 + 30 * M_H**2 * cos**2 - 120 * M_H * sin - 30 * M_H**3 * sin * cos**2 + 80 * M_H**2 * sin**2 + 9 * M_H**4 * sin**2 * cos**2 - 20 * M_H**3 * sin**3
      L_M = cos * (1 - M_H * sin)**(-3) * L

      p_L = 0.5 * rho * a**2 * F_H * F_T * L_M

      #Total

      p_total = p_T + p_L
      plt.figure(1)
      plt.plot(t, p_total)
      plt.title('Signal in time domain')
      plt.xlabel('time [s]')
      plt.ylabel('acoustic pressure [Pa]')

      #fundamental frequency
      ff = n*N_b
      print('ff',ff)

      #Sampling frequency
      T = t[1] - t[0]
      f_s = 1/T
      print('fs',f_s)

      #Trying to get the one third octave frequency spectrum

      test = bandpass_third_octaves(p_total, f_s,frequencies=NOMINAL_THIRD_OCTAVE_CENTER_FREQUENCIES,order=8,purge=False,zero_phase = True)
      a_l = list()
      i = 0
      while i < 34:
      a = max(test[1][i])
      a_l.append(a)
      i+=1

      f = NOMINAL_THIRD_OCTAVE_CENTER_FREQUENCIES
      plt.figure(2)
      plt.bar(f, np.abs(a_l))
      plt.title('Supposed one third octave spectrum of the time signal')
      plt.xlabel('frequency [Hz]')
      plt.ylabel('acoustic pressure [Pa]')
      plt.xlim(0,100)

      #FFT of the time signal p_total

      N = p_total.size
      f = np.linspace(0, 1/T, N)
      f_scaled = f[:N // 2]
      p_total -= np.mean(p_total)
      fft = np.fft.fft(p_total)
      fft_scaled = np.abs(fft)[:N // 2] * 2 / N
      plt.figure(3)
      plt.bar(f_scaled, fft_scaled)
      plt.title('Signal in frequency domain')
      plt.xlabel('frequency [Hz]')
      plt.ylabel('acoustic pressure [Pa]')
      plt.xlim(0,100)
      plt.show()









      share|improve this question
















      I am trying to get a third-octave frequency spectrum of a time signal.



      The time signal is the acoustic pressure of rotational rotor noise which is harmonic. Its fundamental frequency is ff = n * N_b and for that reason, all frequencies should be multiples of ff.



      Using fft I get the expected result:
      Multiples of the fundamental frequency are the relevant frequencies in the spectrum.



      To get the third-octave frequency spectrum I wanted to use python acoustics, but the result of the function bandpass_third_octaves is not what I expected.



      I expected the peaks from the fft frequency spectrum to be simply shifted to the third-octave centre frequencies with an adjusted amplitude. At least that is what I would like to get.



      I think I interpret the output of bandpass_third_octaves incorrectly. Its output is a tuple containing the third-octave frequencies and a list of arrays which are supposed to contain the amplitude values as far as I know.



      I currently use the arrays' maximum value as resulting amplitude because it works better than using the sum of it. It is possible that this interpretation is my mistake.



      I would appreciate any help. There is no need for me to use python acoustics. Any solution to get the third-octave frequency spectrum would be awesome.



      Edit: Using the mean instead of the maximum produces better results, but I am still not completely satisfied with it.



      Signal in time domain, frequency domain and supposed third octave spectrum



      import matplotlib.pyplot as plt
      import numpy as np
      from scipy.sparse import spdiags
      from scipy.signal import butter, lfilter, freqz, filtfilt, sosfilt

      import acoustics.octave
      #from acoustics.octave import REFERENCE

      import acoustics.bands
      from scipy.signal import hilbert
      from acoustics.standards.iso_tr_25417_2007 import REFERENCE_PRESSURE
      from acoustics.standards.iec_61672_1_2013 import (NOMINAL_OCTAVE_CENTER_FREQUENCIES,
      NOMINAL_THIRD_OCTAVE_CENTER_FREQUENCIES)

      try:
      from pyfftw.interfaces.numpy_fft import rfft
      except ImportError:
      from numpy.fft import rfft


      def bandpass_filter(lowcut, highcut, fs, order=8, output='sos'):
      """Band-pass filter.
      :param lowcut: Lower cut-off frequency
      :param highcut: Upper cut-off frequency
      :param fs: Sample frequency
      :param order: Filter order
      :param output: Output type. 'ba', 'zpk', 'sos'. Default is 'sos'. See also :func:`scipy.signal.butter`.
      :returns: Returned value depends on `output`.
      A Butterworth filter is used.
      .. seealso:: :func:`scipy.signal.butter`.
      """
      nyq = 0.5 * fs
      low = lowcut / nyq
      high = highcut / nyq
      output = butter(order / 2, [low, high], btype='band', output=output)
      return output



      def bandpass(signal, lowcut, highcut, fs, order=8, zero_phase=False):
      """Filter signal with band-pass filter.
      :param signal: Signal
      :param lowcut: Lower cut-off frequency
      :param highcut: Upper cut-off frequency
      :param fs: Sample frequency
      :param order: Filter order
      :param zero_phase: Prevent phase error by filtering in both directions (filtfilt)
      A Butterworth filter is used. Filtering is done with second-order sections.
      .. seealso:: :func:`bandpass_filter` for the filter that is used.
      """
      sos = bandpass_filter(lowcut, highcut, fs, order, output='sos')
      if zero_phase:
      return _sosfiltfilt(sos, signal)
      else:
      return sosfilt(sos, signal)


      class Frequencies:
      """
      Object describing frequency bands.
      """

      def __init__(self, center, lower, upper, bandwidth=None):

      self.center = np.asarray(center)
      """
      Center frequencies.
      """

      self.lower = np.asarray(lower)
      """
      Lower frequencies.
      """

      self.upper = np.asarray(upper)
      """
      Upper frequencies.
      """

      self.bandwidth = np.asarray(bandwidth) if bandwidth is not None else np.asarray(self.upper) - np.asarray(
      self.lower)
      """
      Bandwidth.
      """

      def __iter__(self):
      for i in range(len(self.center)):
      yield self[i]

      def __len__(self):
      return len(self.center)

      def __str__(self):
      return str(self.center)

      def __repr__(self):
      return "Frequencies()".format(str(self.center))

      def angular(self):
      """Angular center frequency in radians per second.
      """
      return 2.0 * np.pi * self.center



      class OctaveBand(Frequencies):
      """Fractional-octave band spectrum.
      """

      def __init__(self, center=None, fstart=None, fstop=None, nbands=None, fraction=1,
      reference=acoustics.octave.REFERENCE):

      if center is not None:
      try:
      nbands = len(center)
      except TypeError:
      center = [center]
      center = np.asarray(center)
      indices = acoustics.octave.index_of_frequency(center, fraction=fraction, ref=reference)
      elif fstart is not None and fstop is not None:
      nstart = acoustics.octave.index_of_frequency(fstart, fraction=fraction, ref=reference)
      nstop = acoustics.octave.index_of_frequency(fstop, fraction=fraction, ref=reference)
      indices = np.arange(nstart, nstop + 1)
      elif fstart is not None and nbands is not None:
      nstart = acoustics.octave.index_of_frequency(fstart, fraction=fraction, ref=reference)
      indices = np.arange(nstart, nstart + nbands)
      elif fstop is not None and nbands is not None:
      nstop = acoustics.octave.index_of_frequency(fstop, fraction=fraction, ref=reference)
      indices = np.arange(nstop - nbands, nstop)
      else:
      raise ValueError("Insufficient parameters. Cannot determine fstart and/or fstop.")

      center = acoustics.octave.exact_center_frequency(None, fraction=fraction, n=indices, ref=reference)
      lower = acoustics.octave.lower_frequency(center, fraction=fraction)
      upper = acoustics.octave.upper_frequency(center, fraction=fraction)
      bandwidth = upper - lower
      nominal = acoustics.octave.nominal_center_frequency(None, fraction, indices)

      super(OctaveBand, self).__init__(center, lower, upper, bandwidth)

      self.fraction = fraction
      """Fraction of fractional-octave filter.
      """

      self.reference = reference
      """Reference center frequency.
      """

      self.nominal = nominal
      """Nominal center frequencies.
      """

      def __getitem__(self, key):
      return type(self)(center=self.center[key], fraction=self.fraction, reference=self.reference)

      def __repr__(self):
      return "OctaveBand()".format(str(self.center))




      def bandpass_frequencies(x, fs, frequencies, order=8, purge=False, zero_phase=False):
      """"Apply bandpass filters for frequencies
      :param x: Instantaneous signal :math:`x(t)`.
      :param fs: Sample frequency.
      :param frequencies: Frequencies. Instance of :class:`Frequencies`.
      :param order: Filter order.
      :param purge: Discard bands of which the upper corner frequency is above the Nyquist frequency.
      :param zero_phase: Prevent phase error by filtering in both directions (filtfilt)
      :returns: Tuple. First element is an instance of :class:`OctaveBand`. The second element an array.
      """
      if purge:
      frequencies = frequencies[frequencies.upper < fs / 2.0]
      return frequencies, np.array(
      [bandpass(x, band.lower, band.upper, fs, order, zero_phase=zero_phase) for band in frequencies])




      def bandpass_third_octaves(x, fs, frequencies=NOMINAL_THIRD_OCTAVE_CENTER_FREQUENCIES, order=8, purge=False,
      zero_phase=False):
      """Apply 1/3-octave bandpass filters.
      :param x: Instantaneous signal :math:`x(t)`.
      :param fs: Sample frequency.
      :param frequencies: Frequencies.
      :param order: Filter order.
      :param purge: Discard bands of which the upper corner frequency is above the Nyquist frequency.
      :param zero_phase: Prevent phase error by filtering in both directions (filtfilt)
      :returns: Tuple. First element is an instance of :class:`OctaveBand`. The second element an array.
      .. seealso:: :func:`octavepass`
      """
      return bandpass_fractional_octaves(x, fs, frequencies, fraction=3, order=order, purge=purge, zero_phase=zero_phase)



      def bandpass_fractional_octaves(x, fs, frequencies, fraction=None, order=8, purge=False, zero_phase=False):
      """Apply 1/N-octave bandpass filters.
      :param x: Instantaneous signal :math:`x(t)`.
      :param fs: Sample frequency.
      :param frequencies: Frequencies. Either instance of :class:`OctaveBand`, or array along with fs.
      :param order: Filter order.
      :param purge: Discard bands of which the upper corner frequency is above the Nyquist frequency.
      :param zero_phase: Prevent phase error by filtering in both directions (filtfilt)
      :returns: Tuple. First element is an instance of :class:`OctaveBand`. The second element an array.
      .. seealso:: :func:`octavepass`
      """
      if not isinstance(frequencies, Frequencies):
      frequencies = OctaveBand(center=frequencies, fraction=fraction)
      return bandpass_frequencies(x, fs, frequencies, order=order, purge=purge, zero_phase=zero_phase)



      def _sosfiltfilt(sos, x, axis=-1, padtype='odd', padlen=None, method='pad', irlen=None):
      """Filtfilt version using Second Order sections. Code is taken from scipy.signal.filtfilt and adapted to make it work with SOS.
      Note that broadcasting does not work.
      """
      from scipy.signal import sosfilt_zi
      from scipy.signal._arraytools import odd_ext, axis_slice, axis_reverse
      x = np.asarray(x)

      if padlen is None:
      edge = 0
      else:
      edge = padlen

      # x's 'axis' dimension must be bigger than edge.
      if x.shape[axis] <= edge:
      raise ValueError("The length of the input vector x must be at least " "padlen, which is %d." % edge)

      if padtype is not None and edge > 0:
      # Make an extension of length `edge` at each
      # end of the input array.
      if padtype == 'even':
      ext = even_ext(x, edge, axis=axis)
      elif padtype == 'odd':
      ext = odd_ext(x, edge, axis=axis)
      else:
      ext = const_ext(x, edge, axis=axis)
      else:
      ext = x

      # Get the steady state of the filter's step response.
      zi = sosfilt_zi(sos)

      # Reshape zi and create x0 so that zi*x0 broadcasts
      # to the correct value for the 'zi' keyword argument
      # to lfilter.
      #zi_shape = [1] * x.ndim
      #zi_shape[axis] = zi.size
      #zi = np.reshape(zi, zi_shape)
      x0 = axis_slice(ext, stop=1, axis=axis)
      # Forward filter.
      (y, zf) = sosfilt(sos, ext, axis=axis, zi=zi * x0)

      # Backward filter.
      # Create y0 so zi*y0 broadcasts appropriately.
      y0 = axis_slice(y, start=-1, axis=axis)
      (y, zf) = sosfilt(sos, axis_reverse(y, axis=axis), axis=axis, zi=zi * y0)

      # Reverse y.
      y = axis_reverse(y, axis=axis)

      if edge > 0:
      # Slice the actual signal from the extended signal.
      y = axis_slice(y, start=edge, stop=-edge, axis=axis)

      return y


      rho = 1.2
      a = 340
      N_b = 1
      R = 1
      r_H = 10
      A = np.pi*R**2
      TA = 287
      M_H = 0.3
      w = M_H*a/R
      n = w/(2*np.pi)

      t = np.linspace(0,0.8,num=40000)
      az = t*2*np.pi*n*N_b

      sin = np.sin(az)
      cos = np.cos(az)


      #Thickness Noise

      F_H = R/r_H
      F_E = 0.00012875807653441588 #Bestimmt für den Propeller aus Paper
      T1 = ((3-M_H*sin)*sin)/((1-M_H*sin)**3)
      T2 = (M_H*(cos**2))/(10*(1-M_H*sin)**4)
      T3 = 50 + 39*(M_H**2) - 45*M_H*sin - 11*(M_H**2)*(sin**2) + 12* (M_H**3) *sin - 18*(M_H**3)*(sin**3)
      T_M = ((M_H**3)/12)*(-T1 + T2 * T3)

      p_T = 0.5 * rho * a**2 * F_H * F_E * T_M


      #Loading Noise

      F_T = (TA/ (rho * a**2))**(3/2) * (1 / (60 * np.sqrt(2) * N_b))
      L = 60 + 30 * M_H**2 * cos**2 - 120 * M_H * sin - 30 * M_H**3 * sin * cos**2 + 80 * M_H**2 * sin**2 + 9 * M_H**4 * sin**2 * cos**2 - 20 * M_H**3 * sin**3
      L_M = cos * (1 - M_H * sin)**(-3) * L

      p_L = 0.5 * rho * a**2 * F_H * F_T * L_M

      #Total

      p_total = p_T + p_L
      plt.figure(1)
      plt.plot(t, p_total)
      plt.title('Signal in time domain')
      plt.xlabel('time [s]')
      plt.ylabel('acoustic pressure [Pa]')

      #fundamental frequency
      ff = n*N_b
      print('ff',ff)

      #Sampling frequency
      T = t[1] - t[0]
      f_s = 1/T
      print('fs',f_s)

      #Trying to get the one third octave frequency spectrum

      test = bandpass_third_octaves(p_total, f_s,frequencies=NOMINAL_THIRD_OCTAVE_CENTER_FREQUENCIES,order=8,purge=False,zero_phase = True)
      a_l = list()
      i = 0
      while i < 34:
      a = max(test[1][i])
      a_l.append(a)
      i+=1

      f = NOMINAL_THIRD_OCTAVE_CENTER_FREQUENCIES
      plt.figure(2)
      plt.bar(f, np.abs(a_l))
      plt.title('Supposed one third octave spectrum of the time signal')
      plt.xlabel('frequency [Hz]')
      plt.ylabel('acoustic pressure [Pa]')
      plt.xlim(0,100)

      #FFT of the time signal p_total

      N = p_total.size
      f = np.linspace(0, 1/T, N)
      f_scaled = f[:N // 2]
      p_total -= np.mean(p_total)
      fft = np.fft.fft(p_total)
      fft_scaled = np.abs(fft)[:N // 2] * 2 / N
      plt.figure(3)
      plt.bar(f_scaled, fft_scaled)
      plt.title('Signal in frequency domain')
      plt.xlabel('frequency [Hz]')
      plt.ylabel('acoustic pressure [Pa]')
      plt.xlim(0,100)
      plt.show()






      python signal-processing fft bandpass-filter






      share|improve this question















      share|improve this question













      share|improve this question




      share|improve this question








      edited Mar 7 at 12:37









      Joey Mallone

      2,26561933




      2,26561933










      asked Mar 7 at 9:05









      LarzebLarzeb

      64




      64






















          0






          active

          oldest

          votes











          Your Answer






          StackExchange.ifUsing("editor", function ()
          StackExchange.using("externalEditor", function ()
          StackExchange.using("snippets", function ()
          StackExchange.snippets.init();
          );
          );
          , "code-snippets");

          StackExchange.ready(function()
          var channelOptions =
          tags: "".split(" "),
          id: "1"
          ;
          initTagRenderer("".split(" "), "".split(" "), channelOptions);

          StackExchange.using("externalEditor", function()
          // Have to fire editor after snippets, if snippets enabled
          if (StackExchange.settings.snippets.snippetsEnabled)
          StackExchange.using("snippets", function()
          createEditor();
          );

          else
          createEditor();

          );

          function createEditor()
          StackExchange.prepareEditor(
          heartbeatType: 'answer',
          autoActivateHeartbeat: false,
          convertImagesToLinks: true,
          noModals: true,
          showLowRepImageUploadWarning: true,
          reputationToPostImages: 10,
          bindNavPrevention: true,
          postfix: "",
          imageUploader:
          brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
          contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
          allowUrls: true
          ,
          onDemand: true,
          discardSelector: ".discard-answer"
          ,immediatelyShowMarkdownHelp:true
          );



          );













          draft saved

          draft discarded


















          StackExchange.ready(
          function ()
          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f55039842%2fthird-octave-frequency-spectrum-with-python%23new-answer', 'question_page');

          );

          Post as a guest















          Required, but never shown

























          0






          active

          oldest

          votes








          0






          active

          oldest

          votes









          active

          oldest

          votes






          active

          oldest

          votes















          draft saved

          draft discarded
















































          Thanks for contributing an answer to Stack Overflow!


          • Please be sure to answer the question. Provide details and share your research!

          But avoid


          • Asking for help, clarification, or responding to other answers.

          • Making statements based on opinion; back them up with references or personal experience.

          To learn more, see our tips on writing great answers.




          draft saved


          draft discarded














          StackExchange.ready(
          function ()
          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f55039842%2fthird-octave-frequency-spectrum-with-python%23new-answer', 'question_page');

          );

          Post as a guest















          Required, but never shown





















































          Required, but never shown














          Required, but never shown












          Required, but never shown







          Required, but never shown

































          Required, but never shown














          Required, but never shown












          Required, but never shown







          Required, but never shown







          Popular posts from this blog

          1928 у кіно

          Захаров Федір Захарович

          Ель Греко