5

この質問はGnuplot: How to plot multiple time series from a binary format ;に似ていると理解しています。ただし、少し異なる例を既に設定しているので、投稿しても問題ないことを願っています(自己回答が続きます)。

このようなバイナリ データを生成しています ( genbindata.plPerl スクリプトについては以下を参照してください)。

$ perl genbindata.pl > bin.dat
$ du -b bin.dat 
234 bin.dat

このバイナリ ファイルは、bin.dat次のようにフォーマットされています (最初の 2 行は 1 ベースと 0 ベースのインデックスです)。

>|  1   2   3   4 |  5   6 ... 104 |105 106 ... 204 |205 206 ... 234
>|000 001 002 003 |004 005 ... 103 |104 105 ... 203 |204 205 ... 233
>| WW  WW  WW  WW | XX  XX ...  XX | YY  YY ...  YY | ZZ  ZZ ...  ZZ  

...WW署名の 4 バイトはどこにありますか。XX値が 0 ~ 63 の 100 バイトの正弦波です。YY64 ~ 127 の値を持つ 100 バイトの余弦です。およびZZは 30 バイトのランダム値です。ここではバイトを としますuint8

 

私がやりたいことは、これをそのまま使用するbin.datことです (つまり、データを解析し、より使いやすい形式で出力するスクリプトを書きたくありませんgnuplot) - そして、正弦データと余弦データをプロットします。単一の図に別の色で。

ヘルプのBinary generalセクションを見つけました (gnuplotターミナルで入力しても同じですhelp binary general) が、それを理解するのが困難です (オンラインで他の情報を見つけることができませんでした)。だから - (いくつかの)例をオンラインで掃除した後 -ターミナルモードで起動し、次のコマンドgnuplotを試しています:gnuplot

plot "bin.dat" binary skip=4 array=100x1:100x1 format='%uint8%uint8' origin=(0,0):(100,0) using 0:1 with lines

...意味することを期待して:「最初の 4 バイトをスキップし、次を 100 バイトの 1D データ ('%uint8' としてフォーマットされ、スキップ後の 0,0 の原点) として解釈し、100 バイトの 1D データが続きます。 ('%uint8' としてフォーマットされた 1 列の 100 行、およびスキップ後の 100,0 の原点); 疑似列 0 (ポイントのインデックス) を x 軸として使用し、配列からの最初の結果を線でプロットします" ...残念ながら、それは意味しません-何もプロットされず、コマンドは「Too many using specs for this style」で失敗します。

次に、「多すぎる」場合は、そこusingにプロットします。1

    gnuplot> plot "bin.dat" binary skip=4 array=100x1:100x1 format='%uint8%uint8' origin=(0,0):(100,0) using 1 with lines
    Warning: empty y range [0:0], adjusting to [-1:1]

実際、これはプロットを生成します - y=0 で単一の平坦な赤い線です。

したがって、y の範囲について不平を言うと、元の引数の順序を ((100,0) から (0,100) に) 変更し、最終的にメッセージを生成しないコマンドを取得します。

gnuplot> plot "bin.dat" binary skip=4 array=100x1:100x1 format='%uchar%uchar' origin=(0,0):(0,100) using 1 with lines
gnuplot> 

...しかし、傾いた1本の線だけをプロットします:

gnuplot-fail-1

