示例#1
0
def test_fftcoef_detrend():
    for n in (50, 51):
        t = np.arange(n) / n
        x = np.random.randn(n)
        xd = signal.detrend(x)
        mag, phase, frq = dsp.fftcoef(x, 1 / t[1], dodetrend=True)
        A, B, frq = dsp.fftcoef(x,
                                1 / t[1],
                                coef="ab",
                                window=np.ones(x.shape),
                                dodetrend=True)

        w = 2 * np.pi * frq[1]
        # reconstruct with magnitude and phase:
        x2 = 0.0
        for k, (m, p, f) in enumerate(zip(mag, phase, frq)):
            x2 = x2 + m * np.sin(k * w * t - p)
        assert np.allclose(xd, x2)

        # reconstruct with A and B:
        x3 = 0.0
        for k, (a, b, f) in enumerate(zip(A, B, frq)):
            x3 = x3 + a * np.cos(k * w * t) + b * np.sin(k * w * t)
        assert np.allclose(xd, x3)

    assert_raises(ValueError,
                  dsp.fftcoef,
                  x,
                  1 / t[1],
                  window=np.ones(x.size - 1))
示例#2
0
def test_fftcoef_maxdf():
    n = 16
    t = np.arange(n) / n
    x = np.random.randn(n)
    mag, phase, frq = dsp.fftcoef(x, 1 / t[1])
    mag1, phase1, frq1 = dsp.fftcoef(x, 1 / t[1], maxdf=0.6)
    assert frq1[1] <= 0.6
    assert np.allclose(mag1[::2], mag)
示例#3
0
def test_fftcoef_fold():
    for n in (10, 11):
        t = np.arange(n) / n
        x = np.random.randn(n)
        mag, phase, frq = dsp.fftcoef(x, 1 / t[1], fold=True)
        mag1, phase1, frq = dsp.fftcoef(x, 1 / t[1], fold=False)
        if not (n & 1):
            mag1[1:-1] *= 2.0
        else:
            mag1[1:] *= 2.0
        assert np.allclose(mag, mag1)
        assert np.allclose(phase, phase1)
示例#4
0
def test_fftcoef_recon():
    for n in (50, 51):
        t = np.arange(n) / n
        x = np.random.randn(n)
        mag, phase, frq = dsp.fftcoef(x, 1 / t[1])
        A, B, frq = dsp.fftcoef(x, 1 / t[1], coef="ab", window=np.ones(x.shape))

        w = 2 * np.pi * frq[1]
        # reconstruct with magnitude and phase:
        x2 = 0.0
        for k, (m, p, f) in enumerate(zip(mag, phase, frq)):
            x2 = x2 + m * np.sin(k * w * t - p)
        assert np.allclose(x, x2)

        # reconstruct with A and B:
        x3 = 0.0
        for k, (a, b, f) in enumerate(zip(A, B, frq)):
            x3 = x3 + a * np.cos(k * w * t) + b * np.sin(k * w * t)
        assert np.allclose(x, x3)
