AD変換した大量のデジタルデータをグラフに
リアルタイム(アナログ変換している間)で表示させるには、
どのようなコードを書けばいいのでしょうか?
グラフは受信ボタン(コマンドボタン)を押したときに、
自動的に表示されるようにしたいのですが。
グラフはエクセルでもVBのフォーム上でもいいのですが、
このような場合(大量のデータの場合)はどちらがいいのでしょうか?
経験が浅いので、どなたかご指導よろしくお願いします。
WavファイルをD/A変換しながら波形表示したいと
言う事でしょうか?
D/Aをどのようにされるのですか?
結構プログラムの難易度は高くなると思いますが。
返信ありがとうございます。
WAVファイルは音声をデジタルへ変換したものですよね?
私がやろうとしているのは、人間の生体信号というアナログデータを
デジタルへ変換するという感じです。
だから、Wavファイルではなくて、CSV形式のファイルだと思います。
リアルタイムにするには、D/A変換しなければいけないでしょうか?
できれば、デジタルデータをリアルタイム表示したいです。
心電図のように、右から左へグラフが動いていくという感じにしたいのです。
データはCSVファイルなんですか?
それをリアルタイムで表示とはどういうことでしょう?
(CSVデータに時間情報があるとか?)
単にグラフを書くだけならPictureBoxあたりのLineメソッドで
できると思いますが、どの辺がわからないのでしょうか?
あと「大量」と言われても見ているだけの者にはさっぱりわかりませんよ。
サンプリング間隔ぐらい書かないとね。
匿名さんがおっしゃる通りサンプリング間隔が一番問題だと思いますよ。
リアルタイムといってもデータを通信(RS-232C)等で取り込みながら表示
するということではなくCSVのデータを表示するわけですか?
ここが一番大事なとこだと思います。
一旦採取したデータ(ファイル格納済み)をグラフにするのか、通信でリ
アルに取り込みながら表示するのかで大きく違います。
通信の場合は、サンプリング間隔にVBがついていけるかどうか
が問題になります。送信側でバッファなどを持っていて、一定の時間のデ
ータを一括で送ってくれれば問題ないでしょうが・・・。
1秒の何千文の1単位等で発生するデータを全てリアルタイムでVBで取り込
むことは、不可能です。(VBで不可能というよりは、WindowsOSの問題だと
思います)
一旦取り込んだデータを表示するならエクセルに展開して、グラフを作れど
うでしょうか。
VBからエクセルを操作する方法は、
http://www.bcap.co.jp/hanafusa/index.htmlを参考願います。
(花ちゃんのHPはいつも利用させていただいています)
問題は、VBでそのようなコントロールが無いかっていうことでは???
残念ながら私もそのようなコントロールがないか探しているところですが
出会っていません。
識者のレスを注目していたいと思います。
生体信号と言うものがどのような物か知りませんが、基本的には
周波数帯域が異なるだけで、音声信号と変わらないでしょう。
>リアルタイムにするには、D/A変換しなければいけないでしょうか?
コンピューターで表示するためには、全てA/D変換が必要です。
D/A変換は必要では有りません、D/A変換が必要なのは、アナログの
オシロスコープで表示する場合です。
まずどのように表示するかと言う事よりも先に、どの様に
A/D変換をするかと言う事が、第一関門になります。
それとも既にD/A変換されたデーターが存在するのでしょうか?
生体信号記録計について少し調べて見ました。
サンプリング周波数128Hz時チャンネル数32CH、50KHz時2CH
量子化ビット数16ビットor12ビットとなっています。
通常のリニアPCM(音声)は48KHz(CDは44.1kHz)、16ビット、2Chですから
スピード的には音声信号の処理と、殆ど同じということになります。
音声信号の場合工夫すれば、VBでのリアルタイムの波形表示が可能ですから
生体信号も可能でしょう。
>CSV形式のファイルだと思います。
データーフォーマットですが、多分最初に日にちとか、何のデーターだとかの
ヘッダーが有って、その後はチャンネルデーターを並べた測定データーの羅列
であると思います。多分CSV形式では有りません。
私も経験が浅くてお恥ずかしい限りですが、
VBでグラフを作成しています。PictureBoxのLineメソッドです。
一画面に最大10グラフ(線)表示するものを作っております。
データ数は数十万件ありますが、
そんなにストレスなく表示できていると思います。DBはSQLServerです。
もっと良い方法があれば...私も教えていただきたいです。
リアルタイムという事は、RS-232CかUSBかPCIかISAか知りませんが、
PC--A/D変換器--センサという接続になっているのですよね?
>どのようなコードを書けばいいのでしょうか?
I/Oの方式によって全然違います。
一応、上の4種類であればアドバイス可能です。
>グラフはエクセルでもVBのフォーム上でもいいのですが、
>このような場合(大量のデータの場合)はどちらがいいのでしょうか?
速度を上げたいのであれば、VBでLineToとかのAPIを使用するのが一番です。
PCの性能もあるでしょうが、200Hz、24bit、15Ch位は普通に可能です。
画面の更新(Refrash)を10Hzにしたりとか、
グラフを数点おきに表示したりとか、工夫が必要ですが。
っていうか、私の仕事そのもの過ぎてどこまで答えてよいものやら(メシの種なので)
皆様、丁寧な回答ありがとうございます。
>匿名さん
情報足りなくて、すいません。
サンプリング間隔は100に設定しています。
エクセルにデータをうつしてから、それをグラフに表示させたいのですが、
エクセルにデータを移している間、同時にグラフ表示するというのは、
無理なのでしょうか?
>年寄りの冷や水
返信ありがとうございます。
>匿名さんがおっしゃる通りサンプリング間隔が一番問題だと思いますよ。
>リアルタイムといってもデータを通信(RS-232C)等で取り込みながら表示
>するということではなくCSVのデータを表示するわけですか?
データを通信でとりこみながら、表示させたいです。
ただ、Excelに保存しながら、グラフを表示させていきたいのです。
送信側にはバッファを設定しています。
えと、リアルタイムの捉えかたが各人間で異なっているようですね。
確認ですが、
『現在』の人間の生体信号を、リアルタイムで表示したいのですよね?
『過去』に計測した人間の生体信号を、リアルタイム(同速度)で表示したいわけではありませんよね?
<以下回答>
前者であれば、
>どのようなコードを書けばいいのでしょうか?
データの読込ができているならば、
Lineメソッドを使用すればいいです。
>どちらがいいのでしょうか?
VBがいいです。
<以下小言>
>サンプリング間隔は100
いや、100Hzなんでしょうが、
『間隔は』という文字面をそのまま読むと、
100Sec(0.01Hz)とも、100mSec(10Hz)とも解釈できてしまいます。
単位もちゃんと書いてください。
『サンプリング周波数は』ってんなら話しはわかりますが。。。
>Excelに保存しながら
これも、Excel型(xls)のファイルに保存という意味でしょうか?
Excelで読み込める型(csv等)のファイルに保存という意味でしょうか?
それとも、現在起動しているExcelにデータを送るという意味でしょうか?
『現在』の生体信号を波形表示しながら、CSV形式のファイルに出力すればいいんですよね?
>ぴろあきさん
>『現在』の人間の生体信号を、リアルタイムで表示したいのですよね?
はい、そうです。
単位はヘルツです。説明不測ですいません。
>これも、Excel型(xls)のファイルに保存という意味でしょうか?
>Excelで読み込める型(csv等)のファイルに保存という意味でしょうか?
>それとも、現在起動しているExcelにデータを送るという意味でしょうか?
Excel型のファイルに保存するのがいいと考えています。
表示場所はExcelを予定しているので、そこに1秒間に100のデジタルデータを出していくという感じです。
データは数字のみなので、xlsでもcsvでもあまり変わらない気がするのですが、どうなのでしょうか?
データ自体は何か異常があったときに、ログ情報の一部として用いるので、
グラフよりは重要には思っていません。あくまで、遠くから医者が生体信号のグラフを見て、判断ができればよいと考えています。なので、データを周波数解析などの解析で用いることは予定してません。
>『現在』の生体信号を波形表示しながら、CSV形式のファイルに出力すればいいんですよね?
そのとおりです。波形表示しながら、「同時に」CSV形式のファイルに出力というのは可能なのでしょうか?
>ねろさん
返信ありがとうございます。
>それとも既にD/A変換されたデーターが存在するのでしょうか?
A/D変換は送信部の方で、取り込んだ生体信号をA/D変換カードで
変換しています。
それを遠隔地の受信部へデジタルデータとして送っています。
なので、D/A変換はしていません。
そこからオシロスコープだとかに送りはしないので、D/A変換はいらないということですね。
>ねろさん
追加で一つだけ。
>サンプリング周波数128Hz時チャンネル数32CH、50KHz時2CH
>量子化ビット数16ビットor12ビットとなっています。
量子化ビット数はわかるのですが、理解があいまいなのが
1CH,2CH‥などといったチャンネル数です。
これは、つまり外部機器から同時に取り込めるアナログデータの
数を示しているということでいいのでしょうか?
32CHなら32個接続可能ということになるのですか?
勉強不足で申し訳ないです。よろしくお願いします。
>それとも既にD/A変換されたデーターが存在するのでしょうか?
書き方を間違えました、A/D変換されたデーターは存在するのでしょうか?
と聞きたかったのです、つまりファイルから再生するのか、リアルタイムで
データーが送って来るのか?くりゅうさんのレスでデーターがリアルタイムで
送ってくることは判りました。混乱させて申し訳ない。
>波形表示しながら、「同時に」CSV形式のファイルに出力というのは可能なのでしょうか?
先ずエクセルで表示させたいと言うことが前提になっているようですが、
心電図のように波形が左に動いていく(ロールと言います)表示をエクセルにさせる事は
難しいのでは(多分)、ロールをさせたいのであればVBでPictureBox等に表示させて、そのPictureBox
を左に動かす様な構造にする必要があります。
VBで表示することにすると、データーはCSVの必要は無くBinary形式で保存すればいい事に
なります。この方がデーター量は1/5程度のなるでしょう。
データーの保存と表示は全く別物ですから、いずれのデーターにしろ表示と保存を
同時に行うことは可能です。
チャンネル数が1チャンネルでサンプリングが100Hz位ならかなりゆっくりとした
処理になりVBでも描画は十分に間に合うと思います。
又ファイルからの表示もサンプリングの周波数が決まっていればリアルタイムと同じスピード
で表示することは可能です。
少し難易度が高いと言ったのは、PictureBoxを左に動かしていくとPictureBoxの右端が来てしまいます
その為PictureBoxを2つ用意して適当にわからない様に切り替えるなどのテクニックが必要です。
これは他の方法もあると思いますが。
追加
>32CHなら32個接続可能ということになるのですか?
その通りです、心電図など測定の時体に数箇所べたべたと貼り付けますね、その貼り付けた分が全て違った
信号になります、つまりその分だけチャンネルが有ることになります。
通常は測定のときは多チャンネルのペンレコで波形を書かせていますね。
もしA/D変換ボードが多チャンネルINPUTの物なら、おそらくデジタルデーターは
チャンネルデーターが連続した形で送られてくるのでしょう。
掲示板違いって言われるかもわかりませんが・・・
VBAでやっちゃうのも手かも。(VBAでもMsCommは使えます)
1/100sec毎のデータ(受信サイクルはわかりませんが)をcellの行方向に
順番にセットしていくと、あらかじめ別シートで作成済みの折れ線グラフ
が自動的に更新されていきます。
cellに代入した後、DoEvents をお忘れなく。
多CHでも列方向にCH毎のデータをセットすればOKです。
・・・グラフのリアル表示もデータのエクセル保存も一網打尽です。
ねろさんの言うロールは以前MSのサイトでサンプルがのってました。
URLは忘れましたが、コードが掲載されていましたので参考にドウゾ。
ロールさせなくとも、左から右へ波形を書いて、
右端にきたら左端からっていう繰り返しなど手法は色々ありますが。
波形表示などにExcelを使用すると、
どうしてもその分のオーバーヘッドが出るので、
リアルタイム処理向きでは無いと思います。
VB単体で処理した方がいいでしょう。
>そのとおりです。波形表示しながら、
>「同時に」CSV形式のファイルに出力というのは可能なのでしょうか?
可能です。
Option Explicit
Private Const SRCCOPY = &HCC0020 ' (DWORD) dest = source
Private Const PS_SOLID = 0
Private Declare Function CreateCompatibleDC Lib "gdi32" _
(ByVal hdc As Long) As Long
Private Declare Function CreateCompatibleBitmap Lib "gdi32" _
(ByVal hdc As Long, _
ByVal nWidth As Long, _
ByVal nHeight As Long) As Long
Private Declare Function SelectObject Lib "gdi32" _
(ByVal hdc As Long, _
ByVal hObject As Long) As Long
Private Declare Function CreatePen Lib "gdi32" _
(ByVal nPenStyle As Long, _
ByVal nWidth As Long, _
ByVal crColor As Long) As Long
Private Declare Function LineTo Lib "gdi32" _
(ByVal hdc As Long, _
ByVal x As Long, _
ByVal y As Long) As Long
Private Declare Function MoveToEx Lib "gdi32" _
(ByVal hdc As Long, _
ByVal x As Long, _
ByVal y As Long, _
ByVal lpPoint As Long) As Long
Private Declare Function BitBlt Lib "gdi32" _
(ByVal hDestDC As Long, _
ByVal x As Long, _
ByVal y As Long, _
ByVal nWidth As Long, _
ByVal nHeight As Long, _
ByVal hSrcDC As Long, _
ByVal xSrc As Long, _
ByVal ySrc As Long, _
ByVal dwRop As Long) As Long
Private Const pWidth = 250 ' Width of picture box in pixels.
Private Const pHeight = 150 ' Height of picture box in pixels.
Private Const pGrid = 25 ' Distance between grid lines.
Private Const tInterval = 100 ' Interval between timer samplings
' in milliseconds.
Private Const pHeightHalf = pHeight \ 2
Dim counter As Long ' Number of data points logged so far. Used to
' sync grid.
Dim oldY As Long ' Contains the previous y coordinate.
Dim hDCh As Long, hPenB As Long, hPenC As Long
Private Sub Form_Load()
Dim hBmp As Long
Dim i As Integer
Me.Show
Picture1.ScaleMode = 3
Picture1.Left = 0
Picture1.Top = 0
Form1.ScaleMode = 3
Picture1.Height = 155
Picture1.Width = 255
counter = 0
hDCh = CreateCompatibleDC(Picture1.hdc)
hBmp = CreateCompatibleBitmap(Picture1.hdc, _
pWidth, _
pHeight)
Call SelectObject(hDCh, hBmp)
hPenB = CreatePen(PS_SOLID, 0, vbBlack)
hPenC = CreatePen(PS_SOLID, 0, vbRed)
Call SelectObject(hDCh, hPenB)
' Plot horizontal grid lines.
For i = pGrid To pHeight - 1 Step pGrid
Picture1.Line (0, i)-(pWidth, i)
Next
' Plot vertical grid lines.
For i = pGrid - (counter Mod pGrid) To _
pWidth - 1 Step pGrid
Picture1.Line (i, 0)-(i, pHeight)
Next
Call BitBlt(hDCh, _
0, _
0, _
pWidth, _
pHeight, _
Picture1.hdc, _
0, _
0, _
SRCCOPY)
'Timer1.Interval = 1
'Timer1.Enabled = True
oldY = pHeightHalf
'Call API_Graph
End Sub
Private Sub API_Graph()
Dim i As Integer
Do
Call BitBlt(hDCh, _
0, _
0, _
pWidth - 1, _
pHeight, _
hDCh, _
1, _
0, _
SRCCOPY)
If counter Mod pGrid = 0 Then
Call MoveToEx(hDCh, pWidth - 2, 0, 0)
Call LineTo(hDCh, pWidth - 2, pHeight)
End If
i = Sin(0.1 * counter) * _
(pHeightHalf - 1) + _
pHeightHalf
Call SelectObject(hDCh, hPenC)
Call MoveToEx(hDCh, pWidth - 3, oldY, 0)
Call LineTo(hDCh, pWidth - 2, i)
Call SelectObject(hDCh, hPenB)
Call BitBlt(Picture1.hdc, _
0, _
0, _
pWidth, _
pHeight, _
hDCh, _
0, _
0, _
SRCCOPY)
counter = counter + 1
oldY = i
DoEvents
Loop
End Sub
Private Sub Timer1_Timer()
Dim i As Integer
Call BitBlt(hDCh, _
0, _
0, _
pWidth - 1, _
pHeight, _
hDCh, _
1, _
0, _
SRCCOPY)
If counter Mod pGrid = 0 Then
Call MoveToEx(hDCh, pWidth - 2, 0, 0)
Call LineTo(hDCh, pWidth - 2, pHeight)
End If
i = Sin(0.1 * counter) * _
(pHeightHalf - 1) + _
pHeightHalf
Call SelectObject(hDCh, hPenC)
Call MoveToEx(hDCh, pWidth - 3, oldY, 0)
Call LineTo(hDCh, pWidth - 2, i)
Call SelectObject(hDCh, hPenB)
Call BitBlt(Picture1.hdc, _
0, _
0, _
pWidth, _
pHeight, _
hDCh, _
0, _
0, _
SRCCOPY)
counter = counter + 1
oldY = i
End Sub
>ぴろあきさん
こんなサンプルが有ったんですね、完璧です、驚きました。
これだとロールバックも簡単に出来そうですね。
得した気分です。
オリジナルらしきサイトを探しておきました。
http://www.visualbasiccode.com/asp/showsn.asp?theID=727
ぴろあきさん探していたものが見つかりました。
ありがとうございます。
私は年寄り初心者なので、内容は全て理解できたわけではあり
ませんが、勉強させていただきます。
初心者ながら、初心者向けにサンプルを作って見ました。
まったく初心者が書いた単純なサンプルで理解はしやすいと思
いますが・・・・・。
ぴろあきさんのご提示いただいたサンプルとは、まったく比較
になりませんが、初心者には理解しやすいかなと思って(自分
も初心者なもんで)あえて提示させていただきます。
くりゅうさんも初心者かなって思って書きました。参考になれ
ばいいのですが、まったく余計なおせっかいかもわかりません。
失礼なレスであれば即、無視してください。
Public OLD_X As Integer
Public OLD_Y As Integer
Public LAST_Y As Integer
'####################################################################
' フォーム表示時の初期処理
'####################################################################
Private Sub Form_Load()
Me.Width = 10365 'フォーム・ピクチャボックスの大きさ設定
Me.Height = 6720
Me.Picture1.Width = 10000
Me.Picture1.Height = 5550
Me.Picture1.Left = 120
Me.Picture1.Top = 240
Me.Picture1.BackColor = RGB(0, 0, 0) '背景色を黒に設定
SCALE_DRAW '目盛を描画
End Sub
'####################################################################
' 目盛の表示
'####################################################################
Sub SCALE_DRAW()
Me.Picture1.AutoRedraw = True
Me.Picture1.DrawWidth = 1
Me.Picture1.DrawStyle = 0
Me.Picture1.ForeColor = RGB(50, 110, 50)
For OLD_X = 0 To 10000 Step 300
Me.Picture1.Line (OLD_X, 0)-(OLD_X, 5550)
Next OLD_X
For OLD_Y = 0 To 5550 Step 300
If OLD_Y = 2700 Then '水平位置基準線
Me.Picture1.DrawWidth = 1.3 '若干太め
Me.Picture1.DrawStyle = 2 '鎖線
Me.Picture1.ForeColor = RGB(0, 220, 0) '明るい色
Else '標準目盛線
Me.Picture1.DrawWidth = 1 '標準の太さ
Me.Picture1.DrawStyle = 0 '目盛標準線
Me.Picture1.ForeColor = RGB(50, 110, 50) '目盛標準色
End If
Me.Picture1.Line (0, OLD_Y)-(10000, OLD_Y)
Next OLD_Y
OLD_Y = 0
OLD_X = 0
End Sub
'####################################################################
' データ表示のクリア
'####################################################################
Sub DATA_CLR()
Me.Picture1.Cls '画面全消去
SCALE_DRAW '目盛を描画
End Sub
'####################################################################
' テスト表示
'####################################################################
Private Sub Timer1_Timer()
Dim X As Integer
Dim Y As Integer
Dim TTT As Integer
Me.Timer1.Interval = 200
Me.Picture1.ForeColor = RGB(255, 255, 255)
TTT = 80
Y = Int(Rnd * 3500)
Me.Picture1.Line (OLD_X, OLD_Y)-(OLD_X + TTT, Y)
OLD_X = OLD_X + TTT
OLD_Y = Y
If OLD_X > 10000 Then
LAST_Y = OLD_Y
DATA_CLR
OLD_X = 0
OLD_Y = LAST_Y
End If
End Sub
「年寄りの冷や水」さんのコードを殆どお借りしてロールをしてみました。
Picture1を配列で2つ用意して
Appearance->フラット
BorderStyle->なし
の設定とします、若干Picture1(0)とPicture1(1)の繋ぎ目が
不自然となる場合があります。これを直すとコードがわかりにくく
なるので、とりあえず。
Option Explicit
Const TTT = 80
Private Sub Form_Load()
Dim n As Integer
Me.Width = TTT * 120 'フォーム・ピクチャボックスの大きさ設定
Me.Height = 6720
For n = 0 To 1
Picture1(n).Width = Me.Width
Picture1(n).Height = 5550
Picture1(n).Left = 0
Picture1(n).Top = 240
Picture1(n).BackColor = RGB(0, 0, 0) '背景色を黒に設定
SCALE_DRAW n
Next
Picture1(1).Left = Picture1(0).Left + Picture1(0).Width
Timer1.Interval = 50
Timer1.Enabled = True
End Sub
Sub SCALE_DRAW(n)
Dim OLD_X As Integer, OLD_Y As Integer
Picture1(n).AutoRedraw = True
Picture1(n).DrawWidth = 1
Picture1(n).DrawStyle = 0
Picture1(n).ForeColor = RGB(50, 110, 50)
For OLD_X = 0 To 10000 Step 300
Picture1(n).Line (OLD_X, 0)-(OLD_X, 5550)
Next OLD_X
For OLD_Y = 0 To 5550 Step 300
If OLD_Y = 2700 Then '水平位置基準線
Picture1(n).DrawWidth = 1.3 '若干太め
Picture1(n).DrawStyle = 2 '鎖線
Picture1(n).ForeColor = RGB(0, 220, 0) '明るい色
Else '標準目盛線
Picture1(n).DrawWidth = 1 '標準の太さ
Picture1(n).DrawStyle = 0 '目盛標準線
Picture1(n).ForeColor = RGB(50, 110, 50) '目盛標準色
End If
Picture1(n).Line (0, OLD_Y)-(10000, OLD_Y)
Next OLD_Y
Picture1(n).ForeColor = RGB(255, 255, 255)
OLD_Y = 0
OLD_X = 0
End Sub
Private Sub Timer1_Timer()
Draw
End Sub
Private Sub Draw()
Dim Y As Integer
Static OLD_X As Integer
Static OLD_Y As Integer
Y = Int(Rnd * 3500)
'描画が端に来たらPictureを切り替える
If OLD_X > Picture1(0).Width Then
If Picture1(0).Left < Picture1(1).Left Then
Picture1(0).Left = Picture1(1).Left + Picture1(1).Width
Picture1(0).Cls
SCALE_DRAW (0)
Else
Picture1(1).Left = Picture1(0).Left + Picture1(0).Width
Picture1(1).Cls
SCALE_DRAW (1)
End If
OLD_X = 0
End If
'常に右側のPictureに描画
If Picture1(0).Left < Picture1(1).Left Then
Picture1(1).Line (OLD_X, OLD_Y)-(OLD_X + TTT, Y)
Picture1(0).Left = Picture1(0).Left - TTT
Picture1(1).Left = Picture1(0).Left + Picture1(0).Width
Else
Picture1(0).Line (OLD_X, OLD_Y)-(OLD_X + TTT, Y)
Picture1(1).Left = Picture1(1).Left - TTT
Picture1(0).Left = Picture1(1).Left + Picture1(1).Width
End If
OLD_X = OLD_X + TTT
OLD_Y = Y
End Sub
ツイート | ![]() |