Exemplo n.º 1
0
def kernel_cell(n, m):
    """ Функция отдает двумерное сверточное ядро размером (m x n) на основании максимально плоского фильтра"""
    w_inter_freq = np.array(flattop(n))
    w_inter_time = np.array(flattop(m))
    kernel_in = np.ones((m, n), dtype=np.float64)
    for i in range(m):
        kernel_in[i] = w_inter_freq
    for i in range(n):
        kernel_in[:, i] = kernel_in[:, i] * w_inter_time
    kernel_in = kernel_in / np.sum(kernel_in)
    return kernel_in
Exemplo n.º 2
0
 def test_basic(self):
     assert_allclose(windows.flattop(6, sym=False),
                     [-0.000421051, -0.051263156, 0.19821053, 1.0,
                      0.19821053, -0.051263156])
     assert_allclose(windows.flattop(7, sym=False),
                     [-0.000421051, -0.03684078115492348,
                      0.01070371671615342, 0.7808739149387698,
                      0.7808739149387698, 0.01070371671615342,
                      -0.03684078115492348])
     assert_allclose(windows.flattop(6),
                     [-0.000421051, -0.0677142520762119, 0.6068721525762117,
                      0.6068721525762117, -0.0677142520762119,
                      -0.000421051])
     assert_allclose(windows.flattop(7, True),
                     [-0.000421051, -0.051263156, 0.19821053, 1.0,
                      0.19821053, -0.051263156, -0.000421051])
Exemplo n.º 3
0
 def test_basic(self):
     assert_allclose(windows.flattop(6, sym=False),
                     [-0.000421051, -0.051263156, 0.19821053, 1.0,
                      0.19821053, -0.051263156])
     assert_allclose(windows.flattop(7, sym=False),
                     [-0.000421051, -0.03684078115492348,
                      0.01070371671615342, 0.7808739149387698,
                      0.7808739149387698, 0.01070371671615342,
                      -0.03684078115492348])
     assert_allclose(windows.flattop(6),
                     [-0.000421051, -0.0677142520762119, 0.6068721525762117,
                      0.6068721525762117, -0.0677142520762119,
                      -0.000421051])
     assert_allclose(windows.flattop(7, True),
                     [-0.000421051, -0.051263156, 0.19821053, 1.0,
                      0.19821053, -0.051263156, -0.000421051])
Exemplo n.º 4
0
def get_fft(data, num_samples):

    # Get the signal length
    n = num_samples

    w = np.hanning(n)
    w = flattop(n, False)

    # Get time resolution
    dt = 1 / float(fs)

    # Perform real fft
    fft_output = np.fft.rfft(data)

    # Calculate frequency bins
    rfreqs = np.fft.rfftfreq(n, dt)

    # Take only magnitude of spectrum
    fft_mag = np.abs(fft_output)

    # Double everything because of alias at Nyquist
    fft_mag = fft_mag * 2 / n

    # Scale magnitudes to log scale
    MAG_dB = 20 * np.log10(fft_mag / max(fft_mag))

    return np.array([np.array(MAG_dB), np.array(rfreqs)])
Exemplo n.º 5
0
def compute_frequency(sig, fs):
    N = len(sig)
    windowed = sig * windows.flattop(N, sym=False)
    X = log(abs(rfft(windowed)))

    hps = copy(X)
    for h in arange(2, 9):
        dec = decimate(X, h)
        hps[:len(dec)] += dec
    i_peak = argmax(hps)

    return fs * i_peak / N
Exemplo n.º 6
0
    def process(self, data):
        data = deepcopy(data)

        winData = data.data
        if self.windowType == FourierTransform.WindowTypes.Hann:
            winData *= windows.hann(len(winData), sym=False)
        elif self.windowType == FourierTransform.WindowTypes.Blackman:
            winData *= windows.blackman(len(winData), sym=False)
        elif self.windowType == FourierTransform.WindowTypes.Flattop:
            winData *= windows.flattop(len(winData), sym=False)
        elif self.windowType == FourierTransform.WindowTypes.Tukey:
            winData *= windows.tukey(len(winData), sym=False, alpha=self.alpha)

        data.data = np.fft.rfft(winData, axis=0, norm='ortho')
        data.axes[0] = np.fft.rfftfreq(len(data.axes[0]),
                                       np.mean(np.diff(data.axes[0])))
        return data
