def test_measure_rms(filename, regtest):
    filename = os.path.dirname(os.path.abspath(__file__)) + "/data/" + filename
    data = scipy.io.loadmat(filename, squeeze_me=True)
    rms, key, rel_dB_thresh, active = MSBG.measure_rms(data["signal"],
                                                       data["fs"],
                                                       data["dB_rel_rms"])
    npt.assert_allclose(rms, data["rms"], rtol=RTOL)
    npt.assert_allclose(key, data["key"] - 1,
                        rtol=RTOL)  # index so subtract 1 OK
    npt.assert_allclose(rel_dB_thresh, data["rel_dB_thresh"], rtol=RTOL)
    print(rms, file=regtest)
    print(utils.hash_numpy(key), file=regtest)
    print(rel_dB_thresh, file=regtest)
Ejemplo n.º 2
0
    def process(
        self,
        chans,
        add_calibration=False,
    ):
        """Run the hearing loss simulation.

        Args:
            chans (ndarray): signal to process, shape either N, Nx1, Nx2
            add_calibration (bool): prepend calibration tone and speech-shaped noise
                (default: False)

        Returns:
            ndarray: the processed signal

        """

        fs = 44100  # This is the only sampling frequency that can be used
        if fs != CONFIG.fs:
            logging.error(
                "Warning: only a sampling frequency of 44.1kHz can be used by MSBG."
            )

        logging.info(f"Processing {len(chans)} samples")

        # Get single channel array and convert to list
        chans = Ear.array_to_list(chans)

        # Need to know file RMS, and then call that a certain level in SPL:
        # needs some form of pre-measuring.
        levelreFS = 10 * np.log10(np.mean(np.array(chans)**2))

        equiv_0dB_SPL = CONFIG.equiv0dBSPL + CONFIG.ahr

        leveldBSPL = equiv_0dB_SPL + levelreFS
        CALIB_DB_SPL = leveldBSPL
        TARGET_SPL = leveldBSPL
        REF_RMS_DB = CALIB_DB_SPL - equiv_0dB_SPL

        # Measure RMS where 3rd arg is dB_rel_rms (how far below)
        calculated_rms, idx, rel_dB_thresh, active = MSBG.measure_rms(
            chans[0], fs, -12)

        # Rescale input data and check level after rescaling
        # This is to ensure that the following processing steps are applied correctly
        change_dB = TARGET_SPL - (equiv_0dB_SPL +
                                  20 * np.log10(calculated_rms))
        chans = [x * np.power(10, 0.05 * change_dB) for x in chans]
        new_rms_db = equiv_0dB_SPL + 10 * np.log10(
            np.mean(np.power(chans[0][idx], 2.0)))
        logging.info(
            f"Rescaling: leveldBSPL was {leveldBSPL:3.1f} dB SPL, now {new_rms_db:3.1f}dB SPL. Target SPL is {TARGET_SPL:3.1f} dB SPL."
        )

        # Add calibration signal at target SPL dB
        if add_calibration == True:
            if self.calibration_signal is None:
                self.calibration_signal = Ear.make_calibration_signal(
                    REF_RMS_DB)
            chans = [
                np.concatenate((self.calibration_signal[0], x,
                                self.calibration_signal[1])) for x in chans
            ]

        # Transform from src pos to cochlea, simulate cochlea, transform back to src pos
        chans = [
            Ear.src_to_cochlea_filt(x, self.src_correction, fs) for x in chans
        ]
        chans = [self.cochlea.simulate(x, equiv_0dB_SPL) for x in chans]
        chans = [
            Ear.src_to_cochlea_filt(x, self.src_correction, fs, backward=True)
            for x in chans
        ]

        # Implement low-pass filter at top end of audio range: flat to Cutoff freq, tails
        # below -80 dB. Suitable lpf for signals later converted to MP3, flat to 15 kHz.
        # Small window to design low-pass FIR, to cut off high freq processing noise
        # low-pass to something sensible, prevents exaggeration of > 15 kHz
        winlen = 2 * math.floor(0.0015 * fs) + 1
        lpf44d1 = firwin(winlen,
                         UPPER_CUTOFF_HZ / int(fs / 2),
                         window=("kaiser", 8))
        chans = [lfilter(lpf44d1, 1, x) for x in chans]

        return chans