...私が期待する正弦波のようなものはありません:(

 

だから、私の質問は - どうすればgnuplot必要なデータをプロットすることができますか?


ここにあるgenbindata.pl

#!/usr/bin/env perl

use 5.10.1;
use warnings;
use strict;
use open IO => ':raw'; 

binmode(STDIN);
binmode(STDOUT);

my $signatur = "SIGN";
my @signature = unpack('C*', $signatur);

my (@ch1, @ch2) = ()x2;

# generate 100 samples of (co)sinusoid
for ( my $ix = 0; $ix < 100; $ix++ ) {
  my $val1 = 1 + sin($ix*2*3.14/100); # range: 0-2
  my $val2 = 1 + cos($ix*2*3.14/100); # range: 0-2
  my $ch1val = int($val1*32);
  my $ch2val = int($val2*32+64);
  push(@ch1, $ch1val);
  push(@ch2, $ch2val);
  #print STDERR "val[$ix]: $ch1val, $ch2val\n";
}

# generate 30 samples random
my @end = ();
for ( my $ix = 0; $ix < 30; $ix++ ) {
  my $val = int(128*rand() + 32);
  push(@end, $val);
  #~ print STDERR "val[$ix]: $val\n";
}

# concatenate arrays:
my @output = (@signature,@ch1,@ch2,@end);
my $sizarr = scalar(@output);
#~ print STDERR " ".." ";

# print output - uint8: "C"
my $outstr = pack("C*", @output);
my $lenstr = length($outstr);
#~ print STDERR "output size: $sizarr; output length: $lenstr\n";
print $outstr;

# end
4

1 に答える 1

12

さて、上記の質問にはいくつかの誤解があります。これにはgnuplot 4.4を使用しています。100x1まず、「 」の「」array=100x1:100x1が100行と1列のデータセットを示していると私がどのように考えたかに注意してください-これは1D配列と同じです(インデックスが暗示されています)。しかし、そうではありません。言うことに注意してくださいhelp binary array


注: Gnuplot バージョン 4.2 では、 array=(128,128)ではなく、array=128x128 という構文が使用されていました。古い構文は廃止されましたが、
まだ機能する可能性があります [...]

座標は gnuplot によって生成されます。
配列の次元ごとに数値を指定する必要があります。たとえば、 基礎となるサンプリング構造が、 最初の (x) 次元に沿って 10 個のポイントを持つ2 次元array=(10,20)であることを意味します [..]

したがって、 " 100x1"が概念的には 1D 配列と同一である可能性がある場合でも、そのように記述するだけで、2D データをgnuplot(たとえば、イメージ; これは、100 の 1D 配列とは異なる方法でインスタンス化されると予想されます) に指定しました。要素、内部的にgnuplot)。だから、代わりに「 」と書くべきだったarray=(100):(100)。原則として 1D では括弧を省略できることに注意してください。そのため、" " も問題ありませんでした。ただし、 (ファイルの最後まで読み取る) を次元としてarray=100:100使用する場合は除きます。-1そうしないと、エラーが発生します。

 

次に、複数のレコードの問題があります。これらの「複数のレコード」への参照はほとんど見つかりませんでしたgnuplot-バイナリ構文の削減がありました[以前: 長い議論...] (gnuplot.devel) :

ファイル機能ごとに複数のレコードを捨てるのはどうですか。プロットするビッグ データ セットが複数ある場合は、複数のファイルを作成するだけです。

私は、彼らが複数のレコード機能を維持してくれたことをうれしく思いますが、それがよりよく説明されていることを願っています. Gnuplot で見つけた別のコメント、 Plot with sum of dataset :

... gnuplot (つまり 3.6) は、データの組み合わせを単一のレコードにプロットできますが、複数のデータセットはおろか、複数のレコードのデータを組み合わせることはできません。

これらの計算を行うプリプロセッサを作成する必要があります。

help binary arrayちょうど言います:

コロンを使用して、複数のレコードのディメンションを区切ることができます。
たとえば、ファイルarray=25:35に 2 つの 1 次元レコードがあることを示し
ます。

これにより、 " array=(100):(100)" を 2 つの (複数の) レコードとして指定すると、これらのレコードにそれぞれusing 0:1およびusing 0:2ステートメントで "アクセス" できると思いました (疑似列 0 を使用してデータにインデックスを付けます)。結局のところ、そうではありませんorigin-複数のレコードの仕様が可能にする唯一の機能は、および/またはパラメーターを介してそれらを制御する機能ですが、単一のプロット内でskipのみ可能であるように私には思えます。

記録について言えば、以下もあることに注意してくださいhelp binary record

arrayこのキーワードは、同じ構文を持つと同じ機能を果たします。ただし、recordgnuplot は座標情報を生成しません。これは、そのような情報がバイナリ データ ファイルの列の 1 つに含まれている可能性がある場合です。

これはあまりわかりませんが、原則として、を使用している場合、データにインデックスを付けるために疑似列 0 を指定する必要recordがあることを意味すると思います。しかし、それを行うべきではありませarrayん。したがって、次の 2 つのコマンドは同等です。

plot "bin.dat" binary array=(50) format='%uint8' using 1 with lines
plot "bin.dat" binary record=(50) format='%uint8' using 0:1 with lines

... 最初の 50 サンプルを 1 次元データの最初の (そして唯一の) レコードとして取得し、その (唯一の) 列のデータをuint8- としてフォーマットし、それをプロットします。

gnuplot-50-samps