Exemplo n.º 7
0
def get_fft_window(window_type, window_length):
    # Generate the window with the right number of points
    window = None
    if window_type == "Bartlett":
        window = windows.bartlett(window_length)
    if window_type == "Blackman":
        window = windows.blackman(window_length)
    if window_type == "Blackman Harris":
        window = windows.blackmanharris(window_length)
    if window_type == "Flat Top":
        window = windows.flattop(window_length)
    if window_type == "Hamming":
        window = windows.hamming(window_length)
    if window_type == "Hanning":
        window = windows.hann(window_length)

    # If no window matched, use a rectangular window
    if window is None:
        window = np.ones(window_length)

    # Return the window
    return window
Exemplo n.º 8
0
"""*. Сформувати вектор відліків часу тривалістю 10 с для частоти дискретизації 128 Гц. Сформувати сигнал
послідовності прямокутних імпульсів. Сформувати відліки одної віконної функції тривалості 0.2 секунди та 2 секунди.
Побудувати спектрограми сигналу. Побудувати тривимірні графіки модуля спектральної функції. """
import numpy as np
import matplotlib.pyplot as plt
from scipy.signal.windows import flattop
from scipy.signal import square

duration = 10
sample_rate = 128
time = np.linspace(0, duration, sample_rate * duration, endpoint=False)
freq = np.linspace(0, sample_rate, sample_rate * duration)
frequency = 40

time_shift = 10
window_duration1 = .2
window_duration2 = 2

NFFT1 = int(window_duration1 * sample_rate)
NFFT2 = int(window_duration2 * sample_rate)

window1 = flattop(NFFT1)
window2 = flattop(NFFT2)

