1

TCL スクリプトを使用して、Tektronix の RIBinary 形式で Tektronix オシロスコープからデータを取得しています。次に、スクリプト内でそれを 10 進数値に変換する必要があります。

そもそも私はバイナリ変換をほとんど行っていませんが、私の意見では、このバイナリ形式に関するドキュメントも非常に曖昧です。とにかく、これが私の現在のコードです:

proc ::Scope::CaptureWaveform {VisaAlias Channel} {
    # Apply scope settings
    ::VISA::Write $VisaAlias "*WAI"
    ::VISA::Write $VisaAlias "DATa:STARt 1"
    ::VISA::Write $VisaAlias "DATa:STOP 4000"
    ::VISA::Write $VisaAlias "DATa:ENCdg RIBinary"
    ::VISA::Write $VisaAlias "DATa:SOUrce $Channel"

    # Download waveform
    set RIBinaryWaveform [::VISA::Query $VisaAlias "CURVe?"]

    # Parse out leading label from scope output
    set RIBinaryWaveform [string range $RIBinaryWaveform 11 end]

    # Convert binary data to a binary string usable by TCL
    binary scan $RIBinaryWaveform "I*" TCLBinaryWaveform
    set TCLBinaryWaveform

    # Convert binary data to list
}

ここで、このコードはマシンから次のデータを取得します。

-1064723993 -486674282 50109321 -6337556 70678 8459972 143470359 1046714383 1082560884 1042711231 1074910212 1057300801 1061457453 1079313832 1066305613 1059935120 1068139252 1066053580 1065228329 1062213553

これは、通常の ASCII データを取得したときにマシンが取得するものです (つまり、上記のデータが変換後にどのように見えるか):

-1064723968 -486674272 50109320 -6337556 70678 8459972 143470352 1046714368 1082560896 1042711232 1074910208 1057300800 1061457472 1079313792 1066305600 1059935104 1068139264 1066053568 1065228352 1062213568

最後に、Tektronix の RIBinary 仕様への参照を次に示します。これは標準のデータ型ではないと思うためです。

http://www.tek.com/support/faqs/how-binary-data-represented-tektronix-oscilloscopes

データの変換の詳細については、Tektronix の Web サイトでしばらく探していましたが、上記の URL しか見つかりませんでしたが、さらに情報が見つかった場合は、この投稿にコメントするか編集します。役に立つかもしれません。

アップデート

  • 回答は必ずしも TCL である必要はありません。誰かがこれを高レベルで論理的に処理するのを手伝ってくれるなら、TCLの詳細をハッシュ化できます(これは他の人にも役立つと思います)
  • データをバイナリで転送し、後で変換する必要があるのは、最適化のためです。このため、プロセスが遅くなるため、転送前にデバイスに変換を実行させることはできません。
  • コードを少し更新したところ、結果は実際の結果に非常に近いものになりました。もともとデータに含まれていたカンマと関係があるのではないかと思います。
  • 以下は、解析なしでデバイスから送信された生データの例です。
  • @kostix からの提案で、彼がくれたコードを使用して 2 つ目のスクリプトを作成し、それを自分のデータ セットに合わせて変更しました。以下に表示されますが、結果は上記のコードとまったく同じです。

ASCIi:

:CURVE -1064723968,-486674272,50109320,-6337556,70678,8459972,143470352,1046714368,1082560896,1042711232,1074910208,1057300800,1061457472,1079313792,1066305600,1059935104,1068139264,1066053568,1065228352,1062213568

RIBinary:

:CURVE #280ÀçâýðüÿKì

RIBinary に関する注意 - 「:CURVE #280」はすべて、解析する必要があるヘッダーの一部ですが、#280 の部分は、収集しているデータによって異なる場合があります。#280 の意味に関する Tektronix からの詳細情報を次に示します。

ブロックはバイナリ形式の波形データです。波形は次のようにフォーマットされます。 # は y バイトの数です。たとえば、if = 500 の場合、= 3 です。チェックサムを含めて転送するバイト数です。

つまり、現在のデータ セット x = 2 および yyy = 80 です。バイナリ データの変換に慣れていないので、ブロック形式を処理するためにプログラムで何をすればよいかわかりません。

@kostix からの提案で、データ セットに合わせて変更したコードを使用して 2 つ目のスクリプトを作成しました。

set RIBinaryWaveform [::VISA::Query ${VisaAlias} "CURVe?"]

binary scan $RIBinaryWaveform a8a curv nbytes

encoding convertfrom ascii ${curv}

scan $nbytes %u n

set n

set headerlen [expr {$n + 9}]

binary scan $RIBinaryWaveform @9a$n nbytes

scan $nbytes %u n

set n

set numints [expr {$n / 4}]

binary scan $RIBinaryWaveform @${headerlen}I${numints} data

set data

このコードの出力は、上で提供したコードと同じです。

4

3 に答える 3

2