ご了承ください

  • recordjust で実行using 1すると、上記の同等のコマンドと同じ画像が生成されます。
  • しかし、で行うarray0:1、質問OPから行が生成されます!

1のような「列識別子」の背後にある構造をデバッグして、これを何らかの方法で確認する明確な方法がないように見えるのは残念using 1です。しかし、上記は次のことを意味すると思います:

  • ではrecord、 は11 列 (50x1) のデータセットを表します。したがって、別の 1 列のインデックスと組み合わせることができます。
  • ではarray、 は1実際には 2 列 (50x2) のデータセットを表しており、最初の列はインデックスです。これが、別のインデックス (疑似列 0) と組み合わせると、行が生成される理由です (インデックスの疑似列が最初の列と結合するため)。の列1。これはインデックスでもあります。つまり、単調に増加する (または減少する) 整数のリストです) 。

 

次に、formatパラメーターに注意してください-help binary format状態:

[...] たとえばformat="%uchar%int%float"
、unsigned 文字を最初の using 列に、int を
2 番目の列に、float を 3 番目の列に関連付けます。[...]

さて、これにより、2 つの 1-D 複数レコードを操作したい場合は、次のようなものを使用する必要があると思いました。

plot "bin.dat" binary array=(50):(50) format='%uint8%uint8' using 1 with lines

...生成します:

gnuplot-2rec-50-samps-resamp

正弦と重なっている余弦部分が何らかの形で間違っていることはすぐにわかります。しかし、さらに興味深いのは、図がこれらの関数の全周期を 50 サンプルだけで示していることです。明示的にデータを生成したため、サインとコサインの両方が 100 サンプルの周期を持っています! エルゴ、データはどういうわけかリサンプリングされています-そして、問題はformat.

" array=(50):(50)" を指定することで、 1-Dである2 つの(複数の) レコードを指定し、それぞれ 1 つの (そして唯一の) 列を持ちます。ただし、" " は2 つのレコードの各列の形式を参照するのではなく、明らかに 2 番目の次元を参照します。2 つのレコードが 1D であることを考えると、レコードから 1 つおきのサンプルを取り除くだけです。format='%uint8%uint8'gnuplot

したがって、format='%uint8'プロット コマンドで " " を1 つだけ指定できます。

plot "bin.dat" binary array=(50):(50) format='%uint8' using 1 with lines

...そして、50 個のサンプルで半分のピリオドのみを取得します。

gnuplot-2rec-50-samps

... 予想通り。しかし、それでもレコード間の重複は解決されません。

 

ここで、複数のレコードは常に 1 つの同じプロットに起因するように見えることを覚えておくことが重要です。オフセットはoriginパラメータで調整できます。help binary keywords origin状態:

配列をグラフの別の場所に配置するには、originキーワードで
gnuplot に、配列の左下の点を
タプルで指定された点に配置するように指示します。タプルは、 の場合は double でplot、 の場合は 3 つである必要がありsplotます。

したがって、次のようなことができます。

plot "bin.dat" binary array=(50):(50) format='%uint8' origin=(0,0):(50,0) using 1 with lines

... 次のように解釈できます: 2 つの連続する 1D レコードを取得します。ここで、唯一の次元/列はuint8- としてフォーマットされ、プロット上で最初のレコードを (0,0) だけオフセット/移動し、2 番目のレコードを (50,0) だけオフセット/移動します。 ) (+x 方向に 50 単位) プロット上。2 つのレコードが連結されると予想されますが、実際には次のようになります。

gnuplot-2rec-50-samps-conc

...これで、データの最初の 100 サンプルであると予想されるものを観察できます。

レコードが「同じプロットの一部」であることは、以前に一致した位置から 2 番目のレコードを少し (たとえば、10 ユニット左に) ずらすだけで、より簡単に確認できます。

plot "bin.dat" binary array=(50):(50) format='%uint8' origin=(0,0):(40,0) using 1 with lines

...線でプロット中:

gnuplot-2rec-50-samps-disp

これはもはや関数ではなく、原点のオフセットがどのような影響を与えたかがすぐにわかります。

そうは言っても、データ内のすべてのレコードとそのオフセットを明示的に指定することで、データ全体をプロットできるようになりました。

plot "bin.dat" binary array=(4):(100):(100):(30) format='%uint8' origin=(0,0):(4,0):(104,0):(204,0) using 1 with lines

...予想どおり、連結された4つのレコードを生成します-データセット全体を再作成します:

gnuplot-4rec-all