x = square(2 * np.pi * time * frequency)
X, Y = np.meshgrid(time, x)
z = np.sin(np.sqrt(X**2 + Y**2))
ax = plt.axes(projection='3d')
ax.plot_surface(time, x, z)
plt.show()
Exemplo n.º 9
0
    def pre_processing(self):
        """
        Complete various pre-processing steps for encoded protein sequences before
        doing any of the DSP-related functions or transformations. Zero-pad
        the sequences, remove any +/- infinity or NAN values, get the approximate
        protein spectra and window function parameter names.

        Parameters
        ----------
        :self (PyDSP object): 
            instance of PyDSP class.
            
        Returns
        -------
        None

        """
        #zero-pad encoded sequences so they are all the same length
        self.protein_seqs = zero_padding(self.protein_seqs)

        #get shape parameters of proteins seqs
        self.num_seqs = self.protein_seqs.shape[0]
        self.signal_len = self.protein_seqs.shape[1]

        #replace any positive or negative infinity or NAN values with 0
        self.protein_seqs[self.protein_seqs == -np.inf] = 0
        self.protein_seqs[self.protein_seqs == np.inf] = 0
        self.protein_seqs[self.protein_seqs == np.nan] = 0

        #replace any NAN's with 0's
        #self.protein_seqs.fillna(0, inplace=True)
        self.protein_seqs = np.nan_to_num(self.protein_seqs)

        #initialise zeros array to store all protein spectra
        self.fft_power = np.zeros((self.num_seqs, self.signal_len))
        self.fft_real = np.zeros((self.num_seqs, self.signal_len))
        self.fft_imag = np.zeros((self.num_seqs, self.signal_len))
        self.fft_abs = np.zeros((self.num_seqs, self.signal_len))

        #list of accepted spectra, window functions and filters
        all_spectra = ['power', 'absolute', 'real', 'imaginary']
        all_windows = [
            'hamming', 'blackman', 'blackmanharris', 'gaussian', 'bartlett',
            'kaiser', 'barthann', 'bohman', 'chebwin', 'cosine', 'exponential'
            'flattop', 'hann', 'boxcar', 'hanning', 'nuttall', 'parzen',
            'triang', 'tukey'
        ]
        all_filters = [
            'savgol', 'medfilt', 'symiirorder1', 'lfilter', 'hilbert'
        ]

        #set required input parameters, raise error if spectrum is none
        if self.spectrum == None:
            raise ValueError(
                'Invalid input Spectrum type ({}) not available in valid spectra: {}'
                .format(self.spectrum, all_spectra))
        else:
            #get closest correct spectra from user input, if no close match then raise error
            spectra_matches = (get_close_matches(self.spectrum,
                                                 all_spectra,
                                                 cutoff=0.4))

            if spectra_matches == []:
                raise ValueError(
                    'Invalid input Spectrum type ({}) not available in valid spectra: {}'
                    .format(self.spectrum, all_spectra))
            else:
                self.spectra = spectra_matches[0]  #closest match in array

        if self.window_type == None:
            self.window = 1  #window = 1 is the same as applying no window
        else:
            #get closest correct window function from user input
            window_matches = (get_close_matches(self.window,
                                                all_windows,
                                                cutoff=0.4))

            #check if sym=True or sym=False
            #get window function specified by window input parameter, if no match then window = 1
            if window_matches != []:
                if window_matches[0] == 'hamming':
                    self.window = hamming(self.signal_len, sym=True)
                    self.window_type = "hamming"
                elif window_matches[0] == "blackman":
                    self.window = blackman(self.signal_len, sym=True)
                    self.window = "blackman"
                elif window_matches[0] == "blackmanharris":
                    self.window = blackmanharris(self.signal_len,
                                                 sym=True)  #**
                    self.window_type = "blackmanharris"
                elif window_matches[0] == "bartlett":
                    self.window = bartlett(self.signal_len, sym=True)
                    self.window_type = "bartlett"
                elif window_matches[0] == "gaussian":
                    self.window = gaussian(self.signal_len, std=7, sym=True)
                    self.window_type = "gaussian"
                elif window_matches[0] == "kaiser":
                    self.window = kaiser(self.signal_len, beta=14, sym=True)
                    self.window_type = "kaiser"
                elif window_matches[0] == "hanning":
                    self.window = hanning(self.signal_len, sym=True)
                    self.window_type = "hanning"
                elif window_matches[0] == "barthann":
                    self.window = barthann(self.signal_len, sym=True)
                    self.window_type = "barthann"
                elif window_matches[0] == "bohman":
                    self.window = bohman(self.signal_len, sym=True)
                    self.window_type = "bohman"
                elif window_matches[0] == "chebwin":
                    self.window = chebwin(self.signal_len, sym=True)
                    self.window_type = "chebwin"
                elif window_matches[0] == "cosine":
                    self.window = cosine(self.signal_len, sym=True)
                    self.window_type = "cosine"
                elif window_matches[0] == "exponential":
                    self.window = exponential(self.signal_len, sym=True)
                    self.window_type = "exponential"
                elif window_matches[0] == "flattop":
                    self.window = flattop(self.signal_len, sym=True)
                    self.window_type = "flattop"
                elif window_matches[0] == "boxcar":
                    self.window = boxcar(self.signal_len, sym=True)
                    self.window_type = "boxcar"
                elif window_matches[0] == "nuttall":
                    self.window = nuttall(self.signal_len, sym=True)
                    self.window_type = "nuttall"
                elif window_matches[0] == "parzen":
                    self.window = parzen(self.signal_len, sym=True)
                    self.window_type = "parzen"
                elif window_matches[0] == "triang":
                    self.window = triang(self.signal_len, sym=True)
                    self.window_type = "triang"
                elif window_matches[0] == "tukey":
                    self.window = tukey(self.signal_len, sym=True)
                    self.window_type = "tukey"

            else:
                self.window = 1  #window = 1 is the same as applying no window

        #calculate convolution from protein sequences
        if self.convolution is not None:
            if self.window is not None:
                self.convoled_seqs = signal.convolve(
                    self.protein_seqs, self.window, mode='same') / sum(
                        self.window)

        if self.filter != None:
            #get closest correct filter from user input
            filter_matches = (get_close_matches(self.filter,
                                                all_filters,
                                                cutoff=0.4))

            #set filter attribute according to approximate user input
            if filter_matches != []:
                if filter_matches[0] == 'savgol':
                    self.filter = savgol_filter(self.signal_len,
                                                self.signal_len)
                elif filter_matches[0] == 'medfilt':
                    self.filter = medfilt(self.signal_len)
                elif filter_matches[0] == 'symiirorder1':
                    self.filter = symiirorder1(self.signal_len, c0=1, z1=1)
                elif filter_matches[0] == 'lfilter':
                    self.filter = lfilter(self.signal_len)
                elif filter_matches[0] == 'hilbert':
                    self.filter = hilbert(self.signal_len)
            else:
                self.filter = ""  #no filter
