2012-04-25 17 views
3

私は、高周波音波による非常に低い帯域幅の通信を可能にするアプリケーションの作成に取り組んでいます。私は周波数を作り、フーリエ変換を行うことができるようになった(MoonblinkのオープンソースコードAudalyzerの助けを借りて)。Android - 10msごとにイベントが発生するようにスケジュールする

私の問題は次のとおりです。コードを正しいタイミングで実行することができません。 10msごとにコードを実行したいとしましょう。これをどうやって行うのですか?

私はTimerTaskを使用しようとしましたが、実際にコードが実行されるまでには最大100msの遅延があります。

また、現在の時間にpingを実行し、その時間が経過したときに実行するだけでこの方法を試しました。しかし、まだ遅延の問題があります。皆さんはどんなアイデアを持っていますか?

Thread analysis = new Thread(new Runnable() 
{ 
    @Override 
    public void run() 
    { 
     android.os.Process.setThreadPriority(android.os.Process.THREAD_PRIORITY_URGENT_DISPLAY); 

     long executeTime = System.currentTimeMillis(); 

     manualAnalyzer.measureStart(); 
     while (FFTransforming) 
     {   
      if(System.currentTimeMillis() >= executeTime) 
      { 
       //Reset the timer to execute again in 10ms 
       executeTime+=10; 

       //Perform Fourier Transform 
       manualAnalyzer.doUpdate(0); 

       //TODO: Analyze the results of the transform here... 

      } 
     } 
     manualAnalyzer.measureStop(); 
    } 
}); 
analysis.start(); 
+0

あなたはexecuteTime = System.currentTimeMillis()+ 10を入れてみましたか? doUpdate()の後に?この方法では、doUpdatesの間に10ミリ秒の正確な遅延が必要です – Renard

+0

しかし、ガベージコレクションや他のスレッドが実行されているために現在の時刻が実行時よりも高い場合がありますので、最初に試しました。正確に10ミリ秒単位で発生しません。私はこれらの正確な増分を期待している別のデバイスと同期しようとしているので、完全には機能しません。 – YasharBahman

+0

すべてのコードを管理できる場合は、割り振りトラッカーを使用してガベージコレクションを排除し、すべてのオブジェクトを事前に割り当てることもできます。また、あなたが10msよりも長いdoUpdateでスパイクを取得すると、タイミングがオフになることにも注意してください。 – Renard

答えて

1

あなたのスレッド/ループ戦略はおそらくおおよそお近くになります。しかし、10msは多くの時間ではありません。ほとんどのAndroid搭載端末は超強力ではなく、フーリエ変換は多くの作業が必要です。私はあなたが10ミリ秒でそれほど多くの仕事にフィットすることはありそうもないと感じています。私はあなたがその期間を増やさなければならないと思う。

+0

私はそれをタイムアウトし、フーリエ変換は通常1mS(通常約300μS)で起こります。しかし、ガベージコレクションや他のスレッドが実行されていると、時々タイミングがスローされることがあります。スレッドの優先度を最高の優先度(ドキュメントによれば-20)に設定できることは分かっていますが、何らかの理由でこれが悪い習慣であると感じています。どう思いますか? – YasharBahman

+0

興味深いことに、私は少し速くそれを得ることができますが、それが動作する場合は動作します。あなたが10ms増分を得ることが本当に重要であれば、スレッドに最高の優先順位を与えることは悪いことではないと思います。あなたは通常10msの間隔を得ることができますか?時折スパイクを得ることができますか? – kabuko

+0

正直、それは働いているようです。しかし、再び、私はギャラクシーネクサスでそれを実行しているので、それは古い携帯電話よりも少し有利ですが、それは良くありません。そして、ええ、私は時折スパイクを取得します。 Renardはガベージコレクションを排除すると述べましたが、おそらくその問題を軽減するでしょう。あなたは別の方法を知っていますか?または、TimerTaskを厳しく強制する方法がありますか? – YasharBahman

1

doUpdateの実行時間が考慮されるようにコードを変更しました。 System.nanoTime()を使用すると精度も向上します。

public void run() { 
android.os.Process.setThreadPriority(android.os.Process.THREAD_PRIORITY_URGENT_DISPLAY); 

long executeTime=0;   
long nextTime = System.nanoTime(); 

manualAnalyzer.measureStart(); 
while (FFTransforming) 
{   
    if(System.nanoTime() >= nextTime) 
    { 
     executeTime = System.nanoTime(); 
     //Perform Fourier Transform 
     manualAnalyzer.doUpdate(0); 
     //TODO: Analyze the results of the transform here... 
     executeTime = System.nanoTime() - executeTime; 
     //guard against the case that doUpdate took longer than 10ms 
     final long i = executeTime/10000000; 
     //set the timer to execute again at the next full 10ms intervall 
     nextTime+= 10000000+ i*10000000 
    } 
} 
manualAnalyzer.measureStop(); 
    } 

他に何ができますか?

  • ガベージコレクション
  • をなくすにはNDKでネイティブ行く(単なるアイデア、これは同様に何のメリットが得られないかもしれません)
+0

これは良いアイデアです。しかし、私はサイクルを逃した場合、それは問題になるだろう、残りのデータが壊れています。しかし、少なくともこの方法では、私はそれを検出することができます。 – YasharBahman

+0

(間違ってすぐに投稿しました) 上記のように、ガベージコレクションを排除する唯一の方法は割り当てを避けることです。私がそうする時間があることを知っているとき、System.gc()を呼び出すのは良い考えでしょうか?そうすれば、私は頻繁に起こることはありません。またはirはまだ頻繁に起こるでしょうか? – YasharBahman

+0

伝える方法はありません。私は前にこの習慣を見てきましたが、フレームタイム中にたくさんの割り当てを行うと、最終的にgcが発生します。また、私は[クリスStrattons](http://stackoverflow.com/users/429063/chris-stratton)の答えはあなたの問題:-)に最適な解決策だと思います – Renard

2

私は非常に異なったアプローチをお勧めします:実行しようとしないでくださいコードをリアルタイムで入力してください。

代わりに、リアルタイムで実行されている低レベルのオーディオコードだけを、対象のイベントを含む期間、継続的に録音(または再生)することができます。

あなたのコードは、これとは幾分非同期で実行され、オーディオバッファによって切り離されています。コードの時間の意味は、実行時のシステムクロックではなく、使用するオーディオデータの定義済みのサンプル間間隔によって決まります。 (つまり、48 Kspsを使用している場合、10 mS後の方が480サンプル後になります)

送信が予想される時間ウィンドウを広げるために、デバイス間の相互作用を制御するプロトコルを変更する必要があります。つまり、「パケット」内の実際の変調とシンボルに関して正確なタイミングを取ることができますが、パケットを送受信するタイミングをほぼ同じ精度で予測する必要はありません。雑音を含むより長い記録の中で。

+0

これは良い考えですが、私は把握することはできませんどのように私は一緒に携帯電話を同期するだろう。なぜなら、私は、どのデータが送られるべきかに依存してデータを動的にロードしようとしているので、私はオーディオストリームを使用しているからです。準備ができたらそれを再生します。そして、私はオーディオバッファが空であることを知らせる方法はないと思います。また、すべてのサンプルが再生された後にコールバック関数を実行することができたとしても、完了した瞬間とは必ずしも呼ばれるとは限りません。スケジューラがそれを決定するとすぐに呼び出されます。 – YasharBahman

+0

それがあっても、バッファを再度ロードして再生を開始するには、未知の時間がかかりませんか? 私が誤解しているかどうか教えてください。 – YasharBahman

+0

最低のレイテンシーオーディオを得る方法を調べる必要があります。さらに重要なことは、送信と受信確認の間の長い折り返しウィンドウのプロトコルを設計する必要があることです。電話機は、信号を探しているデータを処理するのに十分速いため、正確なタイミングで確実に処理することはできません。そこにはいくつかのバッファを用意しておきます - データは正確なタイミングで記録または作成されますが、処理が平均より遅く、または遅く起こることがあります。 –

関連する問題