예제 #1
0
def test_bound():
    assert helpers.bound(-1, [0, 1]) == 0 and helpers.bound(2, [0, 1]) == 1
예제 #2
0
def pulse_finder_species_set(spec, species_df, window_len="from_df", plot=False):
    """ perform windowed pulse finding (ribbit) on one file for each species in a set

    Args:
        spec: opensoundscape.Spectrogram object
        species_df: a dataframe describing species by their pulsed calls.
            columns: species | pulse_rate_low (Hz)| pulse_rate_high (Hz) | low_f (Hz)| high_f (Hz)| reject_low (Hz)| reject_high (Hz) |
                    window_length (sec) (optional) | reject_low2 (opt) | reject_high2 |
        window_len: length of analysis window, in seconds.
                    Or 'from_df' (default): read from dataframe.
                    or 'dynamic': adjust window size based on pulse_rate

    Returns:
        the same dataframe with a "score" (max score) column and "time_of_score" column
    """

    species_df = species_df.copy()
    species_df = species_df.set_index(species_df.columns[0], drop=True)

    species_df["score"] = [[] for i in range(len(species_df))]
    species_df["t"] = [[] for i in range(len(species_df))]
    species_df["max_score"] = [np.nan for i in range(len(species_df))]

    for i, row in species_df.iterrows():

        # we can't analyze pulse rates of 0 or NaN
        if isNan(row.pulse_rate_low) or row.pulse_rate_low == 0:
            # cannot analyze
            continue

        pulse_rate_range = [row.pulse_rate_low, row.pulse_rate_high]

        if window_len == "from_df":
            window_len = row.window_length
        elif window_len == "dynamic":
            # dynamically choose the window length based on the species pulse-rate
            # try to capture ~4-10 pulses
            min_len = 0.5  # sec
            max_len = 10  # sec
            target_n_pulses = 5
            window_len = bound(
                target_n_pulses / pulse_rate_range[0], [min_len, max_len]
            )
        # otherwise, use the numerical value provided for window length

        signal_band = [row.low_f, row.high_f]  # changed from low_f, high_f

        noise_bands = None
        if not isNan(row.reject_low):
            noise_bands = [[row.reject_low, row.reject_high]]
            if "reject_low2" in species_df.columns and not isNan(row.reject_low2):
                noise_bands.append([row.reject_low2, row.reject_high2])

        # score this species for each window using ribbit
        if plot:
            print(f"{row.name}")
        pulse_scores, window_start_times = ribbit(
            spec, signal_band, pulse_rate_range, window_len, noise_bands, plot
        )

        # add the scores to the species df
        species_df.at[i, "score"] = pulse_scores
        species_df.at[i, "t"] = window_start_times
        species_df.at[i, "max_score"] = (
            max(pulse_scores) if len(pulse_scores) > 0 else np.nan
        )
        species_df.at[i, "time_of_max_score"] = (
            window_start_times[np.argmax(pulse_scores)]
            if len(pulse_scores) > 0
            else np.nan
        )

    return species_df