• ベストアンサー

正弦波DATAの各サイクルでの位相を求めるプログラムについて

いつもお世話になっております。VB超初心者です。 現在VB6にてオシロ測定DATAの解析プログラムを作成しています。 DATAは電圧-時間の正弦波が約100サイクル続くDATAです。 この正弦波の各位相0°に相当するポイント(-→+へ移る際の0ポイント)をピックアップしていきたいのですが+-の境目で数値がバタつき、 うまく0°の場所を拾えず180°も拾ってしまいます。 数値の並びは-→+の境目は下記のかんじで -0.16 -0.16 0 -0.08 -0.08 -0.16 -0.08 -0.08 -0.08 -0.08 0 0 -0.08 -0.08 -0.08 -0.08 -0.08 0 -0.08 -0.08 -0.08 0 -0.16 -0.08 -0.08 0 とここから0が増えて+が現れる感じです。バタつきの幅や並びの傾向 から下記のプログラムをとりあえず作ったのですが結果は180°も 一緒に拾ってしまいます。カウント10で1ポイント拾うものなので 20で拾わずにカウント0に戻せばいいのでしょうか? というよりSGN関数使うとかすべきなのでしょうか?何かいいやり方 ありませんか? Private Sub StartCommand_Click() Dim rs, r: Dim ws, w: Dim rLine As String Dim wLine As String Dim nowVolt As Double Dim beforeVolt As Double Dim start As Integer Dim counter As Integer Dim point As Integer Dim LineX '事前準備 Set rs = CreateObject("Scripting.FileSystemObject") Set r = rs.OpenTextFile(ReadFile.Text, 1) Set ws = CreateObject("Scripting.FileSystemObject") Set w = _ ws.CreateTextFile(WriteFile.Text, True) counter = 0 point = 0 nowVolt = 0 beforeVolt = 0 start = 0 Last = 0 '実際の計算 Do Until r.AtEndOfStream '電圧値取得 rLine = r.readLine LineX = Split(rLine & ",,,,,,,", ",") nowVolt = Val(LineX(4)) 'ゼロ点検出用カウンタ処理 If (beforeVolt < 0) Then If (nowVolt >= 0) Then counter = counter + 1 End If End If 'ゼロ点検出処理 If counter = 1 Then start = point End If If counter = 10 Then Last = LineX(3) wLine = Last w.WriteLine (wLine) counter = 0 End If '次処理 beforeVolt = nowVolt Loop '事後処理 r.Close: w.Close: End Sub

質問者が選んだベストアンサー

  • ベストアンサー
回答No.10

Do Until r.AtEndOfStream   rLine = r.readLine   LineX = Split(rLine & ",,,,,,,", ",")   Xdat(XdatP) = Val(LineX(4))   Xtime(XdatP) = Val(LineX(3))   XdatP = XdatP + 1   If XdatP > 10 Then XdatP = 1   newVolt = Xdat(1) + Xdat(2) + Xdat(3) + Xdat(4) + Xdat(5) +        Xdat(6) + Xdat(7) + Xdat(8) + Xdat(9) + Xdat(10)    If newVolt > 0 And beforeVolt < 0 Then     XdatPw = Xdat(5) = Last       <=== ここはおかしい     If XdatPw < 1 Then XdatPw = XdatPw + 10     Last = LineX(3)       <=== ここはおかしい     wLine = Last     w.WriteLine (wLine)   End If   beforeVolt = newVolt Loop 正しくは、 Do Until r.AtEndOfStream   rLine = r.readLine   LineX = Split(rLine & ",,,,,,,", ",")   Xdat(XdatP) = Val(LineX(4))   Xtime(XdatP) = Val(LineX(3))   XdatP = XdatP + 1   If XdatP > 10 Then XdatP = 1   newVolt = Xdat(1) + Xdat(2) + Xdat(3) + Xdat(4) + Xdat(5) +        Xdat(6) + Xdat(7) + Xdat(8) + Xdat(9) + Xdat(10)    If newVolt > 0 And beforeVolt < 0 Then     XdatPw = XdatP-5     If XdatPw < 1 Then XdatPw = XdatPw + 10     Last = Xtime(XdatPw)     wLine = Last     w.WriteLine (wLine)   End If   beforeVolt = newVolt Loop また29の移動積分では、 Do Until r.AtEndOfStream   rLine = r.readLine   LineX = Split(rLine & ",,,,,,,", ",")   Xdat(XdatP) = Val(LineX(4))   Xtime(XdatP) = Val(LineX(3))   XdatP = XdatP + 1   If XdatP > 29 Then XdatP = 1   newVolt = Xdat(1) + Xdat(2) + Xdat(3) + Xdat(4) + Xdat(5) +・・・・・・+Xdat(25) + Xdat(26) + Xdat(27) + Xdat(28) + Xdat(29)    If newVolt > 0 And beforeVolt < 0 Then     XdatPw = XdatP-14     If XdatPw < 1 Then XdatPw = XdatPw + 29     Last = Xtime(XdatPw)     wLine = Last     w.WriteLine (wLine)   End If   beforeVolt = newVolt Loop 上の様になおして処理した場合は?

raphael01
質問者

お礼

ありがとうございました!結局If newVolt > 0 And beforeVolt <= 0 Then にする事で0点は100%抜き取りが出来、180°が2~3点入る感じですが ほぼ目標に達する事ができました。 勉強になりました。また、宜しくお願い致します。

その他の回答 (9)

回答No.9

ごめんなさい。よく考えてみると、ADボードからデータを採っているのでは なかったのですね。勘違いしておりました。深く謝ります。 オシロが自動的にADデータをフロッピーに落とすタイプのを使っているのですね。 プログラムでは、そのデータを読んでいるだけだったのです。 僕は、てっきりパソコンでADデータを採って、後から解析しているのだと思って いました。 オシロが採集したADデータでもいかないのなら、また話は別かも。 でも、理論的には、あのプログラムでいくはずです。そうでないと、世の中の数式が すべて通らなくなる事になります。 なぜ、生データに問題があるのか、わかりません。オシロの性能によるものかもしれません。 高機能なタイプでないといけないとか?。そういえば、ADのデータって、0.02secの周期 だから、丁度50Hzですね。一体なんのデータなんですか。参考までに聞かして頂ければ 幸いです。今後の私の勉強の為にも。 あの、その生データを1000個づつ分けて、1000ファイルに落とし、適当に抜き打ちで ランダムな任意の30個ほどのファイルを一度エクセルでグラフを描いたらどうです。 そこそこ、綺麗な正弦波形をなしているのか確認するもの方法です。 それか、VBで1000個づつ、読んで連続れグラフを描くプログラムを作成すれば。 20ステプもあればできます。マウスをクリックする度に、1000個ずつ読んでグラフを 描かすのです。 そうすれば、なにか手がかりがつかめるかも?。

回答No.8

最終的になにをどの様にしたいのかイマイチのみこめまないです。 ただ言えるのは、ADで電圧データをとるのに、軽くみていると 思います。 ちなにみどこまでADに関して詳しいのでしょう?。 今回の場合は、特殊で、やはりボードの選定とかは事前にされたのでしょうか?。 どんなADボードでも良いと思っていたらおおきな間違いです。 普通だと、どんなボードでもよいと思います。 しかし、サンプリング周期が早い場合、充分検討する必要があるのです。 サンプリング周期が20マイクロsecだから、普通にポーリング方式で採って いると、VBでは遅くてとてもとれません。データの欠落が必ずでます。 まず、ボードの仕様は最低でもDMA転送のついているタイプでないと駄目です。 DMA転送は、これは、高速で、ボードのデータをパソコンのメモリに転送する 方式です。これがないとまず駄目です。 DMA転送とは、どの様にハード的に動作をするかご存知ですか?。 あと、サンプリング方法ですが、FIFO方式かポーリング方式の2種類が ありますが違いを把握していますか?。 今回は、サンプリング周期が20マイクロsecだから、当然FIFO方式で ないと駄目です。 ボードには、256MB程のメモリが最低でも搭載されているタイプを勿論 選定されたのでしょうね。メモリがのっていないと、今回の場合は絶対無理です。 あと、ボードの最大サンプリング周期を調べたのでしょうね。ADボードなら なんでも良いとなりません。ボードによって、最大サンプリング周期は決まって います。当然安いボードだと、マイクロ秒で採ることは不可能です。 パソコンでいくら早くにADデータを採りにいっても、ADボードの感応速度が 遅いと、同じデータが帰ってきます。 私は、まず、仕事を掛かる前に、どの様なデータを採るかによって、ボードの種類 選択を考えます。今回の仕事にあったボードをまず選びます。 ごぞんじですか?。仮に1メーカーだけでも、ADボードの種類がどれだけあるか?。 概算ですが、30種類程最低でもあります。それは、データを採る内容によって、 安いのから高いのまで揃えているからです。なぜかと言えば、10ミリsec位でしか サンプリングしないのに、わざわざ、マイクロsecで採るボードは必要ないからです。 >あとは、この前検出したパルスピークの位相が分かれば完成なのですが。 >この位相ゼロ点とパルスピークの時間値を合わせれば位相は出ますよね? うー。直感だけど、無理だと思います。なぜなら、前回のはノイズ対策をして いないからです。そこまで、質問内容だけでは分からないから。 また、前回のプログラムと今回のプログラムは別々に動作するのだから、 それを抱き合わして、1本のデータにする事は、仮に時間軸が合っているから としても、無理があります。やはり、前回のと今回のとを同時に処理をする プログラムでないとデータの整合性は取れないとおもいます。

回答No.7

ADボードはどこのメーカーですか?。 私は、コンテックとインターフェースのADボードはよく 使います。 ボードと使用している関数を教えて下さい。 どうみても、生データに問題がるとおもう?。 それと、サンプリング方法です。大概どこのメーカーも FIFO方式かポーリング方式の2種類があります。 この場合、FIFO方式でないと無理です。 また、安いボードだとポーリング方式しかないのがあります。 先ほども言いましたが、1サイクル1000個の電圧データ なのだから、1サイクル内で、連続29個以上プラスVと29連続 マイナスVが存在しているはずだから、1000サイクルこれが 繰り返されるのだから、絶対に取れるポイントが1000を割ることは ないと思います。理論的にありえない。

raphael01
質問者

補足

お世話になっております! ADボードと使用してる関数ですか??リースのオシロで一旦返して しまい、よく分からないんです。 現在生データの内容をチェックしてます。確かに基本的に検出出来る はずですよね。 あとは、この前検出したパルスピークの位相が分かれば完成なのですが。この位相ゼロ点とパルスピークの時間値を合わせれば位相は 出ますよね?

回答No.6

1000サイクルとも0Vを中心に正弦波になる様になっていると、 本来なら、理論的に取れるポイントの数が1000より少なくなる事は ありえないはずだと思います。移動積分にせよ、移動平均にせよかならず、 マイナスVからプラスVに1000回移動するはずです。 もし、これがその様にならないく、少なくあがるとの事でしたら、 (1)電圧の生データが、電圧の中心が0Vよりやはりずれているか、 (2)山と谷との電圧の差がすくないか、 (3)サンプリング周期は早いので、ADボードからデータを読み込む時に  データの欠落が出来ているかしか考えられないと思います。 本来1サイクルの1000個の電圧データで、連続して29個以上プラス側の データと、連続して29個以上マイナス側のデータがあるはずですから。 ただし、電圧データの中心が0Vであるとの前提です。 この理屈からいくと、かならず、1000個以上取れるのが普通です。 1000以上ともうしたのは、ノイズがあるからです。 あと、考えられるのは、ADボードの感度精度がわるく、20マイクロsecの感度 で反応しないものなのか。安いボードだと、サンプリング周期が20マイクロsec に対応していないのがある。

回答No.5

少し内容が把握できてきました。 サンプリング点数がそう言えば、すごく多いみたいですね。 今回の回答で初めてしりました。 1サイクル0.02秒でしかも、1サイクル1000点のデータと なると、1データ20マイクロsecとなります。 かなり早いですね。 ちなみに、ききたいのですが、ADボードでのサンプリングは、 FIFOでサンプリングしているのですか?。 一旦ボードのメモリに蓄えるタイプて、遅れて読み込んでいる のでしょうね?。 どの様にサンプリングされているのですか?。 あと、1サイクル1000点となっているので、やはり29点でも よいかもしれません。 ちなみに、電圧の山と谷との差は平均でいくら?。 平均の最大と最小の幅はいくら?。教えて下さい。 この幅が小さいと、ノイズが乗りやすいで、演算以前の問題になかも。 これが余り小さいと、その他の手をかんがえなくてはいけないと思う。 もちろん、全データの電圧の平均は、勿論0Vなのでしょうね。 もし、全電圧データの平均が0Vよりずれておれば、補正しないといけません。 また、1000サイクルすべての電圧は、位相0℃は必ず0Vになるのですか?。 Do Until r.AtEndOfStream   rLine = r.readLine   LineX = Split(rLine & ",,,,,,,", ",")   Xdat(XdatP) = Val(LineX(4))   Xtime(XdatP) = Val(LineX(3))   XdatP = XdatP + 1   If XdatP > 10 Then XdatP = 1   newVolt = Xdat(1) + Xdat(2) + Xdat(3) + Xdat(4) + Xdat(5) +        Xdat(6) + Xdat(7) + Xdat(8) + Xdat(9) + Xdat(10)    If newVolt > 0 And beforeVolt < 0 Then     XdatPw = Xdat(5) = Last       <=== ここはおかしい     If XdatPw < 1 Then XdatPw = XdatPw + 10     Last = LineX(3)     wLine = Last     w.WriteLine (wLine)   End If   beforeVolt = newVolt Loop

回答No.4

下のデータの意味は時間ですか?。 -0.989974 -0.969974 -0.949952 -0.909958 -0.889956 -0.869952 -0.829954 -0.809964 -0.78996 -0.769964 -0.729962 -0.719956 -0.709968 -0.689948 -0.66994 -0.649928 -0.609936 -0.59995 なるほど、3サイクルまで拾っていますね。 ちなみに、サンプリング電圧データの最大値と最小値はいおおむねいくらなのですか?。 それによって、プログラムを多少考慮する必要があるので。電圧の最大と最小の幅が小さいと 10データの移動積分でないと駄目だと思います。 恐らく29の移動積分はおおいです。最小に述べている様に10データの移動積分で充分だと 思います。 最初の回答で、1℃とたとえばの話で述べています。しかし、最後に、1℃にこだわる必要 がなく、データ点数は10の移動積分でいいと結論付けていると思います。 たぶん、29の移動積分は点数が多いとおもう?。ノイズがそれほどのっていないので。 10の移動積分方式では、どうなりました?。教えて下さい。

raphael01
質問者

補足

お世話になってます。あの値はLineX(3)の時間値です。 10の場合、41ポイント取れて -0.949962 -0.849964 -0.769986 -0.74997 -0.68996 -0.669974 -0.529956 -0.42993 -0.389944 -0.379946 -0.189926 -0.18992 -0.129952 -0.049936 -0.009908 0.000034 この様な感じです。時間値は1.000046~-0.99992です。最初の0点は -0.98997あたりでそこから0.02間隔、1サイクル10000ポイントです。 プログラムは Private Sub StartCommand_Click() Dim rs, r: Dim ws, w: Dim rLine As String Dim wLine As String Dim Xdat(10) As Double Dim XdatP As Integer Dim XdatPw As Integer Dim Xtime(10) As Integer Dim beforeVolt As Double Dim newVolt As Double Set rs = CreateObject("Scripting.FileSystemObject") Set r = rs.OpenTextFile(ReadFile.Text, 1) Set ws = CreateObject("Scripting.FileSystemObject") Set w = _ ws.CreateTextFile(WriteFile.Text, True) XdatP = 1 Do Until r.AtEndOfStream rLine = r.readLine LineX = Split(rLine & ",,,,,,,", ",") Xdat(XdatP) = Val(LineX(4)) Xtime(XdatP) = Val(LineX(3)) XdatP = XdatP + 1 If XdatP > 10 Then XdatP = 1 newVolt = Xdat(1) + Xdat(2) + Xdat(3) + Xdat(4) + Xdat(5) +        Xdat(6) + Xdat(7) + Xdat(8) + Xdat(9) + Xdat(10)  If newVolt > 0 And beforeVolt < 0 Then XdatPw = Xdat(5) = Last If XdatPw < 1 Then XdatPw = XdatPw + 10 Last = LineX(3) wLine = Last w.WriteLine (wLine) End If beforeVolt = newVolt Loop r.Close: w.Close: End Sub です。データの並びをもっと把握すべきなのでしょうか?

回答No.3

>1サイクル10000ポイントで1°あたり29ポイント取ってみて 29個の移動積分を取っているとの事ですか? その場合は下の様にしているとの事ですか? dim Xdat(28) as double dim XdatP as integer dim XdatPw as integer dim Xtime(28) as integer dim beforeVolt as double dim newVolt as double XdatP=1 Do Until r.AtEndOfStream   rLine = r.readLine   LineX = Split(rLine & ",,,,,,,", ",")   Xdat(XdatP)=Val(LineX(4))   Xtime(XdatP)=Val(LineX(3))   XdatP=XdatP+1   if XdatP>10 then XdatP=1   newVolt=Xdat(1)+Xdat(2)+Xdat(3)+Xdat(4)+Xdat(5)+Xdat(6)+Xdat(7)+.....+Xdat(27)+Xdat(28)   if newVolt>0 and beforeVolt<0 then     XdatPw=XdatP-5     if XdatPw<1 then XdatPw=XdatPw+10     Last = Xtime(XdatPw)     wLine = Last     w.WriteLine (wLine)   end if   beforeVolt = nowVolt Loop あと、下の数字は、newVolt の値になるのですか? -0.989974 -0.969974 -0.949952 -0.909958 -0.889956 -0.869952 -0.829954 -0.809964 -0.78996 -0.769964 -0.729962 -0.719956 -0.709968 -0.689948 -0.66994 -0.649928 -0.609936 -0.59995 >この様に79ポイント拾えます。 これの意味は、1ポイントから79ポイントの値がこれとの意味? >実際の0ポイントは0.02間隔で現れる >はずなので3ポイント目までは拾っているのですが、あとは駄目です。 >値のバタつきが不規則だからでしょうか この3ポイント目まで拾えるの意味を教えて下さい。 バタつきが不規則は、今の所、データをみる限り、問題ないと思います。 ノイズがそれほどひどくないので。通常だと、ノイズがあれば、もっと 電圧が変動します。 もし、差し支えなければ、ソースを載せてくれます?。 チェックしてみます。

回答No.2