Exemplo n.º 10
0
class PyQtGraphPlotter(QtWidgets.QGroupBox):
    @enum.unique
    class WindowTypes(enum.Enum):
        Rectangular = 0
        Hann = 1
        Flattop = 2
        Tukey_5Percent = 3

    windowFunctionMap = {
        WindowTypes.Rectangular:
        lambda M: windows.boxcar(M, sym=False),
        WindowTypes.Hann:
        lambda M: windows.hann(M, sym=False),
        WindowTypes.Flattop:
        lambda M: windows.flattop(M, sym=False),
        WindowTypes.Tukey_5Percent:
        lambda M: windows.tukey(M, sym=False, alpha=0.05),
    }

    dataIsPower = False
    prevDataSet = None
    curDataSet = None

    axes_units = [ureg.dimensionless]
    data_unit = ureg.dimensionless

    def __init__(self, parent=None):
        _style_pg()

        super().__init__(parent)

        pal = self.palette()
        highlightPen = pg.mkPen(
            pal.color(QtGui.QPalette.Highlight).darker(120))
        darkerHighlightPen = pg.mkPen(highlightPen.color().darker(120))
        alphaColor = darkerHighlightPen.color()
        alphaColor.setAlphaF(0.25)
        darkerHighlightPen.setColor(alphaColor)

        self.toolbar = QtWidgets.QToolBar(self)
        self.toolbar.addWidget(QtWidgets.QLabel("Fourier transform window:"))
        self.windowComboBox = QtWidgets.QComboBox(self.toolbar)
        for e in self.WindowTypes:
            self.windowComboBox.addItem(e.name, e)
        self.toolbar.addWidget(self.windowComboBox)
        self.windowComboBox.currentIndexChanged.connect(self._updateFTWindow)

        self.pglwidget = pg.GraphicsLayoutWidget(self)
        self.pglwidget.setBackground(None)

        vbox = QtWidgets.QVBoxLayout(self)
        vbox.addWidget(self.toolbar)
        vbox.addWidget(self.pglwidget)

        self.plot = self.pglwidget.addPlot(row=0, col=0)
        self.ft_plot = self.pglwidget.addPlot(row=1, col=0)

        self.plot.setLabels(title="Data")
        self.ft_plot.setLabels(title="Magnitude spectrum")

        self.plot.showGrid(x=True, y=True)
        self.ft_plot.showGrid(x=True, y=True)

        self._make_plot_background(self.plot)
        self._make_plot_background(self.ft_plot)

        self._lines = []
        self._lines.append(self.plot.plot())
        self._lines.append(self.plot.plot())
        self._lines[0].setPen(darkerHighlightPen)
        self._lines[1].setPen(highlightPen)

        self._ft_lines = []
        self._ft_lines.append(self.ft_plot.plot())
        self._ft_lines.append(self.ft_plot.plot())
        self._ft_lines[0].setPen(darkerHighlightPen)
        self._ft_lines[1].setPen(highlightPen)

        self._lastPlotTime = time.perf_counter()

    def _make_plot_background(self, plot, brush=None):
        if brush is None:
            brush = pg.mkBrush(self.palette().color(QtGui.QPalette.Base))

        vb_bg = QtWidgets.QGraphicsRectItem(plot)
        vb_bg.setRect(plot.vb.rect())
        vb_bg.setBrush(brush)
        vb_bg.setFlag(QtWidgets.QGraphicsItem.ItemStacksBehindParent)
        vb_bg.setZValue(-1e9)
        plot.vb.sigResized.connect(lambda x: vb_bg.setRect(x.geometry()))

    def setLabels(self, axesLabels, dataLabel):
        self.axesLabels = axesLabels
        self.dataLabel = dataLabel

        self.updateLabels()

    def updateLabels(self):
        self.plot.setLabels(bottom='{} [{:C~}]'.format(self.axesLabels[0],
                                                       self.axes_units[0]),
                            left='{} [{:C~}]'.format(self.dataLabel,
                                                     self.data_unit))

        ftUnits = self.data_unit
        if not self.dataIsPower:
            ftUnits = ftUnits**2

        self.ft_plot.setLabels(bottom='1 / {} [{:C~}]'.format(
            self.axesLabels[0], (1 / self.axes_units[0]).units),
                               left='Power [dB-({:C~})]'.format(ftUnits))

    def get_ft_data(self, data):
        delta = np.mean(np.diff(data.axes[0]))
        winFn = self.windowFunctionMap[self.windowComboBox.currentData()]
        refUnit = 1 * self.data_unit
        Y = np.fft.rfft(data.data / refUnit * winFn(len(data.data)), axis=0)
        freqs = np.fft.rfftfreq(len(data.axes[0]), delta)
        dBdata = 10 * np.log10(np.abs(Y))
        if not self.dataIsPower:
            dBdata *= 2
        return (freqs, dBdata)

    def _updateFTWindow(self):
        if self.prevDataSet:
            F, dBdata = self.get_ft_data(self.prevDataSet)
            self._ft_lines[0].setData(x=F, y=dBdata)

        if self.curDataSet:
            F, dBdata = self.get_ft_data(self.curDataSet)
            self._ft_lines[1].setData(x=F, y=dBdata)

    def drawDataSet(self, newDataSet, *args):
        plotTime = time.perf_counter()

        # artificially limit the replot rate to 20 Hz
        if (plotTime - self._lastPlotTime < 0.05):
            return

        self._lastPlotTime = plotTime

        self.prevDataSet = self.curDataSet
        self.curDataSet = newDataSet

        if (self.curDataSet.data.units != self.data_unit
                or self.curDataSet.axes[0].units != self.axes_units[0]):
            self.data_unit = self.curDataSet.data.units
            self.axes_units[0] = self.curDataSet.axes[0].units
            self.updateLabels()

        if self.prevDataSet:
            self._lines[0].setData(x=self._lines[1].xData,
                                   y=self._lines[1].yData)
            self._ft_lines[0].setData(x=self._ft_lines[1].xData,
                                      y=self._ft_lines[1].yData)
        if self.curDataSet:
            self._lines[1].setData(x=self.curDataSet.axes[0],
                                   y=self.curDataSet.data)
            F, dBdata = self.get_ft_data(self.curDataSet)
            self._ft_lines[1].setData(x=F, y=dBdata)
