アナログデータのリアルタイム描画

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
キョウ太郎

アナログデータのリアルタイム描画

#1

投稿記事 by キョウ太郎 » 5年前

はじめまして。
キョウ太郎です。

現在、C++Builderを使用してアナログデータの収集と波形の描画するアプリを作成しいます。
USBから取得したアナログデータをメモリに書き溜めて
先頭からForm画面に配置したTImageにCanvasで描画するところまではできたのですが、
データの収集速度と描画の速度がどうしても合わなくてリアルタイムとは言えない状態になっています。
(明らかに描画の速度が遅いと思われます。)
やりたいこととしてはスタートボタン押下で、データの取集は開始して別のタスクにて常にデータをメモリに溜め込む(1秒1000サンプル)処理を開始。
その後、別タスクにてメモリに溜まったデータを常に描画する処理を行っています。
この時、描画がカクつかないように描画のループ中に定期的にTImageをUpdate()して画面に反映させています。

描画が早すぎるとデータ収集が追い付かずに描画可能データが無くなりカクついてしまい
遅いとリアルタイムで無くなってしまい困っています。
1秒間のデータをきっちり1秒間で描画出来るようにしたいです。
(現在だと0.8秒くらいなのでドンドン遅れていきます。)

この掲示板や色んなサイトからリフレッシュレートや1秒間に視認できる回数など確認したのですが
これは視認回数Update()の回数で調整するべきなのか?
それとも何らかのタイマー関数を使用して時間を計算して書かせるべきなのでしょうか?

開発環境はWindows7の C++Builder10.2を使用しています。
主にVB、C#、.netでの開発経験はあるのですがC++は初めてで色々と手こずっております。
VisualStudioもあるので、対応方法があればBuilderに限らず教えて頂ければと存じます。

データ収集にはNI社のNI-Daqmxを使用しています。

掲示板に相談するのは初めてなので何か粗相や足りない情報があれば仰ってください。
よろしくお願いいたします。

Math

Re: アナログデータのリアルタイム描画

#2

投稿記事 by Math » 5年前

キョウ太郎さん 全体的話が抽象的過ぎてよく見えないのですが

”USBから取得したアナログデータをメモリに書き溜めて先頭からForm画面に配置したTImageにCanvasで描画するところまでは”

は NI社のソフトウェアのサンプルに山ほどあると思います。

具体的に問題点を絞ってC++Bulderの プログラムを 検証できる形にして 提示頂ければと思います。

(私のPCには C++Bulder10.3 がインストールされています。)

(基本的にはPCのスペックの問題のように思いますが?)

Math

Re: アナログデータのリアルタイム描画

#3

投稿記事 by Math » 5年前

C++Bulder は Delphi のC++版であり C# はDelphi の開発チームがボーランドからMicrosoft に移籍

して開発したものなので 似ています。 C#  はDelphi に 似ている部分が多いのです。

https://ja.wikipedia.org/wiki/%E3%82%A2 ... C%E3%82%B0

VB も アンダース・ヘルスバーグによって C# 風に 2000万行ほどで書き換えられました(VS2015の時)。

Math

Re: アナログデータのリアルタイム描画

#4

投稿記事 by Math » 5年前

C++Buider は C# とは双子のような 関係で RAD のできる 唯一の C++ になっています。

VS のCLI/CLR はもうメンテナンスされてないようで C#に移行しているようです。私は VS のCLI/CLR を勉強
したのですが。

キョウ太郎

Re: アナログデータのリアルタイム描画

#5

投稿記事 by キョウ太郎 » 5年前

Mathさん

ご返信有難うございます。
確かに抽象的過ぎて申し訳ございません。

NI社のホームページ等やネット上にも確かにサンプルたくさんあるのですが
どれも1秒間隔とかTimerを使い一定間隔のデータを全て描画処理してから画面に反映させる物ばかりでカクカクとした動きでプロットしていくものばかりでした。

私がやりたい内容としては滑らかにほぼリアルタイムで流れる波形を表示するもので
現在、1秒分のデータ(1000サンプル)をループ処理中に10回に1回程度Update() で画面に反映する事で滑らかに表示させているのですが、この場合ループ処理の重さやUpdate() 回数によって描画速度が変わってしまうのでスペックの問題になってしまうと思うのですが、スペックに関係なく一定の速さで描画する方法を探しております。
(古いOSとかメモリ2Gとか低すぎる環境では多少仕方ないとは思いますが・・・)

例えば、高すぎるスペック動かしたら1秒分の処理が0.5秒で終わり、次のデータが溜まるまで待つとカクカクした描画になってしまうし
低すぎるスペックだと、カクカクしないけど、1秒分のデータ描画するのに1.2秒かかったら毎秒0.2秒ずつ遅れていき10秒後には2秒前のデータを描画している事になってしまうのでそれを避けたいと言う事です。
(現在、これの状態です。)

オシロスコープやPicoスコープの様な製品だとスペックに関係なく時間通り動いていると思うので、恐らく上記での方法は間違っているのかなと思い
どういう仕組みで作れば正解なのかと方法を探しています。


私も最初にVSのC++MFCで試していたのですが
C言語したい触ったことが無かったので理解に苦しんでいたところ、C++Builderに出会ってC#っぽいのと画面デザインの作りやすさに感動しています。

Math

Re: アナログデータのリアルタイム描画

#6

投稿記事 by Math » 5年前

それなら方法がありますが今から出かけるので夕方帰ってからにします。

キョウ太郎

Re: アナログデータのリアルタイム描画

#7

投稿記事 by キョウ太郎 » 5年前

Mathさん

ご確認ありがとうございます。
ご回答お待ちしております。

Math

Re: アナログデータのリアルタイム描画

#8

