Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Replace np.append method with scipy.signal.lfilter (preemphasis) #64

Merged
merged 1 commit into from Apr 28, 2024

Conversation

eryk-urbanski
Copy link
Contributor

What does this implement/fix? Explain your changes.

Scipy implementation of a first-order FIR filter has better performance and efficiency of the filtering process. The lfilter method provides a more optimized implementation, resulting in faster processing times.

Any other comments?

Recently I have started working on an audio feature extraction library as a university project. Read about the pre-emphasis process, found out that one way is to simply apply a first-order high-pass FIR filter and so looked up some implementations, like in spafe, seen that it uses np.append, tried lfilter instead, saw it's a bit faster. Now trying to contribute with a main goal to see if my observations are correct :D

@eryk-urbanski
Copy link
Contributor Author

Did some more testing with audio signals of different number of samples, turns out that the execution times depend on the size of the signal. For large signals, lfilter is definitely faster, for signals with a small number of samples np.append may, but not always, execute faster. I wonder if there is point in implementing an 'if' statement that checks the number of samples and uses one of the methods accordingly. If there is, then I can try to look for a more precise 'bordering number' of samples at which lfilter starts to perform thoroughly faster.

Zrzut ekranu 2024-04-14 125822

@SuperKogito
Copy link
Owner

I just tested this, and it looks like a decent speed improvement without introducing computational error.
I used this to test it:

import numpy as np
from scipy.signal import lfilter
import time
import random

def pre_emphasis_new(signal: np.ndarray, alpha: float = 0.97) -> np.ndarray:
    # Apply pre-emphasis filter
    return lfilter([1, -alpha], [1], signal)

def pre_emphasis_old(sig: np.ndarray, pre_emph_coeff: float = 0.97) -> np.ndarray:
    return np.append(sig[0], sig[1:] - pre_emph_coeff * sig[:-1])

t1 = []
t2 = []
diff = []
# Generate random input signal
for i in range(10000):
    np.random.seed(0)
    random_sig_size = random.randint(10**3, 10**6)
    input_signal = np.random.rand(random_sig_size)
    pre_emp_coeff = random.uniform(0, 1)

    # Measure execution time for preemphasis function
    start_time = time.time()
    emphasized_signal_1 = pre_emphasis_new(input_signal, pre_emp_coeff)
    elapsed_time_1 = time.time() - start_time
    t1.append(elapsed_time_1)

    start_time = time.time()
    emphasized_signal_2 = pre_emphasis_old(input_signal, pre_emp_coeff)
    elapsed_time_2 = time.time() - start_time
    t2.append(elapsed_time_2)

    # Check if the outputs are similar
    max_diff = np.max(np.abs(emphasized_signal_1 - emphasized_signal_2))
    #print("Maximum difference between signals:", max_diff)
    diff.append(max_diff)

    # Check execution time
    #print("Execution time for preemphasis function 1:", elapsed_time_1)
    #print("Execution time for preemphasis function 2:", elapsed_time_2)


print("NEW         : ", np.array(t1).mean())
print("OLD         : ", np.array(t2).mean())
print("IMPROVEMENT : ", np.mean((np.abs(np.array(t1) - np.array(t2)) / np.array(t2)) * 100) )
print("DIFFERENCE  : ", np.array(diff).sum())                                                                                                                                                                                                                                                                                                                                                                             

Results:

Run 1:
NEW         :  0.002433323121070862
OLD         :  0.002672420573234558
IMPROVEMENT :  48.354533410641274
DIFFERENCE  :  0.0

RUN 2:
NEW         :  0.00303207573890686
OLD         :  0.0031427544593811037
IMPROVEMENT :  52.71266613720194
DIFFERENCE  :  0.0

RUN 3:
NEW         :  0.0019071268796920777
OLD         :  0.002438677978515625
IMPROVEMENT :  34.354617995259716
DIFFERENCE  :  0.0

Overall there is a speed improvement of at least 10% and up to 50% in some cases if my code is correct.
Moreover, this is actually an implementation of the Pre-emphasis of an audio signal with a first-order differencing filter. As mentioned here

This looks good to me, so I will be merging this into the master and it will be part of the next release.
Congratulations on your first contribution 🎉

@SuperKogito SuperKogito merged commit c7c8499 into SuperKogito:master Apr 28, 2024
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants