すいません。後半部分が読みにくいので...。
アイススケーター、Bosscatさんがご指摘の転送速度がネックになっている
のだと思うのですが、HDDへの書き込みが遅く、命令が終わっていても、
4,5分はデータを保存し続けていました。上のfor分で「任意に設定する」
を100とか設定してしまうと、バッファーからデータがあふれてしまい、
今度は本当にデータが完全に保存されないのではと考えています。
とりあえず、対策としてはHDDへの書き込み速度をみて、モータの移動速度を
遅くしたり、タイマー等(SetTimer関数で良いのかな?)を使い、時間稼ぎして
みようと思います。
共有メモリを使用して、ファイルと連携を取り、クローズ時に自動的に保存する方法も
ありますよ。
HDD側も内部にバッファを持っているでしょうし、
OS側も内部にバッファを持っていると思います。
バッファが空いていれば、関数はバッファに書き込んで
復帰するので実際の書き込み動作がHDD側で行われていても
気にする必要は無いと思います。
両方のバッファがいっぱいになれば、実際の書き込み関数が内部で待たされる
はずです。この辺の書き込み動作の保証が無いとこういった書き込みバッファの
存在自体に意味がなくなるのでデータが紛失する事は無いと思います。
それに結果的に関数からの復帰が遅れるのでタイミングも大丈夫なんではないか
と思います。
問題になるとすれば、書き込み関数から復帰した後の
一連の動作(モーター制御、トリガー発生、計測開始)が
どこかで間に合わないと言うような事が起これば問題かもしれません。
(これは書き込みに時間がかかると言う話とは別の話になりますね)
私が心配していたのはモーター制御の開始が全く別の周期で行われている。
(例えば、別スレッドに単独にタイミング取りしている)
だとすると、保存時間がかかっていてもモーターの制御はかまわず動作して
しまうと思うので結果的に間に合わないと言うことがあるという点でした。
今の話ならモーター制御は保存の後にしか行われないようなので
仮に保存に時間がかかってもモーター制御が保存関数が動作中に
行われるような事は無いと思うので大丈夫ではないかと思います。
ふと思ったんですが、
データの保存タイミングってどういうタイミングなんですかねぇ。
サンプリングと保存を一周期で回してしまうとバッファがいっぱいになった
タイミングで書き込みで待たされると思いますが、
そうなるとサンプリングに間に合わないと言う自体もありえると思います。
サンプリング中はメモリに貯めておいて一気に書き込みというのであれば、
杞憂かもしれませんけれど。
少し疑問があるのですが・・・
もじもじくんさんのプログラムを見ると
ファイル書き込みとデータ取得が1000回ループの中にあるので
HDDの速度にデータ取得が引きづられませんか?
取りこぼし無しのデータであることが保証されていません。
質問1)
外部トリガーとの同期はどうしているのでしょうか?
トリガーの取りこぼしや、重複取り出しが検出できていない。
上のプログラムでは、データ数は1000回ループなので必ず1000個分のデータが取れるでしょう
が、重複や取りこぼしを検出できていないのでは?
(外部トリガなら1000回打たれたのか1001回打たれたのか解らないのでは?)
そこで、ファイル書き込みWriteFile()?を非同期(オーバーラップ)にすると
WriteFile()自体は瞬間的に復帰しますが、こんどは、
書き込みバッファが溢れてしまう(エラー検出はできます)可能性があります。
(私が最初に指摘した「ハードウェアの限界」)
質問2)
全体のデータ数が2G超えなのは何故でしょう?
以下の認識であってますか?
・1トリガー64kのデータが発生する。
・1000トリガーで1纏まり(64M)
・そのデータを何個も纏めて取って同じファイルに書き込む。
また、この場合、纏める単位に何か関連がありますか?(時間等)
関連があるなら、全体を考えなければならないので、、、
次に、SetTimerの話ですが、、
これも一番最初に示した通り、20msec以下は正確に動かないと思います。
これは、OSのスレッド管理の問題です。
結果、やはりトリガーの取りこぼしが発生するでしょう。
> アイススケーター、Bosscatさんがご指摘の転送速度がネックになっている・・・
私はHDDの書き込み速度(ほぼそれだけ)を気にしています。
更に、プログラムはメモリーに書き込んだつもりでも
OSの仮想メモリ機構によってHDDアクセスが発生し(ただでさえ高負荷なHDDに)
HDD余計なアクセスが発生してしまうことを懸念しています。
思い切って 「仮想メモリを無効にしてしまう」 手もあるかもしれない。
最後に、このシステムでは、恐らく以下の事が重要です。
①データの取りこぼしが無いことが最優先
②HDDアクセスを効率的に行うこと
私ならば、以下の設計をします。
・①の為に、データ取得専用のスレッドを作ります。(高優先度)
・②の為にデータ格納用のバッファは常に物理メモリ上に置きます。
・②の為に非同期書き込みを行います。(常にWriteFile()している状態を作り出す。)
アイススケーターさん、PATIOさん、Bosscatさん
皆様、こん××は。
お忙しい中、貴重なコメントを頂きましてありがとうございます。
>共有メモリを使用して、ファイルと連携を取り、クローズ時に自動的に保存する方法も
>ありますよ。
私のコンピュータ知識とプログラミングレベルを超える領域になって
きており、だいぶチンプンカンプンになりつつあります(お恥かしい)。
PATIOさん
>データの保存タイミングってどういうタイミングなんですかねぇ。
Bosscatさん
>質問1)
>外部トリガーとの同期はどうしているのでしょうか?
>トリガーの取りこぼしや、重複取り出しが検出できていない。
PATIOさん、Bosscatさん、お二方とも同じご指摘をされたのだと思いますが、
保存とトリガーのタイミングが合っていないかも知れません。現状のプログラムだと、
重複や取りこぼしを検出していません。
1000トリガー毎の時刻を調べてみたところ、だいたい16,17秒ごとの刻み
になっていました。1000トリガーですから10秒、モータの移動は確か1秒だったので、
残りは書き込みにようする時間と理解して良いのかな。
ただ、実験をしていた時は、制御(モータの移動とAD変換ループから抜ける)が
終わってから、しばらくはHDDへデータを保存し、保存が終了して制御可能になった
気がします。そう考えると、モータの移動とADのデータをどこかに貯め込んでいて、
その後でデータをはき出していたのかな...?
取得した位置データを見たのですが、トリガー数とモータの位置の関係は、
期待していた値を示していましたが、PATIOさんのご指摘のように
最終的にサンプリングが間に合わなくなることもあり得るとすると取得した
データ位置も怪しくなってしまいますね。
>質問2)
>全体のデータ数が2G超えなのは何故でしょう?
>以下の認識であってますか?
>・1トリガー64kのデータが発生する。
>・1000トリガーで1纏まり(64M)
>・そのデータを何個も纏めて取って同じファイルに書き込む。
>また、この場合、纏める単位に何か関連がありますか?(時間等)
>関連があるなら、全体を考えなければならないので、、、
データは構造体の構造体(入れ子構造)になっていまして、トリガー毎に
時刻、モータの位置、AD変換のデータとなっています。その構造体が
1000回分保存。続いてモータの位置を変えて(19箇所)同じようにデータ
を保存。自動的に2回連続(合計38000トリガー分)で保存したために
2.5GBになっています。
保存先のファイル名の作り方が問題なので、1ファイルでデータ
(合計19000トリガー分)が読み込めるようなに変更するつもりで
います。
取得したデータは、1トリガー毎のデータを512ポイント毎に分解して、
FFTし、積分します。そういう意味では、データ取得レートが多少悪くても
モータの位置が確実であれば、1000個分の積算出来れば良しという
ところもあります。計測レートがおちますが...。
>更に、プログラムはメモリーに書き込んだつもりでも
>OSの仮想メモリ機構によってHDDアクセスが発生し(ただでさえ高負荷なHDDに)
>HDD余計なアクセスが発生してしまうことを懸念しています。
>思い切って 「仮想メモリを無効にしてしまう」 手もあるかもしれない。
>最後に、このシステムでは、恐らく以下の事が重要です。
>①データの取りこぼしが無いことが最優先
>②HDDアクセスを効率的に行うこと
>私ならば、以下の設計をします。
>・①の為に、データ取得専用のスレッドを作ります。(高優先度)
>・②の為にデータ格納用のバッファは常に物理メモリ上に置きます。
>・②の為に非同期書き込みを行います。(常にWriteFile()している状態を作り出す。)
Bosscatさんの設計思想はわかるのですが、あまりコンピュータの細かいところまで
よく知らないので、どのようにプログラムを書いて良いのやら...。
正直言いまして、よく解りません。私のレベルはその程度のレベルなので、皆様から
頂いたコメントは大変貴重で勉強になりました。
日曜日から3,4日外出でしてご相談させて頂いた装置の調整に行って来ます。関東に
いますが、装置が東北にありましてすぐに調整出来ないのが悩みです。
私が書いた取りこぼしの話は、
1)一点のデータ取り込み
2)一点のデータ書き込み
これを65536点分繰り返すとなると、
書き込み用のキャッシュがいっぱいになった時点で
ハード的な書き込み動作が入り、サンプリングが間に合わなくなるケースが
発生するのではないかという話です。
モーター制御とサンプリング開始用のトリガーの関係は、
モーター制御が終わってサンプリング開始が可能になったと言う意味合いのトリガーと
解釈していますが、それが正しいのであれば、サンプリング開始のトリガー取得から
モーター制御前までのサンプリングが一気に行われていて、
書き込みもサンプリング後に一気に行っているのであれば、
取りこぼしの心配は少ないのではないかと思います。
PATIOさん、皆さん
こん××は。
>モーター制御とサンプリング開始用のトリガーの関係は、
>モーター制御が終わってサンプリング開始が可能になったと言う意味合いのトリガーと
>解釈していますが、それが正しいのであれば、
はい、正しいです。
モータの位置情報を
for(j=0;j<1000;j++)
{
モータの位置情報取得 <-追加
AD変換(8bit, 65536)(外部トリガーによりAD、サンプリング周波数は500MHz、ADボ
ードには2MBのオンボードメモリー)
ファイルに保存
}
のように取得し、モータの移動速度を遅くしたデータを解析したところきちんと保存
されていました。データ取得の効率が悪くなりますが、時間スケールがそこまで必要
ないので、現状でよしとすることにしました。
今回様々なコメントを皆様から頂きましてありがとうございました。次のプログラムを
作る時は、もう少し考えて効率よくデータ取得、保存ができるように設計するつもり
でいます。皆様、重ね重ねありがとうございました。