投稿記事 by Math » 5年前

http://www2.koyoen.birdview.co.jp/~abcx ... X-001-.PNG

今 C++Bulder Windows VCL アプリケーションのサンプルを実行して見ています。

キョウ太郎さん の具体的なコードを見せて下さい。

キョウ太郎
記事: 7
登録日時: 5年前

Re: アナログデータのリアルタイム描画

#9

投稿記事 by キョウ太郎 » 5年前

Mathさん

ご連絡ありがとうございます。

下記のコードはC++Builderのスレッドオブジェクトを追加してThread.cppに記載してます。
メイン処理からデータ取得のタスクを動かした後に「MyThread::Execute()」を実行して
MainFrm内に配置したTImageに対してメイン画面のStopボタンが押されるまで描画しています。

※ 最大8chまで描画可能の予定ですが現在テスト段階なので2chまでしか表示しないようにしています。
 罫線などはメイン側に記載のDrawingArea();で描画させています。
実際の描画画面も見て頂きたかったのですが、
画像ギャラリーのエラーで画像取り込めないので、とりあえずコードのみ記載します。

お手数ですがご確認をよろしくお願い致します。

コード:

// マルチスレッド中の描画処理
void __fastcall MyThread::UpdateDrawing()
{
    Application->ProcessMessages();

	// 描画領域のY軸幅を計算
	haba = DrawHeightY2 / 20;
	haba = haba *10;        //小数点切り捨てられてるので戻さないと罫線とずれる
 // 	MainFrame->TImgBG->Canvas->Pen->Color = clRed;


	Ypoint0 = (DrawHeightY + haba);
	Xpoint0 = DrawLeftX;
	x = 0;

	haba = DrawLeftX2 - DrawLeftX;
	// 描画領域のX軸幅を計算
	ms = haba / 10000;
	// ten = 0;

	// データ取得
	// 共有メモリ(メモリマップトファイル)を開く
	HANDLE hMapping = OpenFileMapping(FILE_MAP_READ, FALSE, L"NI-Data_test");
	if ( hMapping == NULL ) {
		ShowMessage("共有メモリが見つかりません");
		return;
	}
	// マッピング開始
	char *dat = (char *)MapViewOfFile(hMapping,
					FILE_MAP_READ,	// 読込モード
					0,
					0,
					0);		// 上限まで読込
	if ( dat == NULL ) {
		ShowMessage("共有メモリのデータがありません");
		return;
	}

	// データ読込
	AnsiString ebuff = AnsiString(dat);

	// マッピング解除
	UnmapViewOfFile(dat);

	//int cnt = 1;

	//int gou2 = 1000 * Tspan;
	int gou2 = 1000 * MainFrame->Tspan * MainFrame->pages;

	//gou = 0;

	 //カンマ区切りの文字列
	//結果格納用のTStringListを用意
	TStringList* splittedResult = new TStringList();
	//CommaTextプロパティにセット
	splittedResult->CommaText = ebuff;


	for(int i= DataCnt; i < splittedResult->Count-1; i++)
	{
		switch(chCnt)
		{
		  case 1:
			x2 = x2 + ms;

			// ten1_1 = (array[DataCnt].ToDouble() * -10.0 )  * MainFrame->correctValue;
			ten1_1 = (splittedResult->Strings[DataCnt].ToDouble() * -10.0 )  * MainFrame->correctValue;
			MainFrame->TImgBG->Canvas->Pen->Color = clRed;
			// TImgBG->Canvas->MoveTo(Xpoint0 + x, Ypoint0 + (ten1 * Vspan));
			MainFrame->TImgBG->Canvas->MoveTo(Xpoint0 + X_time, Ypoint0 + (ten1 * MainFrame->V_valueUP));
			MainFrame->TImgBG->Canvas->LineTo(Xpoint0 + x2*(10.0/MainFrame->Tspan), Ypoint0 + (ten1_1 * MainFrame->V_valueUP));
			chCnt = 2;

			ten1 = ten1_1;
			break;
		  case 2:
			// ten2_1 = (array[DataCnt].ToDouble() * -10.0 )  * MainFrame->correctValue;
			ten2_1 = (splittedResult->Strings[DataCnt].ToDouble() * -10.0 )  * MainFrame->correctValue;
			MainFrame->TImgBG->Canvas->Pen->Color = TColor("$001763FF");
			// TImgBG->Canvas->MoveTo(Xpoint0 + x, Ypoint0 + (ten2 * Vspan));
			MainFrame->TImgBG->Canvas->MoveTo(Xpoint0 + X_time, Ypoint0 + (ten2 * MainFrame->V_valueUP));
			MainFrame->TImgBG->Canvas->LineTo(Xpoint0 + x2*(10.0/MainFrame->Tspan), Ypoint0 + (ten2_1 * MainFrame->V_valueUP));
			chCnt = 1;

			ten2 = ten2_1;
            gou = gou + ms;
			//x = x2*(10.0/Tspan);
			X_time = x2*(10.0/MainFrame->Tspan);


			//  右端まで行ったら次ページとして先頭にカーソルを戻す。
			if ((MainFrame->TImgBG->Width) < gou * (10 / MainFrame->Tspan) )
			{

                Sleep(50);
				MainFrame->pages = MainFrame->pages + 1;
				gou = 0;
				X_time = 1;
				x2 = 1;
				// 縦横の罫線を再描画する。
				MainFrame->TImgBG->Picture = NULL;
				MainFrame->DrawingArea();
			}

			break;
		  case 3:
  //			ten3_1 = array[DataCnt].ToDouble() * -10.0 ;
			MainFrame->TImgBG->Canvas->Pen->Color = TColor("$$00800040");;
			// TImgBG->Canvas->MoveTo(Xpoint0 + x, Ypoint0 + (ten3 * Vspan));
			MainFrame->TImgBG->Canvas->MoveTo(Xpoint0 + X_time, Ypoint0 + (ten3 * MainFrame->Vspan));
			MainFrame->TImgBG->Canvas->LineTo(Xpoint0 + x2*(10.0/MainFrame->Tspan), Ypoint0 + (ten3_1 * MainFrame->Vspan));
			chCnt = 4;

			ten3 = ten3_1;
			break;
		  case 4:
  //			ten4_1 = array[DataCnt].ToDouble() * -10.0 ;
			MainFrame->TImgBG->Canvas->Pen->Color = TColor("$clBlue");;
			// TImgBG->Canvas->MoveTo(Xpoint0 + x, Ypoint0 + (ten4 * Vspan));
			MainFrame->TImgBG->Canvas->MoveTo(Xpoint0 + X_time, Ypoint0 + (ten4 * MainFrame->Vspan));
			MainFrame->TImgBG->Canvas->LineTo(Xpoint0 + x2*(10.0/MainFrame->Tspan), Ypoint0 + (ten4_1 * MainFrame->Vspan));
			chCnt = 5;

			ten4 = ten4_1;
			break;
		  case 5:
  //			ten5_1 = array[DataCnt].ToDouble() * -10.0 ;
			MainFrame->TImgBG->Canvas->Pen->Color = TColor("$$00FF8000");;
			// TImgBG->Canvas->MoveTo(Xpoint0 + x, Ypoint0 + (ten5 * Vspan));
			MainFrame->TImgBG->Canvas->MoveTo(Xpoint0 + X_time, Ypoint0 + (ten5 * MainFrame->Vspan));
			MainFrame->TImgBG->Canvas->LineTo(Xpoint0 + x2*(10.0/MainFrame->Tspan), Ypoint0 + (ten5_1 * MainFrame->Vspan));
			chCnt = 6;

			ten5 = ten5_1;
			break;
		  case 6:
  //			ten6_1 = array[DataCnt].ToDouble() * -10.0 ;
			MainFrame->TImgBG->Canvas->Pen->Color = TColor("$$00408000");;
			// TImgBG->Canvas->MoveTo(Xpoint0 + x, Ypoint0 + (ten6 * Vspan));
			MainFrame->TImgBG->Canvas->MoveTo(Xpoint0 + X_time, Ypoint0 + (ten6 * MainFrame->Vspan));
			MainFrame->TImgBG->Canvas->LineTo(Xpoint0 + x2*(10.0/MainFrame->Tspan), Ypoint0 + (ten6_1 * MainFrame->Vspan));
			chCnt = 7;

			ten6 = ten6_1;
			break;
		  case 7:
  //			ten7_1 = array[DataCnt].ToDouble() * -10.0 ;
			MainFrame->TImgBG->Canvas->Pen->Color = TColor("$$0040FF00");;
			// TImgBG->Canvas->MoveTo(Xpoint0 + x, Ypoint0 + (ten7 * Vspan));
			MainFrame->TImgBG->Canvas->MoveTo(Xpoint0 + X_time, Ypoint0 + (ten7 * MainFrame->Vspan));
			MainFrame->TImgBG->Canvas->LineTo(Xpoint0 + x2*(10.0/MainFrame->Tspan), Ypoint0 + (ten7_1 * MainFrame->Vspan));
			chCnt = 8;

			ten7 = ten7_1;
			break;
		  case 8:
  //			ten8_1 = array[DataCnt].ToDouble() * -10.0 ;
			MainFrame->TImgBG->Canvas->Pen->Color = TColor("$clOlive");;
		   //	TImgBG->Canvas->MoveTo(Xpoint0 + x, Ypoint0 + (ten8 * Vspan));
			MainFrame->TImgBG->Canvas->MoveTo(Xpoint0 + X_time, Ypoint0 + (ten8 * MainFrame->Vspan));
			MainFrame->TImgBG->Canvas->LineTo(Xpoint0 + x2*(10.0/MainFrame->Tspan), Ypoint0 + (ten8_1 * MainFrame->Vspan));
			chCnt = 1;

			ten8 = ten8_1;
			gou = gou + ms;
			//x = x2*(10.0/Tspan);
			X_time = x2*(10.0/MainFrame->Tspan);
			break;
		  default:
			chCnt = 1;
			break;
		}

		if((i % 10) == 0)
		{
			MainFrame->TImgBG->Update();
			MainFrame->TImgWave->Left = Xpoint0 + x2*(10.0/MainFrame->Tspan);
			MainFrame->TImgWave->Update();
			if (Terminated)
			break;
		}
		DataCnt += 1;

		if (Terminated)
			break;
	}
}
//---------------------------------------------------------------------------
void __fastcall MyThread::Execute()
{
	gou;
	haba;			                               			// 描画領域のXY幅
	DrawLeftX = 0;                                          // 描画領域左端
	DrawLeftX2 = MainFrame->TImgBG->Width;                	// 描画領域右端
	DrawHeightY = 0;                     					// 描画領域上端
	DrawHeightY2 = MainFrame->TImgBG->Height;				// 描画領域下端

	Ypoint0;
	Xpoint0;


	//---- ここにスレッド コードを記述します ----
	while(1)
	{
		// VCLコンポーネントに対する操作は、Synchronize() メソッド経由で行わなければならない。
		Synchronize(&UpdateDrawing);
		// Queue(&UpdateDrawing);
			// Sleep(10);

		if (Terminated)
			break;
			// return;

	}
}