質問はこの前の続きですね。 計測データですね。特に電圧は当然、フラツクものです。また多少のノイズもあるのかもしれな。 見た目は奇麗な正弦波でも、電圧は必ずフラツイているものと思って処理をする必要があります。 単に、マイナスからプラスに変わった時とか、マイナスからプラス方向に変わった回数が10に なったからとかしてもうまくいきません。なぜなら、ご指摘の通り位相が180°ずれたところでも 当然電圧がフラツイているから、位相が180°のところと位相0°のところは同じ現象になり必ず 180°ごとにデータを拾うことになります。当たり前と言えば当たり前です。 この場合の解決手段は、正弦波のグラフを書いて、そのグラフを眺めれば、自然と解決手段が 出てきます。 ここで、図を提示す事が難しいので、頭の中でイメージを描いて下さい。 正弦波なので、ある程度きれいなサインカーブを描いているとして、プラス側の半弦、マイナス側の半弦 が交互に出るイメージですね。この場合、そのカーブ線が拡大するとフラツイいる。 でも、データを積分すれば、はっきりとマイナス点からプラス点の境目がはっきりと出る事が分かります。 この積分すれば、位相が180°ずれたとところは、必ず、プラス点からマイナス点の移動と判定される ので、位相が180°ずれたところは拾うことはなくなります。 じゃー。この積分方法はどうするのかってことだね。 積分=面積となる。要するに面積を考えて、プラス側の面積、マイナス側の面積を考えて、マイナス側の 面積とプラス側の面積の境目が位相ゼロ点となります。 じゃー。今度はこの面積をどうするかだ。 正弦波のイメージを描いて下さい。0°から760°の2正弦波があるイメージ紙に描いて下さい。 この紙に描いたグラフを0°から760°の間を760等分にして、1°ごとの正弦波の面積を求めるのです。 当然1°ごとの正弦波の面積を180個足せば、半弦の面積、360個足せば1正弦波、760個足せば2正弦波 になります。当然です。分割したのを集めるだけですから。 この1°ごとの面積を計算して、この面積がマイナス側の面積からプラス側の面積に変わったとこと から0.5°戻った所がほぼ位相0°の点になるのです。 あなたの質問されている方法は、点で求めているから駄目なのです。面積を求めていれば、フラツキ はカバーできるのです。 じゃー。この1°ごとの面積はどうして求めるの?。 実は大変簡単なのです。面積=積分=足し算となるのです。 サンプリング周期がどれだけかわかりません。1正弦波のサンプリング点数の概算を最初に机上で 計算しておきます。大体でよいと思います。仮に1正弦波の測定データがきりのよい3600点として おきましょう。当然1°のデータ点数は10点となります。 この場合、1°分の面積とは、最終的に、単に測定データ10点の足し算(積分=面積)となります。 10点ごとの足し算した合計値を順番に比較していき、この各1°ごとの合計値がマイナスからプラスに 変わった時点が位相0°付近になります。付近だからその点から0.5°さかのぼったところが位相0°に なると予測できます。 ここからプログラムはどうするか。概略でのべると 仮に1正弦波の測定データがきりのよい3600点として 測定データを10点ずつの合計値をもとめる。その各合計値のマイナス側からプラス側にかわったとこと から、そのデータ点数(10点)の中間点が答えです。 ここで更に注意点を少し。 1正弦波のサンプリング点数が概ね3600点以下の場合。たとえば、1正弦波のデータ点数が360点だと 1°のデータ点数は1個になり、これでは意味がない。データのフラツキがカバー出来ない。 その時は1°の面積ではなく、10°の面積で考えなくてはいけない。ここから想像すると1正弦波の データ点数を360で割った数で足し算するのではなく、最初からたえず10点の合計値で出すだけで よい事が想像できる。要するにこだわるのは1°ではなく点数って事になります。 データのフラツキがおおきれば、10点を15点、20点と増やしていきます。サンプルデータでみる限りでは 10点から15点で充分だとおもいます。 更に精度を上げるのであれば、移動積分法をで求めるとよいです。 下のプログラムは10点の移動積分法です。 dim Xdat(10) as double dim XdatP as integer dim XdatPw as integer dim Xtime(10) as integer dim beforeVolt as double dim newVolt as double XdatP=1 Do Until r.AtEndOfStream   rLine = r.readLine   LineX = Split(rLine & ",,,,,,,", ",")   Xdat(XdatP)=Val(LineX(4))   Xtime(XdatP)=Val(LineX(3))   XdatP=XdatP+1   if XdatP>10 then XdatP=1   newVolt=Xdat(1)+Xdat(2)+Xdat(3)+Xdat(4)+Xdat(5)+Xdat(6)+Xdat(7)+Xdat(8)+Xdat(9)+Xdat(10)   if newVolt>0 and beforeVolt<0 then     XdatPw=XdatP-5     if XdatPw<1 then XdatPw=XdatPw+10     Last = Xtime(XdatPw)     wLine = Last     w.WriteLine (wLine)   end if   beforeVolt = nowVolt Loop 尚、上のプログラムは思いつきで上げております。デバッグしていません。 概ねこの様な感じってことです。些細ところでバグがあれば、そこは考慮してください。

raphael01
質問者

お礼

お世話になっておりますっ!すごいです。わかりやすく、しかも 考えてもいなかった考え方で勉強になります。 早速、この土日で奮闘してみます!ありがとうございます。

raphael01
質問者

補足

いろいろとやってみているのですが、ポイントを拾いきれません。 1サイクル10000ポイントで1°あたり29ポイント取ってみて -0.989974 -0.969974 -0.949952 -0.909958 -0.889956 -0.869952 -0.829954 -0.809964 -0.78996 -0.769964 -0.729962 -0.719956 -0.709968 -0.689948 -0.66994 -0.649928 -0.609936 -0.59995 この様に79ポイント拾えます。実際の0ポイントは0.02間隔で現れる はずなので3ポイント目までは拾っているのですが、あとは駄目です。 値のバタつきが不規則だからでしょうか?

noname#259269
noname#259269
回答No.1

データをある程度バッファに入れていき、ゼロ→最初のプラス値になった位置でバッファをさかのぼって、最初のマイナス値の位置を取得。両者の中間点が0°ポイント。 180°の時はプラスとマイナスの判定を逆転させる。 こんなのはどうでしょう。

raphael01
質問者

お礼

ありがとうございますっ参考になります!早速チャレンジしてみます。

関連するQ&A

専門家に質問してみよう