ブログ

割とコンピュータよりの情報をお届けします。

2019/3/27

Phidgets 温度センサ4入力USB熱電対インタフェースを使ってみた

Phidgets 温度センサ4入力USB熱電対インタフェースを購入してみた.
なかなか使いやすく良いが,残念な点もある.

良い点

安いところ.
そしてドライバーをインストールする必要がない点.(NIの商品より安く使い始められてドライバもいらない)
PhidgetsのWEBサイトでライブラリを配布しているが,このライブラリはシステム全体に入れる必要はなく,アプリケーションに添付するだけでも良い.(開発する場合にはNugetパッケージのインストールだけで良い)

残念な点

USBケーブルが付属しないので,別途購入する必要がある.(用意しないと使えない)
K型熱電対で分解能は0.04 度であるようなことが仕様書に書いてあるが,実際に使ってみると,確かに高い分解能の表示はしてくれるが,0.4 度程度の段差が生じる.仕様に特別に項目を設けて「Ambient Temperature Error Max ±0.5」 Kとあったのでこれのことを言っていると思われる.
(通常の表示では気付かないかもしれないが,使用したいサンプリング周波数よりオーバーサンプリングしてデジタルでローパスフィルタを掛けると量子化雑音の低減を期待できるが,確かにうまくいっている時間帯もあったが,隠しきれないステップが現れた.)
冷接点補償か何かのセンサの分解能が不足しているか量子化雑音を気にしないエンジニアがファームウェアの補償の部分を書いているのではないかと疑っている.
安いだけはある.

残念な点に対する対策(現在はこうすればうまく段差が消えるだろうという見込みの段階

0-3チャンネルに熱電対入力があるのと,4チャンネルに内蔵の温度入力ICのサンプリングがつながっている
おそらく,この1048_0B というIDのついた商品では,0-3チャンネルの値は4チャンネルの入力で補正されている.

この商品では0-3チャンネル(4チャンネル分)については電圧としてもサンプリングできるらしいので確認してみたい.ここで補償か何かのセンサの分解能が不足していることが確認できれば,自分で式を書いて滑らかになるように訂正することができる かも
温度ICの温度の値がブラックボックスになっていないのは良い.

仮想的には,測定点での起電力Aに測定器側での起電力Bの差A-Bが電圧入力に入っているはずである.
温度から熱起電力を換算する多項式近似はJISに掲載されている.
普通に使用する部分では,一対一対応なので熱起電力から温度を換算する式(関数)も作ることができる.

≫ Read More

2019/03/27 コンピュータ   TakeMe

SQLiteのデータベースファイルへの同時アクセス3

先の記事の例でSQLiteで操作している部分は良いのだが,おまけのような形でつけてしまったMicrosoft Chart Controlsへのバインドに問題があることが分かった.

主に問題なのは読み込みの例で出したコードである.
this.chart1.DataBind();を最初に呼ぶのは問題ないが,毎回呼ぶと相当な負荷がかかるのだ.10000点などのプロットの場合には一瞬でもCPU負荷が100%近くに上昇してしまう.
DataBindはPointsバッファの切り替えを伴うので大きな負荷になってしまう.
Timerなどで周期的に実行する場合には,一回目の書き込みにはDataBindを使用してすでにPointがあるSeriesに対しては点の追加で対応すべき.(もちろん数珀点程度の更新なら問題ない)

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Data.SQLite;

namespace SQLView2
{
    public partial class Form1 : Form
    {
        private System.Data.SQLite.SQLiteConnection cn;
        private DataSet ds;
        private System.Data.SQLite.SQLiteDataAdapter da;

        public Form1()
        {
            InitializeComponent();

            SQLiteConnectionStringBuilder sqlConnectionSb = new SQLiteConnectionStringBuilder { DataSource = "../../../SQLite2/bin/Debug/test.db" };
            this.cn = new SQLiteConnection(sqlConnectionSb.ToString());
            this.cn.Open();

            ds = new DataSet();
            da = new SQLiteDataAdapter();
            var cmd = new SQLiteCommand(cn);
            cmd.CommandText = "SELECT * FROM test ORDER BY time asc";
            da.SelectCommand = cmd;

            da.Fill(ds, "test");
            this.dataGridView1.DataSource = ds.Tables["test"];

            chart1.Series[0].XValueMember = "time";// チャートへのバインド
            chart1.Series[0].YValueMembers = "value";
            this.chart1.DataSource = ds.Tables["test"];
            this.chart1.DataBind();
        }

        private void timer1_Tick(object sender, EventArgs e)
        {
            if (ds.Tables["test"].Rows.Count > 0)
            {
                DateTime last = (DateTime)ds.Tables["test"].Rows[ds.Tables["test"].Rows.Count - 1][0];
                var cmd = new SQLiteCommand(cn);
                cmd.CommandText = "SELECT * FROM test WHERE time > "
                    + $"'{last.ToString("yyyy-MM-dd HH:mm:ss.fff")}'"
                    + " ORDER BY time asc";
                da.SelectCommand = cmd;
            }

            this.da.Fill(ds, "test");
            this.chart1.DataBind();
        }

        private void Form1_FormClosing(object sender, FormClosingEventArgs e)
        {
            this.cn.Close();
        }
    }
}

おそらく以下のように直すとよい.

        private void timer1_Tick(object sender, EventArgs e)
        {
            if (ds.Tables["test"].Rows.Count > 0)
            {
                Int32 newDataStartingIndex = ds.Tables["test"].Rows.Count;
                DateTime last = (DateTime)ds.Tables["test"].Rows[ds.Tables["test"].Rows.Count - 1][0];
                var cmd = new SQLiteCommand(cn);
                cmd.CommandText = "SELECT * FROM test WHERE time > "
                    + $"'{last.ToString("yyyy-MM-dd HH:mm:ss.fffffff")}'"
                    + " ORDER BY time asc";
                da.SelectCommand = cmd;
                this.da.Fill(ds, "test");
                for (int i = newDataStartingIndex; i < ds.Tables["test"].Rows.Count; i++)
                {
                    for (int j = 0; j < this.chart1.Series.Count; j++)
                    {
                        this.chart1.Series[j].Points.AddXY(ds.Tables["test"].Rows[i][0], ds.Tables["test"].Rows[i][j + 1]);
                    }
                }
            }
            else
            {
                var cmd = new SQLiteCommand(cn);
                cmd.CommandText = "SELECT * FROM test ORDER BY time asc";
                da.SelectCommand = cmd;
                this.da.Fill(ds, "test");
                this.chart1.DataBind();
            }
        }

時々,書き込みのタイミングと読み込みのタイミングが連続で一致してしまうとBlockに関する例外が発生する.少しタイミングをずらして再読み込みを試みるようにした方が確実のようだ.少しバッファなどを設けて長時間SQLiteの書き込みが連続しないようにしておくとよい(複数行の書き込みはトランザクションにしないとかえってブロック時間が長くなる).

≫ Read More

2019/03/27 コンピュータ   TakeMe