Math

Re: アナログデータのリアルタイム描画

#10

投稿記事 by Math » 5年前

ダブルバファリングをしてflipするタイミングを固定値に制御(fps)すればよいと思ったのですが

ここで答えるような問題ではなくNI社に聞けば直ぐにわかると思いますよ。

今の時代大抵のことはすでに他人がやっていてそれを ”どこに聞くか分かっているか” が問題だけどこのような専門的な内容はここでは不向きだと思いますよ。悪しからず。

キョウ太郎
記事: 7
登録日時: 5年前

Re: アナログデータのリアルタイム描画

#11

投稿記事 by キョウ太郎 » 5年前

Mathさん

ご確認ありがとうございました。

NI社の方にも質問はしているのですが
あそこの場合、開発言語を知っている方が少なく、言語の技術的な質問の場合、殆ど解決できず最終的にLabViewを進められると言う悲しい事になるのであまり期待していません。

アニメーションとかバッファリングも調べては見たのですが、やはりそれだけで解決できなそうですね。
今は高精度タイマ(QueryPerformanceFrequency)とか使って何とかできないか考えているのですが
いい案が浮かんでこなくて投稿してみました><

初投稿なので無反応だったらどうしようと思っていましたので、回答していただけでも嬉しかったのでありがとうございます。
もし、何かいい案が浮かびましたら教えて頂けると幸いです。

