Cálculos de evolução em Numpy / Scipy

perfil de um trabalho computacional que estou fazendo me mostrou que um gargalo no meu programa era uma função que basicamente fazia isso np énumpy, sp éscipy):

def mix1(signal1, signal2):
    spec1 = np.fft.fft(signal1, axis=1)
    spec2 = np.fft.fft(signal2, axis=1)
    return np.fft.ifft(spec1*spec2, axis=1)

Ambos os sinais têm forma(C, N) OndeC é o número de conjuntos de dados (geralmente menores que 20) eN é o número de amostras em cada conjunto (cerca de 5000). A computação para cada conjunto (linha) é completamente independente de qualquer outro conjunt

Pensei que era apenas uma convolução simples, então tentei substituí-lo por:

def mix2(signal1, signal2):
    outputs = np.empty_like(signal1)

    for idx, row in enumerate(outputs):
        outputs[idx] = sp.signal.convolve(signal1[idx], signal2[idx], mode='same')

    return outputs

... só para ver se obtive os mesmos resultados. Mas não, e minhas perguntas são:

Por que não Existe uma maneira melhor de calcular o equivalente amix1()?

(Eu percebo quemix2rovavelmente não teria sido mais rápido, mas poderia ter sido um bom ponto de partida para a paralelizaçã

Aqui está o script completo que eu usei para verificar rapidamente isso:

import numpy as np
import scipy as sp
import scipy.signal

N = 4680
C = 6

def mix1(signal1, signal2):
    spec1 = np.fft.fft(signal1, axis=1)
    spec2 = np.fft.fft(signal2, axis=1)
    return np.fft.ifft(spec1*spec2, axis=1)

def mix2(signal1, signal2):
    outputs = np.empty_like(signal1)

    for idx, row in enumerate(outputs):
        outputs[idx] = sp.signal.convolve(signal1[idx], signal2[idx], mode='same')

    return outputs

def test(num, chans):
    sig1 = np.random.randn(chans, num)
    sig2 = np.random.randn(chans, num)
    res1 = mix1(sig1, sig2)
    res2 = mix2(sig1, sig2)

    np.testing.assert_almost_equal(res1, res2)

if __name__ == "__main__":
    np.random.seed(0x1234ABCD)
    test(N, C)

questionAnswers(3)

yourAnswerToTheQuestion