ノート:

  • (読み取りから終了まで)を使用array=(4):(100):(100):(-1)すると、同じ画像が生成されます
  • origin=(0,0):(4,0):(104,0)の 4 つのレコードで (leave out last) を使用arrayすると、最後の 30 バイトが最初から重複します。
  • (leave out last) を使用array=(4):(100):(100)すると、最後の 30 バイトがプロットから消えます (元のレコードが 3 つまたは 4 つある場合)。

 

最後に、skip パラメータを見てみましょう。help binary skip状態:


[...] たとえば、ファイルがデータ領域の開始前に 1024 バイトのヘッダーを含む場合、おそらくplot '<file_name>' binary skip=1024 ...を使用したいと思うでしょう。

これらのコマンドはどちらも次のとおりであるため、これは少し誤解を招く可能性があります。

plot "bin.dat" binary array=(100) format='%uint8' using 1 with lines
plot "bin.dat" binary skip=4 array=(100) format='%uint8' using 1 with lines

... 同じプロットを生成します。

gnuplot-1rec-nooffs

...スキップが表示されない場所。ただしskip=4、キーワード リストの最後 ( の前using) に移動すると、コマンドは次のようになります。

plot "bin.dat" binary array=(100) format='%uint8' skip=4 using 1 with lines

...そして生成します:

gnuplot-1rec-offs

...実際、スキップが表示されます。

からも注意してくださいhelp binary skip

ファイルに複数のレコードがある場合は、それぞれに先行オフセットを指定できます。たとえば、最初のレコードの前に 512 バイト、2 番目と 3 番目のレコードの前に 256 バイトをスキップするには、
plot <file_name> binary record=356:356:356 skip=512:256:256 ...

それを説明しましょう-以下のコマンド:

plot "bin.dat" binary array=(100):(100) format='%uint8' origin=(0,0):(100,0) skip=4 using 1 with lines

... 2 つの 1-D レコードがあります (オフセットに追加originする必要があります。そうしないと、レコードが再びオーバーラップします)。スキップは 1 つだけです。これにより、基本的にシーケンス全体が 4 単位左に移動します。

gnuplot-2rec-skip

コマンドのように、skip で両方のフィールドに対処する場合:

plot "bin.dat" binary array=(100):(100) format='%uint8' origin=(0,0):(100,0) skip=4:20 using 1 with lines

...出力に気付くことができます:

gnuplot-2rec-2skip

... 2 番目のレコードが左に 20 単位移動されたことを示します。最後に失われた 20 単位を補うために、次のレコードからの残りのデータ (プロット コマンドでは対処されません)。

 

ここで、元の質問に戻ることができます - 「サインとコサインのデータを別々の色で単一の図にプロットする」。

その前に、プロットごとに 2 つのデータ「関数」を使用すると、originパラメータが実際にプロット上のレコードを移動することが簡単にわかることに注意してください。たとえば、次のコマンドです。

plot "bin.dat" binary array=(100) format='%uint8' origin=(4,0) using 1 with lines, \
"" binary array=(100) format='%uint8' origin=(104,0) using 1 with lines

...結果:

gnuplot-1rec-2func

...同じ最初の 100 サンプルのデータが、プロット内の 2 つの異なる場所に (異なる色で) レンダリングされます。

上記のすべての後、データを「解析」して「分割」しようとする-たとえば、「レコード」を使用して-プロットごとに2つのデータ「関数」を使用array=(4):(100):(100):(30) することはあまり役に立ちません(暗示されているように)別々の色で); 単一のデータ「関数」のみ。

つまり、2 つのデータ関数の場合、次の 1 つの 1D レコードとその長さのみを指定できますarray。その (唯一の) 列の形式。およびデータごとの「関数」によるオフセットskip:

plot "bin.dat" binary array=(100) format='%uint8' skip=4 using 1 with lines, \
"" binary array=(100) format='%uint8' skip=104 using 1 with lines

...目的のレンダリングを取得するには:

gnuplot-1rec-2func

binary array最後の注意として -をbinary record-に置き換えることで、まったく同じ図を得ることができusing 1ますusing 0:1

plot "bin.dat" binary record=(100) format='%uint8' skip=4 using 0:1 with lines, \ "" binary record=(100) format='%uint8' skip=104 using 0:1 with lines

...この特定のケースであっても、using 1同様に機能します。

 

さて、これが誰かに役立つことを願っています、
乾杯!

于 2013-01-23T04:27:50.577 に答える