Math

Re: アナログデータのリアルタイム描画

#12

投稿記事 by Math » 5年前

そうでしたか、了解です。

God Bless You.

ISLe
記事: 2650
登録日時: 13年前
連絡を取る:

Re: アナログデータのリアルタイム描画

#13

投稿記事 by ISLe » 5年前

オフトピック
わたしの得意分野かと思ったのですが、回答するのが憚られる流れですな。
最近ここに来るの不定期だし、Builder使ったことないので具体的な回答はできそうにないし。

Math

Re: アナログデータのリアルタイム描画

#14

投稿記事 by Math » 5年前

うわ~!残念。遅かりし由良・・・

Math

Re: アナログデータのリアルタイム描画

#15

投稿記事 by Math » 5年前

あ、違った
いい方法があったら教えてあげてください。
このかたはBuilderでなくてもVisualStudioでもいいそうなので。

Math

Re: アナログデータのリアルタイム描画

#16

投稿記事 by Math » 5年前

キョウ太郎さんISLeさんはゲームのプログラムのプロでFPS制御には詳しいかたなので問題点をなんでも聞いて見てください。

キョウ太郎
記事: 7
登録日時: 5年前

Re: アナログデータのリアルタイム描画

#17

投稿記事 by キョウ太郎 » 5年前

ISLeさん

コメントありがとうございます。
今回はC++Builderで作成中ではありますが、
基本はVisualStudioを使って開発をしていますし
今回の問題は考え方の問題なのかと思っているので。
言語の縛りなく教えて頂けると助かります。

いま問題視しているのは描画の速度と実時間の誤差をなるべくスペックに左右されないで動かす方法です。
前に書いた内容と同じですが
************************************
例えば、高すぎるスペック動かしたら1秒分の処理が0.5秒で終わり、次のデータが溜まるまで待つとカクカクした描画になってしまうし
低すぎるスペックだと、カクカクしないけど、1秒分のデータ描画するのに1.2秒かかったら毎秒0.2秒ずつ遅れていき10秒後には2秒前のデータを描画している事になってしまうのでそれを避けたいと言う事です。
(現在、これの状態です。)
************************************

以上

何か方法あれば、些細なことでも良いのでご指南頂けると幸いです。

Mathさん
気づくの遅くなり申し訳ございません。
コメントありがとうございました。
添付ファイル
波形描画.png

アバター
usao
記事: 1887
登録日時: 11年前

Re: アナログデータのリアルタイム描画

#18

投稿記事 by usao » 5年前

(1)
描画が測定より早い場合に,毎測定ごとにデータ描画して更新するよりも「カクカク」しない描画の仕方って何だろう?

(2)表示が遅れる場合:
まず,(何らかの画像バッファへの?)「描画」が遅いのか,
それとも,描画したものを「表示」するのが遅いのか,どちらなのか?

「描画」が圧倒的に遅いという場合,
どんどん遅れていくのを避けるには
データをてきとーに間引いて描画する的な措置しか思いつかない.

「描画」の速度が問題なのではなく「表示の更新」側が足引っ張るようなら,
「たまったデータを全描画したら→更新」にすれば良い(データ測定が等速ならば,表示遅延が一定になる)ように思うけども.

キョウ太郎
記事: 7
登録日時: 5年前

Re: アナログデータのリアルタイム描画

#19

投稿記事 by キョウ太郎 » 5年前

usaoさん

ご確認ありがとうございます。

(1)描画が測定より早い場合に,毎測定ごとにデータ描画して更新するよりも「カクカク」しない描画の仕方って何だろう?
⇒データ取得のタスク開始→描画処理のタスクを開始するの順に別々のタスクを順番に開始するので
取得データと描画開始までのタイムラグがあるのはいいのですが
このEXEを動かす端末によって描画時の速度が変わってしまうのを防ぎたいです。
[私の開発環境]
Windows7 64bit Core i7-4710MQ 2.50GHz メモリ8GB
この開発環境だと1秒分のデータを描くのに1.01秒位の速度で描画される為、波形描画が止まることなく流れるように表示できるのですが

[別環境の端末]
Windows10 64bit Core i7-7700HQ 2.80GHz メモリ16GB
この環境だと恐らく描画が早すぎて(1秒分のデータを描くのに0.9秒位)で処理されてしまう為、次の描画データが溜まるまで描画処理が止まってしまう現象が起きています。


