-3

私は過去 2 年間にわたってこの質問をしてきましたが、まだこれを行う良い方法を探しています。私がやっていることは次のとおりです。

過去 3 年間に開発された WPF/C# アプリケーションがあります。UDP ポート経由でバイトのリアルタイム ストリームが必要です。各レコード セットは 1000 バイトです。これらのバイト レコードを 1 秒あたり 100 件取得しています。データを読み取り、さまざまな形式で表示するために処理しています。これらの論理レコードは部分交換されます。

最初の 300 バイトは同じで、各論理レコードには Byte、Int16、UInt16、Int32、および UInt32 の値が混在しています。これらの値の約 70% は、最終的に最下位ビットで乗算され、Double が作成されます。これらのパラメータは常に同じです。2 番目の 300 バイトは、Byte、Int16、UIn32、Int32、および UInt32 値の別の混合です。ここでも、これらの値の約 70% が LSB で乗算され、Double が作成されます。これらのパラメータも常に同じです。最後のセグメントは 400 バイトで、準交換されます。これは、レコードの最後の部分に 20 の異なる論理レコード形式のうちの 1 つが含まれていることを意味します。Type01...Type20データと呼んでいます。それがどれであるかを教えてくれる識別子バイトがあります。これらにも、変換が必要な Byte、Int、UInt データ値が含まれています。

現在、このデータを処理するために何百もの関数呼び出しを使用しています。各関数呼び出しは、1000 バイト配列をパラメーターとして受け取り、バイト配列内のパラメーターの開始位置へのオフセット (インデックス) を受け取ります。次に、BitConverter.ToXXX 呼び出しを使用してバイトを正しいデータ型に変換し、必要に応じて LSB を掛けて最終的なデータ値を作成し、それを返します。

ソースに基づいてデータ ストリームが変化するため、この処理を合理化しようとしています。たとえば、新しいデータ ソース (フィード) の 1 つは、最初の 300 バイトで約 20 個のパラメーターを変更し、2 番目の 300 バイトで約 24 個のパラメーターを変更し、最後にサブ交換された 400 バイト レコードでいくつかのパラメーターを変更します。

辞書に論理レコード番号 (データの型)、レコードへのオフセット、データの LSB、変換されるデータの型 (Int16、UInt32 など)、そして最後に出力型 ( Int32、Double など)。使用するBitConverter関数も含めて「動的にキャスト」することもできますか?

これは、テンプレート クラスとおそらくデリゲートを使用する演習のようですが、これを行う方法がわかりません。例のようなコードをいただければ幸いです。

データも記録されるので、再生は 2 倍速、4 倍速、8 倍速、16 倍速で実行できます。これらの速度で何千ものパラメーターを調べる方法について誰かがコメントする前に、それは人が考えるほど難しくありません。良い場合は緑の背景、悪い場合は赤など、いくつかのタイプのデータ。または、マップの位置 (LAT/LON) を経時的にプロットすると、興味深いイベントを見つけるための高速再生に非常に役立ちます。だからそれは可能です。

助けてくれてありがとう。

他の人が私がやろうとしていることを理解しているかどうかわからないので、ソースコードの小さなセグメントを投稿して、誰かがそれを改善できるかどうかを確認しようと思いました.

上で述べたように、データはバイト ストリームで提供されます。バイト配列で読み取られると、次のようになります。

Byte[] InputBuffer = { 0x01, 0x00, 0x4F, 0xEB, 0x06, 0x00, 0x17, 0x00, 
0x00, 0x00, ...    };

最初の 2 バイトは、1 に等しい ushort です。これは、この特定のレコードのレコード タイプです。この数の範囲は 1 ~ 20 です。

次の 4 バイトは、453,455 に等しい uint です。この値は、10 分の 1 秒です。この場合の値は 12:35:45.5 です。これに到達するには、次のサブルーチンに対して次の呼び出しを行います。

labelTimeDisplay.Content = TimeField(InputBuffer, 2, .1).ToString();

public Double TimeField(Byte[] InputBuffer, Int32 Offset, Double lsb)
{
   return BitConverter.ToUInt32(InputBuffer, Offset) * lsb;
}

次のデータ フィールドはソフトウェア バージョンで、この場合は 23 です。

labelSoftwareVersion.Content = SoftwareVersion(InputBuffer, 6).ToString();

public UInt16 SoftwareVersion(Byte[] InputBuffer, Int32 Offset)
{
   return BitConverter.ToUInt16(InputBuffer, Offset);
}

次のデータ フィールドは、別の UInt16 のシステム ステータス ワードです。

16 ビットのいずれかが論理 1 に設定されている場合、Built-In-Test ステータス ビットは他のルーチンに渡されます。

UInt16 CheckStatus = SystemStatus(InputBuffer, 8);

public UInt16 SystemStatus(Byte[] InputBuffer, Int32 Offset)
{
   return BitConverter.ToUInt16(InputBuffer, Offset);
}

バイト配列に格納されたデータを処理するために、文字通り 1,000 を超える個々のサブルーチンがあります。バイト配列は常に 1000 バイトの固定長です。最初の 6 バイトは常に同じ識別子と時刻です。その後、パラメータはフレームごとに異なります。

次のソフトウェア バージョン用に多くのパラメータを再定義するソフトウェアにいくつかの主要な変更が加えられます。古いバージョンのソフトウェアをサポートしなければならないので、ソフトウェアはさらに複雑になります。私の目標は、辞書検索を使用してデータを処理する方法を見つけることです。そうすれば、辞書を作成し、辞書を読んでデータの処理方法を知ることができます。おそらく、ループを使用してデータをコレクションにロードし、それを表示フィールドにバインドします。

このようなもの:

public class ParameterDefinition
{
    String ParameterNumber;
    String ParameterName;
    Int32 Offset;
    Double lsb;
    Type ReturnDataType;
    Type BaseDataType;
}

private ParameterDefinition[] parms = new ParameterDefinition[]
{
   new ParameterDefinition ( "0000","RecordID",  0, 0.0,  typeof(UInt16), typeof(UInt16)), 
   new ParameterDefinition ( "0001",    "Time",  2, 0.1,  typeof(Double), typeof(UInt32)), 
   new ParameterDefinition ( "0002",   "SW ID",  6, 0.0,  typeof(UInt16), typeof(UInt16)),
   new ParameterDefinition ( "0003",  "Status",  8, 0.0,  typeof(UInt16), typeof(UInt16)),  
   // Lots more parameters
}

私の肝心な問題は、適切な関数をキャストまたは選択するためのパラメーター定義を取得することです。「辞書」を実際のデータ出力にリンクする方法が見つかりません

助けてくれてありがとう

4

2 に答える 2

0

バイトがさまざまなデータ型を表すバイトストリームを手動で逆シリアル化しているようです。その問題は以前に解決されています。

最初の 600 バイトを表すクラスを定義してそれを逆シリアル化し、Protocol Buffer Serializerを使用して逆シリアル化してみてください(その実装は SO 自身の Marc Gravell によるもので、SO のトップ貢献者である Jon Skeet による別の実装があります)。

プロトコル バッファは、通信プロトコルとデータ ストレージで使用するために構造化データをシリアル化する、言語とプラットフォームに依存しない、拡張可能な方法です。データをどのように構造化するかを一度定義すると、特別に生成されたソース コードを使用して、さまざまなデータ ストリームとの間で、さまざまな言語を使用して構造化データを簡単に読み書きできます。「古い」形式に対してコンパイルされた展開済みプログラムを壊すことなく、データ構造を更新することもできます。

ソース、および私が個人的に使用していない 3 番目の実装。

最後の 300 バイトについては、適切な形式の適切なクラス定義を作成し、再びプロトコル バッファーを使用して適切なクラスを逆シリアル化します。

最終的な修正 (値を double に変換するなど) では、クラスを後処理するか、適切な最終的な数値を返す getter を使用することができます。

于 2015-07-22T21:00:57.650 に答える