Exemplo n.º 11
0
def testbench():

    #Parametros del muestreo
    N = np.power(2, 10)
    fs = np.power(2, 10)

    #Size del montecarlo
    S = 200

    #Limites de la distribucion de fr
    l1 = -2 * (fs / N)
    l2 = 2 * (fs / N)

    #Amplitud
    Ao = 2 * np.ones((S, 1), dtype=float)

    #Fase
    Po = np.zeros((S, 1), dtype=float)

    #Frecuencia central
    fo = int(np.round(N / 4))

    #Cantidad ventanas
    Nw = 2

    #Fr sera una variable aleatoria de distribucion uniforme entre -2 y 2
    #Genero 200 realizaciones de fr
    fr = np.random.uniform(l1, l2, S).reshape(S, 1)

    #Genero 200 realizaciones de f1
    f1 = fo + fr

    #Enciendo el generador de funciones
    generador = gen.signal_generator(fs, N)

    #Genero 200 realizaciones de x
    (t, x) = generador.sinewave(Ao, f1, Po)

    #Genera una matriz con las 5 ventanas
    w = np.array([], dtype='float').reshape(N, 0)

    for j in range(0, Nw):

        if j is 0:
            wj = np.ones((N, 1), dtype=float)
        elif j is 1:
            wj = win.flattop(N).reshape(N, 1)
        elif j is 2:
            wj = win.hann(N).reshape(N, 1)
        elif j is 3:
            wj = win.blackman(N).reshape(N, 1)
        elif j is 4:
            wj = win.flattop(N).reshape(N, 1)

        w = np.hstack([w, wj.reshape(N, 1)])

    #Inicializo el analizador de espectro
    analizador = sa.spectrum_analyzer(fs, N, algorithm="fft")

    for j in range(0, Nw):

        wi = w[:, j].reshape(N, 1)

        Ao_estimador = np.array([], dtype='float').reshape(1, 0)

        #Contempla la energia o potencia en un ancho de banda
        Ao2_estimador = np.array([], dtype='float').reshape(1, 0)

        for i in range(0, S):

            xi = x[:, i].reshape(N, 1)

            xi = xi * wi

            #Obtengo el espectro para las i esima realizacion de x
            (f, Xi) = analizador.module(xi)

            aux = Xi[(fo - 2):(fo + 3)]

            #Calculo una realizacion del estimador
            Aoi_estimador = Xi[fo].reshape(1, 1)

            #Ao2i_estimador = np.sqrt(np.sum(np.power(aux,2))).reshape(1,1)
            Ao2i_estimador = np.sqrt(np.sum(np.power(aux, 2)) / 5).reshape(
                1, 1)

            #Lo adjunto a los resultados
            Ao_estimador = np.hstack([Ao_estimador, Aoi_estimador])
            Ao2_estimador = np.hstack([Ao2_estimador, Ao2i_estimador])

        plt.figure()
        plt.hist(np.transpose(Ao_estimador), bins='auto')
        plt.axis('tight')
        plt.title('Energia en el bin para ventana #' + str(j))
        plt.xlabel('Variable aleatoria')
        plt.ylabel('Probabilidad')
        plt.grid()

        plt.figure()
        plt.hist(np.transpose(Ao2_estimador), bins='auto')
        plt.title('Energia en un ancho de banda para ventana #' + str(j))
        plt.axis('tight')
        plt.xlabel('Variable aleatoria')
        plt.ylabel('Probabilidad')
        plt.grid()

        sesgo = np.mean(Ao_estimador) - Ao[0, 0]

        varianza = np.mean(np.power(Ao_estimador - np.mean(Ao_estimador), 2))

        sesgo2 = np.mean(Ao2_estimador) - Ao[0, 0]

        varianza2 = np.mean(np.power(Ao2_estimador - np.mean(Ao2_estimador),
                                     2))

        print('------------Ventana #' + str(j) + '--------------')

        print('Estimador: Energia en un bin')

        print('Sesgo: ' + str(sesgo))

        print('Varianza: ' + str(varianza))

        print('Estimador: Energia en un ancho de banda (5 bin)')

        print('Sesgo: ' + str(sesgo2))

        print('Varianza: ' + str(varianza2))

        i = i + 1

    return w