(2)表示が遅れる場合:
⇒こちらはデータ取得では特に遅延無いので、描画のループ処理で上記のスペック差での問題があると思っています。
画面に表示するタイミングを人が認識できる速度で画面更新しているつもりですが
この画面更新回数で描画速度が変化しているので、この回数を端末のスペック毎に動的に出来れば良いのか?もしくは根本的にこのようなアプリを作る場合の作法が違うのか?と言うところで悩んでおります。

タスクマネージャーのCPU使用率の様に1秒間隔で画面更新するなら問題なく作れるのですが
(人が認識できるレベルで)流れるような常に描画されるようなプログラムを目指しております。

アバター
usao
記事: 1887
登録日時: 11年前

Re: アナログデータのリアルタイム描画

#20

投稿記事 by usao » 5年前

(1)側に関して:
> 1秒分のデータ
ってのを何回に分けて描画&表示 しているのかわからないけども,
測定周期よりも早くできちゃうのが困る場合には,
都度(測定周期 - かかった時間)だけ描画&表示の進行を待ってやればよいのでは.

(2)側に関して:
> 作法
なんてものがあるのかすら知りませんが,
 【測定者】→(測定データ)→【描画者】→(描画結果)→【表示者】
という3者の間で速度差をどう吸収するか?って話ですよね?

・【描画者】が遅い場合は,前記した通り,描画データを間引くしかないかなー,と思います.
・【表示者】が遅い場合は,【表示者】がビジーな間は【描画者】は同じ画像バッファに描画を続け,【表示者】の手が空いたタイミングで渡してやるような感じにすればどうでしょう?
 あるいは【描画者】から送られてくる結果がほっとくと「溜まる」状況なのだとして,【表示者】は最新の物だけを表示すれば(表示できなかった古いのは無視して捨てれば)OKとか.
オフトピック
200msに一回程度の更新で,その更新間隔も数十msくらいの幅でばらついても
「流れるように」見えちゃう人なので,これ系で表示のクオリティにはあまりこだわったことないです.
「データがどんどん溜まるかもしれない(=メモリが際限なくやばい)」側は問題視するけど.

キョウ太郎
記事: 7
登録日時: 5年前

Re: アナログデータのリアルタイム描画

#21

投稿記事 by キョウ太郎 » 5年前

(1)
1秒分のデータ(1000サンプル分)をループ中に10回に1回画面に反映させています。
待機するとカクカクするかと考えていましたが、描画が早い場合には画面反映させるタイミングを計算して調整すればイケるかもですね。試してみます。

(2)
表示は回数増やしても対応できているっぽいので恐らく描画処理の速度によるものだと思っています。
確かに描画が遅いのなら処理効率を上げるか処理数を減らすしかないですよね。。。
なるべく間引くのは最後の手段に考えているのでまずは(1)と処理効率を精査してみます。

仮に間引く場合ですが、その端末で処理が「遅い」か「早い」かって
実際に描画処理を走らせる前に判別する方法ってありますか?
描画処理中に毎回確認していると、それこそ処理が重くなってしまう気がするので
起動時とかの準備中に検証用データを裏で処理させて確認するとかでしょうか?

アバター
usao
記事: 1887
登録日時: 11年前

Re: アナログデータのリアルタイム描画

#22

投稿記事 by usao » 5年前

> 仮に間引く場合ですが、その端末で処理が「遅い」か「早い」かって
> 実際に描画処理を走らせる前に判別する方法ってありますか?

わかりません.
ただ,
> 準備中に検証用データを裏で処理させて
…的な処理だと,その検証結果と実処理との間にどれだけ差があるのかわからないので(それこそ環境次第な部分もある?)どうなのかなぁ,とか…?

「処理の最初の時点からいきなりうまい具合に動かないと話にならない!」という厳しい(?)話でないならば
実処理中にかかった時間でも計測して動作中に適宜調整される仕組みとかにしてもいいと思うけど…
オフトピック
(この話題の解決策としてはずれているからofftopic)
【調整が効く諸々を「設定値」として外出しして「いい感じに調整してどうぞ」で逃げる】という選択肢.

こういうのは,「このくらいならOK感」みたいな感覚が人によって違ったりするし,
頑張って仕込んだ自動調整機能が未知のいかなる環境でも常に「妥当に」動くか?とか考えるとうんざりしそうだし.
(例えば,めちゃくちゃ遅い環境で動かしたら「データが間引かれ過ぎて,全く表示の用を成さないぞ!!」とか)

ISLe
記事: 2650
登録日時: 13年前
連絡を取る:

Re: アナログデータのリアルタイム描画

#23

投稿記事 by ISLe » 5年前

わたしなら
・データ受信処理は、データの受信だけして描画に必要なデータを溜めておく
・描画処理は、タイマーイベントで定期的に呼び出し、(タイマーの間隔は信用できないので)実際の経過時間を取得して描画範囲を求め、描画
というふうにします。

描画に時間が掛かれば、1回あたりの描画範囲が広がるわけです。

ウィンドウズはリアルタイムOSではないので、常に一定の間隔とか、ちょうどぴったりとかはできません。
できるだけ近づけることはできます。

デスクトップを操作したりとか、バックグラウンドで何か処理が動いたりとかで、プログラムの動作にかかる負荷が変わることがあります。
タイミングは実行中も常に変動するものとして考える必要があります。

キョウ太郎
記事: 7
登録日時: 5年前

Re: アナログデータのリアルタイム描画

#24

投稿記事 by キョウ太郎 » 5年前

usaoさん
ISLeさん

コメントありがとうございます。

確かに同じ端末でも裏で何か動いていれば負荷も変わってくるから
一定時間で動作させるっていうのは無理がありますね。。。

自己満かもですが、端末枚の設定調整とか付加してみて
経過時間を取得しながら描画速度の調整して実時間に近づける方向で考えてみたいと思います。
もし、良い感じにできたら改めて報告させて頂きます。