私はこのような経験はありませんが、グーグルが好きです。これが私の発見です。

このドキュメントの「フォーマットされた I/O 操作」というタイトルのセクションでは、標準 C API 関数が (デバイスへの書き込み) と(デバイスからの読み取り) をviQueryf()組み合わせていることを示しており、例には次のような呼び出しが含まれています(「IEEE-488.2 バイナリ」セクションを参照)データ—"%b"») で、関数の 3 番目の引数で目的の形式を指定します。viPrintf()viScanf()viQueryf (io, ":CURV?\n", "%#b", &totalPoints, rdBuffer);

あなたの Tcl ライブラリからの手順は、私の目にはVISA::Queryかなり似ているので、データの形式指定する 3 番目の (オプションの) 引数を受け入れることを期待しています。viQueryf()

そのようなものがない場合は、ASCII データを見てみましょう。あなたの FAQ エントリと私が見つけたドキュメントはどちらも、不透明なデータがさまざまなサイズとエンディアンの一連の整数の形式になる可能性があることを指定しています。「RIBinary」形式は、ビッグエンディアンの符号付き整数である必要があると述べています。

Tcl コマンドは、binary scanバイト ストリームから 16 ビットおよび 32 ビットのビッグ エンディアン整数をスキャンできます。対応するS*およびI*フォーマットを使用します。

あなたの ASCII データは明らかに 32 ビット整数のように見えるので、I*.

こちらのドキュメントも参照してください。上でリンクした PDF ガイドと多くの共通点があるようですが、とにかく便利かもしれません。

TL;DR

  • API を調べて、必要なデータ形式をデバイスに明示的に伝える方法を見つけてください。これにより、デバイスが何らかの形で外部から再構成されてデフォルトのデータ形式が変更され、特定の (推測された) デフォルトに依存するコードの足元に敷物を効果的に引っ張る可能性がある場合に、より堅牢なソリューションが生成される可能性があります。
  • 上で概説したようにデータを解釈してみて、解釈が適切に見えるかどうかを確認してください。

PSこれはまったく意味がないかもしれませんが、「CURV」と「?」の間に「e」がある例は見つかりませんでした。への呼び出しでviQueryf()

更新(2013 年 1 月 17 日、データ形式に関する新しい発見に照らして):binary scanさまざまな種類のデータに対して、次の 2 つの手法を使用できます。

  • binary scan好きなだけ連続して指定子を受け入れます。binary scan提供されたデータを読み取るときに、左から右に処理されます。
  • バイナリ データのチャンクに対して複数のbinary scanning を実行するには、このチャンクの一部を切り取るか (文字列操作 Tcl コマンドは、バイト配列で動作していることを認識し、それに応じて動作します) 、フォーマット文字列@offset内の用語を使用してそれを作成します。binary scan指定したオフセットからスキャンを開始します。

ここで採用する価値のあるもう 1 つの手法は、まずおもちゃの例で自分自身を訓練することです。これは、インタラクティブな Tcl シェルで行うのが最適です — これが最善の策ですが、特に(POSIX システムのみ)経由で呼び出す場合はtkconプレーンtclshでも問題ありません。rlwrap

たとえば、次のように偽のデータを作成できます。

% set b [encoding convertto ascii ":CURVE #224"]
:CURVE #224
% append b [binary format S* [list 0 1 2 -3 4 -5 6 7 -8 9 10 -11]]
:CURVE #224............

ここでは、最初にヘッダーを含むバイト配列を作成し、次に MSB を先頭にパックされた 12 個の 16 ビット整数を含む別のバイト配列を作成し、それを最初の配列に追加して、基本的にデバイスが返すことになっているデータ ブロックを作成します。デバイスが返すよりも整数)。encoding convertto文字エンコーディングと文字列の名前を取り、指定されたエンコーディングに変換されたその文字列のバイナリ配列を生成します。binary format任意のサイズのリスト (形式リスト内) を消費し、それをビッグエンディアン形式 (形式文字*) でパックされる 16 ビット整数のリストとして解釈するように指示されます。S

これで、次のようにスキャンできます。

% binary scan $b a8a curv nbytes
2
% encoding convertfrom ascii $curv
:CURVE #
% scan $nbytes %u n
1
% set n
2
% set headerlen [expr {$n + 9}]
11
% binary scan $b @9a$n nbytes
1
% scan $nbytes %u n
1
% set n
24
% set numints [expr {$n / 2}]
12
% binary scan $b @${headerlen}S${numints} data
1
% set data
0 1 2 -3 4 -5 6 7 -8 9 10 -11

