2017-03-13 14 views
3

signal_gen関数で表されるセンサーからのデータを処理するスクリプトを記述しています。テスト関数で見ることができるように、ループはかなりループしています。この関数は何度も呼び出されるので、少し遅くなり、最適化のための正しい方向へのプッシュで素敵です。Pythonのnumpyでのループのベクトル化/最適化

forループをvectorizatid配列と交換することができますが、i_avg [i]行をどのように記述するかについて頭を浮かべることはできません。なぜなら、単一要素y [i] np.cosの中で配列全体xと乗算され、これはやはりi_avgの刺激にすぎません。私たちにI_avg, Q_avgを与えるともNumPy broadcastingを組み込むため、より効率的なソリューションを実現するために、ネストされたループを交換するnumpy.dotmatrix-multiplicationを使用して

def testing(signal): 
    y = np.arange(0.0108, 0.0135, 0.001) # this one changes over time, set 
    #to constant for easier reading 
    x = np.arange(0, (len(signal))) 
    I_avg = np.zeros(len(y)) 
    Q_avg = np.zeros_like(I_avg) 
    for i in range(0, len(y)): 
     I_avg[i] = np.array(signal * (np.cos(2 * np.pi * y[i] * x))).sum() 
     Q_avg[i] = np.array(signal * (np.sin(2 * np.pi * y[i] * x))).sum() 
    D = np.power(I_avg, 2) + np.power(Q_avg, 2) 
    max_index = np.argmax(D) 
    phaseOut = np.arctan2(Q_avg[max_index], I_avg[max_index]) 

#just a test signal 
def signal_gen(): 
    signal = np.random.random(size=251) 
    return signal 
+1

テストでSは何ですか? – Ohjeah

+0

タイプA、 "信号"と言わなければなりません – Runsiv

+0

max_indexは別のタイプミスです。このコードをテストしましたか? – Ohjeah

答えて

1

一つのベクトル化されたアプローチは、そうするようなものだ -

mult = 2*np.pi*y[:,None]*x 
I_avg, Q_avg = np.cos(mult).dot(signal), np.sin(mult).dot(signal) 

のためにそれを注意してください与えられたサンプルは、3の反復(yが長さ3)のためだけに反復しなければならないかわいいバージョンと競合しています。そのため、ここでは大きなスピードアップは見られません。

ランタイムテスト -

In [9]: #just a test signal 
    ...: signal = np.random.random(size=251) 
    ...: y = np.arange(0.0108, 0.0135, 0.001) 
    ...: x = np.arange(0, (len(signal))) 
    ...: 

# Original approach 
In [10]: %%timeit I_avg = np.zeros(len(y)) 
    ...: Q_avg = np.zeros_like(I_avg) 
    ...: for i in range(0, len(y)): 
    ...:  I_avg[i] = np.array(signal * (np.cos(2 * np.pi * y[i] * x))).sum() 
    ...:  Q_avg[i] = np.array(signal * (np.sin(2 * np.pi * y[i] * x))).sum() 
    ...: 
10000 loops, best of 3: 68 µs per loop 

# Proposed approach 
In [11]: %%timeit mult = 2*np.pi*y[:,None]*x 
    ...: I_avg, Q_avg = np.cos(mult).dot(signal), np.sin(mult).dot(signal) 
    ...: 
10000 loops, best of 3: 34.8 µs per loop 
+0

これは本当に魅力的に機能し、計算時間が半減し、非常に読みやすくなっています。ありがとう! – Runsiv

+0

ハードコーディングではなく 'np.newaxis'を使用することもできます。どちらも本質的に同じですが、ちょっとした提案です。 – kmario23

+0

@Runsiv解決策の1つを受け入れることを検討してください。ここでそれについてもっと読む:https://meta.stackexchange.com/questions/5234/how-does-accepting-an-answer-work – Divakar

0

あなたが放送用np.einsumを使用することができます。

yx = 2*np.pi*np.einsum("i,j->ij", y, x) 
I_avg = np.sin(yx) @ signal  
Q_avg = np.cos(yx) @ signal 
関連する問題