ISLe
記事: 2650
登録日時: 13年前
連絡を取る:

Re: アナログデータのリアルタイム描画

#25

投稿記事 by ISLe » 5年前

オフトピック
Windows 7と Windows 10ではデスクトップの描画の仕組みが違います。
新しいOSほど最適化が進んで自動的に無駄が省かれるようになっていきます。

1000サンプリングを10回に1回描画というと100Hz(fps)なので、モニタの周波数が60Hzであれば、モニタに映らないフレームがあります。
内部的な描画は行われますが、Windows 10は、映らないフレームをデスクトップに反映することをしません。

もしかしたら、それが描画速度の差に表れているのかもしれません。
周波数が144Hzあるようなモニタであれば、Windows 7と Windows 10で同様の動作になるかもしれません。

アプリケーション側でどうにかして処理を一定間隔にしようというのは、いくら考えても無理です。
もしやろうとすれば対象のプログラムを動かす環境すべてに対して個々の対応が必要となります。
それくらいなら、頑張ればなんとかなるかもしれません。
ですが、それだけでなく、そのプログラムを動かす環境が、未来で変化することも想定しなくてはいけません。
Windows10でデスクトップ描画の最適化が行われたように、OSアップグレードで変わるかもしれませんし、モニタなど周辺機器の換装で変わるかもしれません。

わたしには、未来を見通す力がないので、現状できることを精一杯頑張っています。

繰り返しになりますが
1. タイマー、あるいはポーリングで、できるだけはやく、あるいはできるだけ一定間隔で処理を呼び出す
2. 1.の呼び出しタイミングは指定した通りにはいかないので、改めて現在時刻を取得して変化分を処理する
というのがわたしの方針です。

自分(アプリ)が時間を決めて相手(システム)に押し付けるのではなく、あくまで相手の都合に合わせ、そこで何が自分にできるかを考える、というものです。

この方針であれば、Windows95の時代に作ったプログラムでも、いまだ環境に影響されず、どんどん速くなったりどんどん遅くなったりすることもなく、滑らかに動きます。
オマケとして、環境が良くなると、自動的により滑らかに動くようになったりします。

Math

Re: アナログデータのリアルタイム描画

#26

投稿記事 by Math » 5年前

キョウ太郎さん
C++を使いたいのでしたらDirectX とか OpenGL とかの選択肢もありではないでしょうか。

viewtopic.php?f=3&t=20482

ゲーム用に情報も豊富ですし 高度な技術にも対応できます。

私は C++ CLR/CLI を勉強して一番強力だと思っていたのですが C#に吸収されたような感じです。
自分的には C# WPF の使用もお勧めします。

キョウ太郎
記事: 7
登録日時: 5年前

Re: アナログデータのリアルタイム描画

#27

投稿記事 by キョウ太郎 » 5年前

ISLeさん
確認遅くなり申し訳ございません。

現在、データの受信部を含め全体を見直しています。
色々調べた結果、確かに一定間隔で処理を呼出&微調整が現実的に思いました。
分かりやすい内容でご教授頂きありがとうございます。

Mathさん
DirectXはC#でこの対応をしていた時に描画が重く感じられた為、除外してしまってました。(今考えるとC#が原因でした。)
OpenGLは使ったことなかったので勉強してみます。
Windowsのみを想定しているので
どちらも使えそうですが、描画系のオススメとしてはDirectXでしょうか?
バージョンもいろいろありますが初心者にはDirectX9から始めるのが無難でしょうか?

Math

Re: アナログデータのリアルタイム描画

#28

投稿記事 by Math » 5年前

今はHP移転準備中でしめてるのですが HPように C# WPF でMVVM パターン を使ったのをつくったものがつかえるかな と思ったのですが。
またC# FORM と DirectX( dxlib 使用 )画面 2画面で データをやり取りしながら描画するサンプルも作りりました。
 いまはOS 自体 DirectXを使っていますが FORM と違い WPF はDirectXをベースにしていて表示が綺麗ですね。

あ、C#は除外でしたか。書いてる途中で気付いきました(^^;

DirectX はまずDxLibから始めたほうがいいです。

まず ここhttps://dixq.net/g/の内容は数日でマスターできるでしょう。

きっと気に入るはずですよ!

Math

Re: アナログデータのリアルタイム描画

#29

投稿記事 by Math » 5年前

なを
viewtopic.php?f=3&t=20479

#5~#8 
も参考にしてください。

アバター
usao
記事: 1887
登録日時: 11年前

Re: アナログデータのリアルタイム描画

#30

投稿記事 by usao » 5年前

オフトピック
余計な話でしょうが,
本当に 描画処理が重い ということなのだとしたら
真っ先に考えるべき事柄の1つとしては,
その描画処理部分の実装を改善できないのか?(要はその部分の実装が良ろしくないのでは?)
という方向の話があるかな,とか.

(まぁ,そういう次元の話はもう既にやりつくしているからこそ,DirectXだの何だのを使うことで得られるかもしれない差分量に期待…的な話をしてるんだろうけども.)

Math

Re: アナログデータのリアルタイム描画

#31

投稿記事 by Math » 5年前