Exemplo n.º 12
0
class MPLCanvas(QtWidgets.QGroupBox):
    """Ultimately, this is a QWidget (as well as a FigureCanvasAgg, etc.)."""
    @enum.unique
    class WindowTypes(enum.Enum):
        Rectangular = 0
        Hann = 1
        Flattop = 2
        Tukey_5Percent = 3

    windowFunctionMap = {
        WindowTypes.Rectangular:
        lambda M: windows.boxcar(M, sym=False),
        WindowTypes.Hann:
        lambda M: windows.hann(M, sym=False),
        WindowTypes.Flattop:
        lambda M: windows.flattop(M, sym=False),
        WindowTypes.Tukey_5Percent:
        lambda M: windows.tukey(M, sym=False, alpha=0.05),
    }

    dataIsPower = False
    dataSet = None
    prevDataSet = None
    _prevAxesLabels = None
    _axesLabels = None
    _prevDataLabel = None
    _dataLabel = None

    _lastPlotTime = 0
    _isLiveData = False

    def __init__(self, parent=None):
        style_mpl()

        super().__init__(parent)

        dpi = QtWidgets.qApp.primaryScreen().logicalDotsPerInch()
        self.fig = Figure(dpi=dpi)
        self.fig.patch.set_alpha(0)

        self.axes = self.fig.add_subplot(2, 1, 1)
        self.ft_axes = self.fig.add_subplot(2, 1, 2)

        self.canvas = FigureCanvasQTAgg(self.fig)
        self.mpl_toolbar = NavigationToolbar2QT(self.canvas, self)

        self.mpl_toolbar.addSeparator()

        self.autoscaleAction = self.mpl_toolbar.addAction("Auto-scale")
        self.autoscaleAction.setCheckable(True)
        self.autoscaleAction.setChecked(True)
        self.autoscaleAction.triggered.connect(self._autoscale)

        self.mpl_toolbar.addWidget(
            QtWidgets.QLabel("Fourier transform "
                             "window: "))

        self.windowComboBox = QtWidgets.QComboBox(self.mpl_toolbar)
        for e in MPLCanvas.WindowTypes:
            self.windowComboBox.addItem(e.name, e)
        self.mpl_toolbar.addWidget(self.windowComboBox)
        self.windowComboBox.currentIndexChanged.connect(self._replot)

        vbox = QtWidgets.QVBoxLayout(self)
        vbox.addWidget(self.mpl_toolbar)
        vbox.addWidget(self.canvas)
        vbox.setContentsMargins(0, 0, 0, 0)
        vbox.setStretch(0, 1)
        vbox.setStretch(1, 1)

        self.setSizePolicy(QtWidgets.QSizePolicy.Expanding,
                           QtWidgets.QSizePolicy.Expanding)
        self.canvas.setSizePolicy(QtWidgets.QSizePolicy.Expanding,
                                  QtWidgets.QSizePolicy.Expanding)
        self.updateGeometry()

        self.fig.tight_layout()

        self._lines = self.axes.plot([], [], [], [], animated=True)
        self._lines[0].set_alpha(0.25)
        self._ftlines = self.ft_axes.plot([], [], [], [], animated=True)
        self._ftlines[0].set_alpha(0.25)
        self.axes.legend(['Previous', 'Current'])
        self.ft_axes.legend(['Previous', 'Current'])
        self.axes.set_title('Data')
        self.ft_axes.set_title('Fourier transformed data')
        self._redraw()

        # Use a timer with a timeout of 0 to initiate redrawing of the canvas.
        # This ensures that the eventloop has run once more and prevents
        # artifacts.
        self._redrawTimer = QtCore.QTimer(self)
        self._redrawTimer.setSingleShot(True)
        self._redrawTimer.setInterval(100)
        self._redrawTimer.timeout.connect(self._redraw)

        # will be disconnected in drawDataSet() when live data is detected.
        self._redraw_id = self.canvas.mpl_connect('draw_event',
                                                  self._redraw_artists)

    def _redraw_artists(self, *args):
        if not self._isLiveData:
            self.axes.draw_artist(self._lines[0])
            self.ft_axes.draw_artist(self._ftlines[0])

        self.axes.draw_artist(self._lines[1])
        self.ft_axes.draw_artist(self._ftlines[1])

    def _redraw(self):
        self.fig.tight_layout()
        self.canvas.draw()
        self.backgrounds = [
            self.fig.canvas.copy_from_bbox(ax.bbox)
            for ax in (self.axes, self.ft_axes)
        ]
        self._redraw_artists()

    def showEvent(self, e):
        super().showEvent(e)
        self._redrawTimer.start()

    def resizeEvent(self, e):
        super().resizeEvent(e)
        self._redrawTimer.start()

    def get_ft_data(self, data):
        delta = np.mean(np.diff(data.axes[0]))
        winFn = self.windowFunctionMap[self.windowComboBox.currentData()]
        refUnit = 1 * data.data.units
        Y = np.fft.rfft(np.array(data.data / refUnit) * winFn(len(data.data)),
                        axis=0)
        freqs = np.fft.rfftfreq(len(data.axes[0]), delta)
        dBdata = 10 * np.log10(np.abs(Y))
        if not self.dataIsPower:
            dBdata *= 2
        data_slice = np.array(freqs) < 2.1
        return (freqs[data_slice], dBdata[data_slice])

    def _dataSetToLines(self, data, line, ftline):
        if data is None:
            line.set_data([], [])
            ftline.set_data([], [])
            return

        #data.data -= np.mean(data.data)
        line.set_data(data.axes[0], data.data)
        freqs, dBdata = self.get_ft_data(data)
        ftline.set_data(freqs, dBdata)

    def _autoscale(self, *, redraw=True):
        prev_xlim = self.axes.get_xlim()
        prev_ylim = self.axes.get_ylim()
        prev_ft_xlim = self.ft_axes.get_xlim()
        prev_ft_ylim = self.ft_axes.get_ylim()

        self.axes.relim()
        self.axes.autoscale()
        self.ft_axes.relim()
        self.ft_axes.autoscale()

        need_redraw = (prev_xlim != self.axes.get_xlim()
                       or prev_ylim != self.axes.get_ylim()
                       or prev_ft_xlim != self.ft_axes.get_xlim()
                       or prev_ft_ylim != self.ft_axes.get_ylim())

        if need_redraw and redraw:
            self._redraw()

        return need_redraw

    def _replot(self,
                redraw_axes=False,
                redraw_axes_labels=False,
                redraw_data_label=False):
        if not self._isLiveData:
            self._dataSetToLines(self.prevDataSet, self._lines[0],
                                 self._ftlines[0])
        self._dataSetToLines(self.dataSet, self._lines[1], self._ftlines[1])

        if self._axesLabels and redraw_axes_labels:
            self.axes.set_xlabel('{} [{:C~}]'.format(
                self._axesLabels[0], self.dataSet.axes[0].units))
            self.ft_axes.set_xlabel('1 / {} [1 / {:C~}]'.format(
                self._axesLabels[0], self.dataSet.axes[0].units))

        if self._dataLabel and redraw_data_label:
            self.axes.set_ylabel('{} [{:C~}]'.format(self._dataLabel,
                                                     self.dataSet.data.units))

            ftUnits = self.dataSet.data.units
            if not self.dataIsPower:
                ftUnits = ftUnits**2

            self.ft_axes.set_ylabel('Power [dB-({:C~})]'.format(ftUnits))

        axis_limits_changed = False
        if (self.autoscaleAction.isChecked()):
            axis_limits_changed = self._autoscale(redraw=False)

        # check whether a full redraw is necessary or if simply redrawing
        # the data lines is enough
        if (redraw_axes or redraw_axes_labels or redraw_data_label
                or axis_limits_changed):
            self._redraw()
        else:
            for bg in self.backgrounds:
                self.canvas.restore_region(bg)
            self._redraw_artists()
            self.canvas.blit(self.axes.bbox)
            self.canvas.blit(self.ft_axes.bbox)

    def drawDataSet(self, newDataSet, axes_labels, data_label):
        plotTime = time.perf_counter()

        looksLikeLiveData = plotTime - self._lastPlotTime < 1

        if looksLikeLiveData != self._isLiveData:
            if looksLikeLiveData:
                self.canvas.mpl_disconnect(self._redraw_id)
            else:
                self._redraw_id = self.canvas.mpl_connect(
                    'draw_event', self._redraw_artists)

        self._isLiveData = looksLikeLiveData

        # artificially limit the replot rate to 5 Hz
        if (plotTime - self._lastPlotTime < 0.2):
            return

        self._lastPlotTime = plotTime

        self.prevDataSet = self.dataSet
        self.dataSet = newDataSet

        redraw_axes = (self.prevDataSet is None
                       or len(self.prevDataSet.axes) != len(self.dataSet.axes))
        if not redraw_axes:
            for x, y in zip(self.prevDataSet.axes, self.dataSet.axes):
                if x.units != y.units:
                    redraw_axes = True
                    break

        redraw_axes_labels = (
            self._axesLabels != axes_labels
            or self.prevDataSet and self.dataSet
            and self.prevDataSet.axes[0].units != self.dataSet.axes[0].units)
        redraw_data_label = (
            self._dataLabel != data_label or self.prevDataSet and self.dataSet
            and self.prevDataSet.data.units != self.dataSet.data.units)

        self._axesLabels = axes_labels
        self._dataLabel = data_label

        self._replot(redraw_axes, redraw_axes_labels, redraw_data_label)
