def stft_from_sig( sig_wf: np.ndarray, frequency_sample_rate_hz: float, band_order_Nth: float ) -> Tuple[np.ndarray, np.ndarray, np.ndarray, np.ndarray]: """ Librosa STFT is complex FFT grid, not power :param sig_wf: array with input signal :param frequency_sample_rate_hz: sample rate of frequency in Hz :param band_order_Nth: Nth order of constant Q bands :return: four numpy ndarrays with STFT, STFT_bits, time_stft_s, frequency_stft_hz """ sig_duration_s = len(sig_wf) / frequency_sample_rate_hz _, min_frequency_hz = scales.from_duration(band_order_Nth, sig_duration_s) order_Nth, cycles_M, quality_Q, \ frequency_center, frequency_start, frequency_end = \ scales.frequency_bands_g2f1(scale_order_input=band_order_Nth, frequency_low_input=min_frequency_hz, frequency_sample_rate_input=frequency_sample_rate_hz) # Choose the spectral resolution as the key parameter frequency_resolution_min_hz = np.min(frequency_end - frequency_start) frequency_resolution_max_hz = np.max(frequency_end - frequency_start) frequency_resolution_hz_geo = np.sqrt(frequency_resolution_min_hz * frequency_resolution_max_hz) stft_time_duration_s = 1 / frequency_resolution_hz_geo stft_points_per_seg = int(frequency_sample_rate_hz * stft_time_duration_s) # From CQT stft_points_hop, _, _, _, _ = \ scales.cqt_frequency_bands_g2f1(band_order_Nth, min_frequency_hz, frequency_sample_rate_hz, is_power_2=False) print('STFT Duration, NFFT, HOP:', len(sig_wf), stft_points_per_seg, stft_points_hop) STFT_Scaling = 2 * np.sqrt(np.pi) / stft_points_per_seg STFT = librosa.core.stft(sig_wf, n_fft=stft_points_per_seg, hop_length=stft_points_hop, win_length=None, window='hann', center=True, pad_mode='reflect') # Must be scaled to match scipy psd STFT *= STFT_Scaling STFT_bits = utils.log2epsilon(STFT) time_stft_s = librosa.times_like(STFT, sr=frequency_sample_rate_hz, hop_length=stft_points_hop) frequency_stft_hz = librosa.core.fft_frequencies( sr=frequency_sample_rate_hz, n_fft=stft_points_per_seg) return STFT, STFT_bits, time_stft_s, frequency_stft_hz
synthetics.antialias_halfNyquist(synth=sig_wf) # Export to wav directory if do_save_wave: wav_sample_rate_hz = 8000. export_filename = os.path.join(output_wav_directory, wav_filename + "_8kz.wav") synth_wav = 0.9 * np.real(sig_wf) / np.max(np.abs((np.real(sig_wf)))) scipy.io.wavfile.write(export_filename, int(wav_sample_rate_hz), synth_wav) # Frame to mic start and end and plot event_reference_time_epoch_s = sig_wf_epoch_s[0] # The min_frequency_hz is needed for STFT max_time_s, min_frequency_hz = scales.from_duration( band_order_Nth=order_number_input, sig_duration_s=sig_duration_s) print('\nRequest Order N=', order_number_input) print('Sweep duration, s:', sig_duration_s) print( 'Lowest frequency in hz that can support this order for this signal duration is ', min_frequency_hz) print('Scale with signal duration and to Nyquist, default G2 base re F1') # TFR: Compute complex wavelet transform (cwt) by specifying the start and end center frequencies # and getting the n-1 band below it. cwt_frequency_high_hz = np.max(frequency_end_hz) * scale_edge**2 cwt_frequency_low_hz = np.min(frequency_start_hz) / scale_edge print('Highest requested CWT frequency, Hz:', cwt_frequency_high_hz) print('Lowest requested CWT frequency, Hz:', cwt_frequency_low_hz)
def cqt_from_sig( sig_wf: np.ndarray, frequency_sample_rate_hz: float, band_order_Nth: float, cqt_window: str = 'hann', dictionary_type: str = "norm" ) -> Tuple[np.ndarray, np.ndarray, np.ndarray, np.ndarray]: """ Compute the constant-Q transform of a signal. :param sig_wf: array with input signal :param frequency_sample_rate_hz: sample rate of frequency in Hz :param band_order_Nth: Nth order of constant Q bands :param cqt_window: string, "cqt_gauss" or librosa window specification for the basis filter. Default is 'hann' :param dictionary_type: "tone" or "norm". Default is 'norm' :return: four numpy ndarrays with CQT, CQT_bits, time_cqt_s, frequency_cqt_hz """ sig_duration_s = len(sig_wf) / frequency_sample_rate_hz min_scale_s, min_frequency_hz = scales.from_duration( band_order_Nth, sig_duration_s) # Match default cwt cqt_points_hop_min, frequency_hz_center_min, scale_number_bins, order_Nth, cqt_points_per_seg_max = \ scales.cqt_frequency_bands_g2f1(band_order_Nth, min_frequency_hz, frequency_sample_rate_hz, is_power_2=False) print('CQT Duration, NFFT, HOP:', len(sig_wf), cqt_points_per_seg_max, cqt_points_hop_min) int_order_N = int(band_order_Nth) # CQT is not power if cqt_window == "cqt_gauss": CQT = librosa.core.cqt(sig_wf, sr=frequency_sample_rate_hz, hop_length=cqt_points_hop_min, fmin=frequency_hz_center_min, n_bins=scale_number_bins, bins_per_octave=int_order_N, tuning=0.0, filter_scale=1, norm=1, sparsity=0.0, window=q_gauss, scale=True, pad_mode='reflect') else: CQT = librosa.core.cqt(sig_wf, sr=frequency_sample_rate_hz, hop_length=cqt_points_hop_min, fmin=frequency_hz_center_min, n_bins=scale_number_bins, bins_per_octave=int_order_N, tuning=0.0, filter_scale=1, norm=1, sparsity=0.0, window=cqt_window, scale=True, pad_mode='reflect') time_cqt_s = librosa.times_like(CQT, sr=frequency_sample_rate_hz, hop_length=cqt_points_hop_min) frequency_cqt_hz = librosa.core.cqt_frequencies( scale_number_bins, frequency_hz_center_min, bins_per_octave=int_order_N, tuning=0.0) cqt_multiplier = cqt_scaling(band_order_Nth, frequency_cqt_hz, frequency_sample_rate_hz, CQT.shape, dictionary_type) CQT *= cqt_multiplier CQT_bits = utils.log2epsilon(CQT) return CQT, CQT_bits, time_cqt_s, frequency_cqt_hz