いまは、そういうレベルの話ではありません(^^;

アバター
usao
記事: 1887
登録日時: 11年前

Re: アナログデータのリアルタイム描画

#32

投稿記事 by usao » 5年前

オフトピック
offtopicにしてる話なので,今の話の流れに無関係であれば気兼ねなく黙認してくださいな.

要は,
何らかのレンダリング処理を自前で書いたとして
そのレンダリング処理に要する計算やらデータアクセス処理やらの実装自体が重い場合,
DirectXだの何だのを持ってこようが,肝心のボトルネック部分が改善されるわけじゃないんだから意味ねぇよな,っていう.

Math

Re: アナログデータのリアルタイム描画

#33

投稿記事 by Math » 5年前

速習法について

#29の
>なを
>viewtopic.php?f=3&t=20479
>の
>#5~#8 
>も参考にしてください

の方法なら1日で https://dixq.net/g/ の例がテストできるはず(^^;

またコマンドプロンプトでビルドをやれば VS2017のIDEを立ち上げず ビルド&RUNができる。
(いま時間がないので後日…)

あと(3.14章 特定のFPSで動作させる方法があります) 

Math

Re: アナログデータのリアルタイム描画

#34

投稿記事 by Math » 5年前

ここは元々 DXライブラリーでゲームを作っていた管理人さんの ページから派生しているのです
(***https://dixq.net/g/ ここのしたから飛んでくる)


https://dxlib.xsrv.jp/cgi/patiobbs/patio.cgi?


に元祖 DXライブラリーを開発・管理されている方の掲示板があります
かなり専門的な質問に丁寧に答えてくださいます。

いまは アンドロイド対応版 もありますよ。

https://dxlib.xsrv.jp/dxinfo.html


DXライブラリの主な特徴を以下に記します。

 1.Windowsプログラム( Android版の場合は Androidアプリプログラム )だと意識しなくて済む
 2.ライブラリの色が薄い
 3.ライブラリのソースコードを公開

 まず1の『Windowsプログラム( Android版の場合は Androidアプリプログラム )だと意識しなくて済む』ですが、 これは大抵の同種のライブラリでも同じだと思います。『メッセージループ』だとか、 WindowsAPI云々などとは99%無縁の環境でゲームプログラムが出来ます。 ( Android版の場合も同じく、Androidアプリ特有の『アクティビティ( Activity )』や『ビュー( View )』といったものを意識せずにプログラムを組むことができます。 )

 次に2の『ライブラリの色が薄い』ですが、これは何を意味するかと いいますと… いわゆるライブラリ独自の『規則』や『法則』が少ないと いうことです。つまり、このライブラリでつちかったゲームプログラム技法は 他の開発環境に移っても通用しますし、逆を言えば他の環境で養ってきたプログラム技法も このライブラリで通用する率が高いということです。
 これは重要なことで、逆に独自性が高いライブラリですと他の開発環境に移ったときに 今まで築いてきた知識が全く役に立たなかったり、そのライブラリを使おうとしたときに多くの 知識と技能を再構築しなくてはならなくなるという事態に陥ります。

 3の『ライブラリのソースコードを公開』 は、今では特徴というほどでもありませんが… 見ようと思えばライブラリ内部で何が行われているか確認することができます。

ーーーーーーーーーーーーーーーーーーーーーーーーーー
と安心して使えます

https://ja.wikipedia.org/wiki/DX%E3%83% ... 9%E3%83%AA

にあるように
DirectX 11に対応している

Math

Re: アナログデータのリアルタイム描画

#35

投稿記事 by Math » 5年前

[参考]
必要があって

DXライブラリーを使ったプログラムをTEXTファイル形式で行えるように設定してみました。

ゲームコード.txt(  試験用コード )

コード:

#include "DxLib.h"
#include "Math.h"

// プログラムは WinMain から始まります
int WINAPI WinMain(HINSTANCE,HINSTANCE,LPSTR,int)
{
	int x,y;
	double PI = 3.14159265358979;		// 産医師異国に向こう産後厄なく産・
	ChangeWindowMode( TRUE );		// ウィンドウモードに設定
	if( DxLib_Init() == -1 )		// DXライブラリ初期化処理
	{
		return -1 ;			// エラーが起きたら直ちに終了
	}

	for(x = 0; x < 640; x++) DrawPixel( x , 240 , GetColor( 0,0,255 ) ) ; // 点を打つ
	for(y = 0; y < 480; y++) DrawPixel( 320 , y , GetColor( 0,255,0 ) ) ; // 点を打つ

	for(x = 0; x < 640; x++) DrawPixel( x , 220*sin((float)x*(2.0*PI/320.0))+240 , GetColor( 0,255,255 ) ) ;

	WaitKey() ;				// キー入力待ち

	DxLib_End() ;				// DXライブラリ使用の終了処理

	return 0 ;				// ソフトの終了 
}

実験・成功
http://www2.koyoen.birdview.co.jp/~abcx ... -02-c-.PNG

下記の #10 です
viewtopic.php?f=3&t=20540

Math

Re: アナログデータのリアルタイム描画

#36

投稿記事 by Math » 5年前

[Windows アプリケーションから Consoleを デバッグ用などに生成する]

DXライブラリーのプログラムをコンソール・アプリケーションとして作成する方法を記したが
逆に Windows アプリケーションから Consoleを デバッグ用などに生成する方法を記す。

コード:

#include "DxLib.h"
#include "Math.h"

// プログラムは WinMain から始まります
int WINAPI WinMain(HINSTANCE,HINSTANCE,LPSTR,int)
{
	AllocConsole();
	FILE* out = 0; freopen_s( &out, "CON", "w", stdout );
	FILE* in = 0; freopen_s( &in, "CON", "r", stdin );


	printf("Hello World!\n");

	printf("%lf\n", 3.141592653589793);


	int x,y;
	double PI = 3.141592653589793;		// 産医師異国に向こう産後厄なく産・
	ChangeWindowMode( TRUE );		// ウィンドウモードに設定
	if( DxLib_Init() == -1 )		// DXライブラリ初期化処理
	{
		return -1 ;			// エラーが起きたら直ちに終了
	}

	for(x = 0; x < 640; x++) DrawPixel( x , 240 , GetColor( 0,0,255 ) ) ; // 点を打つ
	for(y = 0; y < 480; y++) DrawPixel( 320 , y , GetColor( 0,255,0 ) ) ; // 点を打つ

	printf("正弦波・・・\n");

	for(x = 0; x < 640; x++) DrawPixel( x , 220*sin((float)x*(2.0*PI/320.0))+240 , GetColor( 0,255,255 ) ) ;

	WaitKey() ;				// キー入力待ち

	DxLib_End() ;				// DXライブラリ使用の終了処理


	//コンソール解放
	fclose( out ); fclose( in ); FreeConsole();



	return 0 ;				// ソフトの終了 
}
実行する。
http://www2.koyoen.birdview.co.jp/~abcx ... -05-c-.PNG

Math

Re: アナログデータのリアルタイム描画

#37

投稿記事 by Math » 5年前

[ 分割コンパイル ]

g.mak

コード:

TARGETNAME=ゲームコード

C_FLAGS=/c /TP /EHsc /D "_MBCS" /MT  /Ic:\dxlib /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /W3 

LINK_FLAGS=/SUBSYSTEM:WINDOWS /LIBPATH:c:\dxlib "kernel32.lib" "user32.lib" "gdi32.lib" "winspool.lib" "comdlg32.lib" "advapi32.lib" "shell32.lib" "ole32.lib" "oleaut32.lib" "uuid.lib" "odbc32.lib" "odbccp32.lib" 

ALL:
	cl $(C_FLAGS) $(TARGETNAME).txt sub_02.txt
	link /out:$(TARGETNAME).exe $(LINK_FLAGS) $(TARGETNAME).obj sub_02.obj 
	$(TARGETNAME).exe
ゲームコード.txt

コード:

#include "DxLib.h"
#include "Math.h"

void sub_02( void );

// プログラムは WinMain から始まります
int WINAPI WinMain(HINSTANCE,HINSTANCE,LPSTR,int)
{
	AllocConsole();
	FILE* out = 0; freopen_s( &out, "CON", "w", stdout );
	FILE* in = 0; freopen_s( &in, "CON", "r", stdin );


	printf("Hello World!\n");

	printf("%16.15f\n", 3.141592653589793);

	int x, y;

	ChangeWindowMode( TRUE );		// ウィンドウモードに設定
	if( DxLib_Init() == -1 )		// DXライブラリ初期化処理
	{
		return -1 ;			// エラーが起きたら直ちに終了
	}

	for(x = 0; x < 640; x++) DrawPixel( x , 240 , GetColor( 0,0,255 ) ) ; // 点を打つ
	for(y = 0; y < 480; y++) DrawPixel( 320 , y , GetColor( 0,255,0 ) ) ; // 点を打つ


	sub_02();


	WaitKey() ;				// キー入力待ち

	DxLib_End() ;				// DXライブラリ使用の終了処理


	//コンソール解放
	fclose( out ); fclose( in ); FreeConsole();



	return 0 ;				// ソフトの終了 
}

sub_02.txt

コード:

#include "DxLib.h"
#include "Math.h"

void sub_02( void )
{
	double PI = 3.141592653589793;		// 産医師異国に向こう産後厄なく産・

	printf("正弦波・・・\n");

	for(int x = 0; x < 640; x++) DrawPixel( x , 220*sin((float)x*(2.0*PI/320.0))+240 , GetColor( 0,255,255 ) ) ;

	printf("余弦波・・・\n");

	for(int x = 0; x < 640; x++) DrawPixel( x , 220*cos((float)x*(2.0*PI/320.0))+240 , GetColor( 0,255,255 ) ) ;
}
実行する。
http://www2.koyoen.birdview.co.jp/~abcx ... -07-a-.PNG

Math

Re: アナログデータのリアルタイム描画

#38

投稿記事 by Math » 5年前

[ OpenCV4 ]

msys2にて clang(クラン)ake、にて openCV4 を 導入したのですが

OpenGL, DXライブラリー と共に選択肢に入るとおもいますね。

viewtopic.php?f=3&t=20501#p152413



OpenCV 4.0.1をVisual Studio 2017から使用する時の手順

https://qiita.com/h-adachi/items/aad3401b8900438b2acd

Math

Re: アナログデータのリアルタイム描画

#39

投稿記事 by Math » 5年前

C++Builder の話
 
Cpadの作者の話viewtopic.php?f=3&t=20551

「情報系の友人がC++Builderを持っているのですが、C++の入門書や、大学の授業では、コンソールプログラムがほとんどで、BCBはコンソールアプリ作成には使いにくい!と文句を言っていたのです。
BCBは優れた開発ツール(Windowアプリを作るのにはDelphiと並んで最強!)ですが、単純なコンソールプログラムの作成には正直向いていません。
当時CPadはLSI C-86にしか対応してなかったのですが、LSIC86は、基本的にDOS16ビットコンパイラであり、intが16ビットである、C++に対応してない、など今となっては仕様の古さは否めませんでした。(注:もちろん今でも、純粋なフリーのCコンパイラとして貴重な存在であると思います。)

すると、選択肢は、MicrosoftのVisual C++しかなくなってしまいます(他にもありますがメジャーなもの、ということで)。僕はDelphiを使っていたため、Inprise/Borland製品の質の高さを知っていたので、学習用途、コンソールアプリ作成のためだけにVCを買うのはもったいない、CPadをBCBと組み合わせてそういう時に使えるツールにしよう、と思っていたのです。BCBのコンソールアプリに弱い、という弱点を克服できれば、BCBユーザーも増えるし、いいことだらけだ!と。」

C++BuilderはC++で唯一のRAD だけど少し違和感があったのがこれですね。

返信

“C言語何でも質問掲示板” へ戻る