Exemplo n.º 13
0
duration = 1
sample_rate = 128
time = np.arange(0, duration, 1 / sample_rate)
freq = np.arange(0, sample_rate, 1 / duration)

frequency = [2, 2.5]
title = [["Сигнал з частотою 2 Гц", "Сигнал з частотою 2.5 Гц"],
         ['Амплітудний спектр без віконної функції', 'Амплітудний спектр без віконної функції'],
         ['Амплітудний спектр із віконною функцією', 'Амплітудний спектр із віконною функцією']]
x_label = ["Час, с", "Частота, Гц", "Частота, Гц"]
figure, axes = plt.subplots(2, 3, constrained_layout=True)
figure.set_size_inches(12, 6)
for i, ax in enumerate(axes):
    x = np.sin(2 * np.pi * frequency[i] * time)
    y = 2 * np.abs(fft(x) / len(x))
    y_window = 2 * np.abs(fft(x * flattop(len(x))) / len(x))
    ax[0].plot(time, x)
    ax[1].stem(freq, y)
    ax[1].set_xlim(0, sample_rate / 2)
    ax[2].stem(freq, y_window)
    ax[2].set_xlim(0, sample_rate / 2)
    for j in range(3):
        ax[j].set_xlabel(x_label[j])
        ax[j].set_title(title[j][i])
        ax[j].set_ylabel("Амплітуда")
        ax[j].minorticks_on()
        ax[j].grid(which='major', linewidth=1.2)
        ax[j].grid(which='minor', linewidth=.5)
plt.show()