示例#5
0
def test_fftcoef():
    for n in (50, 51):
        t = np.arange(n) / n

        x = 4.0 * np.sin(2 * np.pi * 4 * t)
        mag, phase, frq = dsp.fftcoef(x, 1 / t[1])
        # lowest frequency = 1/T = 1.0
        # highest frequency = sr/2 = 500.0
        nfrq = (n // 2) + 1
        assert np.allclose(frq, 0.0 + np.arange(nfrq))
        x2 = np.zeros(len(frq))
        x2[4] = 4.0
        assert np.allclose(mag, x2)
        assert np.allclose(phase[4], 0.0)

        x = 4.0 * np.cos(2 * np.pi * 4 * t)
        mag, phase, frq = dsp.fftcoef(x, 1 / t[1])
        # lowest frequency = 1/T = 1.0
        # highest frequency = sr/2 = 500.0
        nfrq = (n // 2) + 1
        assert np.allclose(frq, 0.0 + np.arange(nfrq))
        x2 = np.zeros(len(frq))
        x2[4] = 4.0
        assert np.allclose(mag, x2)
        assert np.allclose(phase[4], -np.pi / 2)

        sig = np.column_stack((x, x, x))
        mag1, phase1, frq1 = dsp.fftcoef(sig, 1 / t[1], axis=0)
        assert np.allclose(frq, frq1)
        for i in range(3):
            assert np.allclose(mag1[:, i], mag)
            assert np.allclose(phase1[:, i], phase)

        sig = sig.reshape(1, 1, -1, 3, 1)
        mag2, phase2, frq2 = dsp.fftcoef(sig, 1 / t[1], axis=2)
        assert np.allclose(frq, frq2)
        assert np.allclose(mag1, mag2.reshape(-1, 3))
        assert np.allclose(phase1, phase2.reshape(-1, 3))
示例#6
0
    def _plot_era(self):
        """
        Plots input data against reduced model.

        Notes
        -----
        If the parameter `input_labels` is left empty, the approximate
        fit plot will not have a corresponding legend. Otherwise, the
        data and its approximations will appear with a corresponding
        legend. If the number of input labels provided does not match
        the number of input signals, this will return an error.

        If the parameter `FFT` is set to True, this function will
        generate an FFT plot of the input data in the corresponding
        color coding of the approximate fit plot. This will appear
        below the approximate fit plot and serves as a helpful
        comparison of detected modal data. If the scaling of the FFT
        plot is suboptimal, it can be adjusted by changing the values
        input to `FFT_range`, which will serve as a maximum cutoff or
        minimum/maximum cutoff pair, depending on whether one or two
        values are given.
        """
        if not self.show_plot:
            return

        y = self.resp_era
        if not hasattr(self, "time"):
            self.time = np.arange(0, self.n_tsteps) / self.sr + self.t0

        # plot each input in its own window
        for j in range(self.n_inputs):
            fig = plt.figure(f"ERA Fit, input {j}", clear=True)

            if self.FFT:
                ax1 = fig.add_subplot(211)
                ax2 = fig.add_subplot(212)
            else:
                ax1 = fig.add_subplot(111)

            # Will execute if the user has specified signal labels
            if self.input_labels:
                # Plot original data
                for i in range(self.resp.shape[0]):
                    ax1.plot(
                        self.time,
                        self.resp[i, :, j],
                        label=f"{self.input_labels[i]} (Data)",
                    )

                # reset color cycle so that the colors line up
                ax1.set_prop_cycle(None)

                # Plot ERA fit to data
                for i in range(self.resp.shape[0]):
                    ax1.plot(
                        self.time,
                        y[i, :, j],
                        "--",
                        label=f"{self.input_labels[i]} (ERA Fit)",
                    )
                # Legend will appear next to plot
                ax1.legend(bbox_to_anchor=(1.04, 1), loc="upper left")
            else:
                # Plot original data
                ax1.plot(self.time, self.resp[:, :, j].T, label="Data")

                # reset color cycle so that the colors line up
                ax1.set_prop_cycle(None)

                # Plot ERA fit to data
                ax1.plot(self.time, y[:, :, j].T, "--", label="ERA fit")

            # Labeling plot
            ax1.set_xlabel("Time (s)")
            ax1.set_ylabel("Response")
            ax1.set_title("Data (solid) vs. ERA Reduced Model (dashed)")

            # Will execute if the user requests an FFT
            if self.FFT:
                # Recovering magnitude, phase, and frequency FFT data
                mag, phase, frq = dsp.fftcoef(self.resp[:, :, j].T,
                                              self.sr,
                                              axis=0,
                                              maxdf=0.2)
                # No defined limits will plot entire FFT
                if not self.FFT_range:
                    ax2.plot(frq, mag)
                # In the case of defined limits, they will be processed
                else:
                    # Converts integer/float input to a list for indexing purposes
                    if isinstance(self.FFT_range, numbers.Real):
                        self.FFT_range = [self.FFT_range]
                    # If only one limit is provided, it is taken as a maximum limit
                    if len(self.FFT_range) == 1:
                        maxlim = max(np.where(frq <= self.FFT_range[0])[0])
                        ax2.plot(frq[:maxlim], mag[:maxlim])
                    # If a pair of limits is provided, it will be used
                    # as minimum/maximum limits
                    elif len(self.FFT_range) == 2:
                        minlim = max(np.where(frq <= self.FFT_range[0])[0])
                        maxlim = max(np.where(frq <= self.FFT_range[1])[0])
                        ax2.plot(frq[minlim:maxlim], mag[minlim:maxlim])

                # Labeling FFT plot
                ax2.set_xlabel("Frequency (Hz)")
                ax2.set_ylabel("Magnitude")
                ax2.set_title("Magnitude of Frequency Responses of Data")

            fig.tight_layout()
            fig.canvas.draw()
        plt.show()