ここでは、次のように進めました。

  1. ヘッダーを解釈します。

    1. データの最初の 8 バイトを ASCII 文字 ( a8) として読み取ります — これにより、:CURVE #プレフィックスが読み取られるはずです。を使用して、ヘッダー プレフィックスを圧縮された ASCII 形式から Tcl の内部文字列エンコーディングに変換しencoding convertfromます。
    2. コマンドを使用して、次のバイト ( ) を読み取りますa。これは、次のフィールドの長さ (バイト単位) として解釈されますscan

      次に、これまでに読み取ったヘッダーの長さを計算して、後で使用します。この値は「headerlen」変数に保存されます。ヘッダーの長さは、次のデータの長さを指定する 9 つの固定バイトと可変数のバイト (この場合は 2) の和になります。

    3. 「データバイト数」値として解釈される次のフィールドを読み取ります。

      これを行うには、スキャナを 9 (「:CURVE #2」の長さ) だけオフセットし、前の手順で取得したのと同じ数の ASCII バイトを読み取るため、@9a$n次の形式に使用します: $n"n" であり、この場合は 2 になります。次にscan、取得した値を取得し、最終的に次の生データの数を取得します。

      バイトではなく 16 ビット整数を読み取るため、この数値を 2 で割り、結果を「numints」変数に格納します。

  2. データを読み取ります。これを行うには、ヘッダーの長さだけスキャナーをオフセットする必要があります。@${headerlen}S${numints}フォーマット文字列に使用します。Tcl は${varname}、文字列を に渡す前にこれらを展開するbinary scanため、この場合の実際の文字列は、@11S12「11 バイトずつオフセットしてから、12 個の 16 ビット ビッグ エンディアン整数をスキャンする」ことを意味します。

    binary scan名前が渡される変数に整数のリストを入れるため、これらの整数をさらにデコードする必要はありません。

実際のプログラムでは、おそらくいくつかの健全性チェックを行う必要があることに注意してください: * 最初のステップの後、ヘッダーの静的部分が実際に ":CURVE #" であることを確認します。* および各呼び出しの後に戻り値をbinary scan確認scanし、コマンドに渡された変数の数と等しいことを確認します (コマンドがデータを解析できたことを意味します)。

もう1つの洞察。あなたが引用したマニュアルには次のように書かれています:

チェックサムを含めて転送するバイト数です。

そのため、これらのデータ バイトのすべてが測定値を表しているわけではなく、一部がチェックサムを表している可能性は十分にあります。このチェックサムの形式 (したがって長さ) とアルゴリズムと位置がわかりません。しかし、データに実際にチェックサムが含まれている場合、 を使用してすべてを解釈することはできませんS*。代わりに、おそらく別のアプローチを取るでしょう。

  1. を使用して測定データを抽出string rangeし、変数に保存します。
  2. binary scanチェックサム フィールド。
  3. 最初のステップで取得したデータのチェックサムを計算し、検証します。
  4. 抽出されたデータを使用binary scanして、測定値を取得します。

チェックサム手順は で利用できますtcllib

于 2013-01-14T23:19:49.373 に答える
2

リンク先のドキュメントによると、RIBinary はビッグエンディアンで署名されています。したがって、バイナリ データを整数に変換するには、binary scan $data "I*" someVar(I*は「できるだけ多くのビッグ エンディアンの 4 バイト整数」を意味します)。RPBinary で同じ変換を使用しますが (それがある場合)、各値を 32 ビットの正の整数範囲に分割する必要があります& 0xFFFFFFFF(少なくとも Tcl 8.5 を想定)。FPBinary の場合は、R*(8.5 が必要) を使用します。SRIBinary、SRPBinary、および SFPBinary はリトルエンディアン バージョンであり、小文字の書式文字を使用します。

変換を正しく行うには、いくつかの実験が必要になる場合があります。

于 2013-01-14T23:21:59.673 に答える
0
# Download waveform
set RIBinaryWaveform [::VISA::Query ${VisaAlias} "CURVe?"]

# Extract block format data
set ResultCount [expr [string range ${RIBinaryWaveform} 2 [expr [string index${RIBinaryWaveform} 1] + 1]] / 4]

# Parse out leading label from Tektronics block format
set RIBinaryWaveform [string range ${RIBinaryWaveform} [expr [string index ${RIBinaryWaveform} 1] + 2] end]

# Convert binary data to integer values
binary scan ${RIBinaryWaveform} "I${ResultCount}" Waveform
set Waveform

さて、上記のコードは魔法のトリックを行います。これは、このページで説明したすべてのことと非常によく似ていますが、バイナリ変換の数値が ASCII で受け取った数値と異なるという混乱を解消する必要があると考えました。

テクトロニクスのアプリケーション スペシャリストとトラブルシューティングを行った結果、バイナリ変換後に受信していたデータ (数桁ずれていた数値) が、実際にはオシロスコープによってキャプチャされた真の値であることがわかりました。

ASCII 値が間違っている理由は、計測器によって行われたバイナリから ASCII への変換の結果であり、その後、正しくない値がオシロスコープによって TCL に渡されます。

それで、私たちは数日前にそれを正しくしました。楽器は私をループに投げ込んだだけでした。

于 2013-01-23T22:22:29.907 に答える