ブログ

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

コンピュータ

Scipyのinterpolateはデータの外側へも広げられる

Scipyのinterpolateはデータの外側へも広げられることを知った.
fminなどを使用していると,引数が意図しない範囲に行って補間が失敗して止まることがあるのだが,未然に防ぐことができる.

scipyのinterpolateは今まで使ったことがなかったが,事前にx, yの2つの数値列を与えておくと補間するための関数を返してくれるという仕様になっている.この関数として返すという仕様がfminなどで使うときの便利さにつながる.
さらに,interpolateはデータの範囲が超えたときにエラーにしない仕様がある.例えば以下のような例である

# -*- coding: utf-8 -*-
import numpy as np
import scipy as scipy
from scipy.optimize import fmin
from scipy import interpolate
import matplotlib
import matplotlib.pyplot as plt

x = np.linspace(0, 100, num=1001, endpoint=True);
y = np.zeros(x.shape);

for i in range(y.shape[0]):
    if i < 500 and i > 50:
        y[i] = 1;
f4 = scipy.interpolate.interp1d(x, y, 'cubic', fill_value='extrapolate')
xi = np.linspace(-100, 200, num=121)

plt.plot(x, y, linewidth='3');
plt.plot(xi, f4(xi))
plt.grid(True)

plt.savefig('20190727test.png', format='png', dpi=100)
plt.show();

さらに数値最小化の追加の例までついかすると例えば以下のようになる.

# -*- coding: utf-8 -*-
import numpy as np
import scipy as scipy
from scipy.optimize import fmin
from scipy import interpolate
import matplotlib
import matplotlib.pyplot as plt

x = np.linspace(0, 100, num=1001, endpoint=True);
y = (x - 40) ** 2

f2 = scipy.interpolate.interp1d(x, y, 'cubic', fill_value='extrapolate')

minimum = scipy.optimize.fmin(f2, 1)

xi = np.linspace(-100, 200, num=121)

plt.plot(x, y, linewidth='3');
plt.plot(xi, f2(xi))
plt.plot(minimum, f2(minimum), '+')
plt.grid(True)

plt.savefig('20190727test2.png', format='png', dpi=100)
plt.show();

導関数を使わない数値最小化ならこれらでもよいが,微分係数を使って勾配を下に下らせるように最適化を目指すアルゴリズムを使用したい場合には,計算が増えてしまう.そこで,UnivariateSplineというものもある.まず上の置き換えだけなら,

from scipy.interpolate import UnivariateSplie
f2 = scipy.interpolate.UnivariateSpline(x, y, s=0, ext=0)

にするだけである.さらにf2.derivatives()なるものが使えるようになる
f2.derivatives(minimum)は[ほぼ0, ほぼ0, 2, ほぼ0]になるはず.順にf2の補間結果,1次微分係数,2次微分係数,...

≫ 続きを読む

2019/07/27 コンピュータ   TakeMe
タグ:Python

Pythonのsounddeviceその2

Pythonでnumpyの信号をスピーカーから出力するのはどうすればよいのかを探していると,sounddeviceというのが見つかった.
これを使って前は少し遊んでみるた
sounddeviceにはplayrecという関数があって再生と録音を同時にできる.

音を入力出力する例としては,sd.playrec(z, samplerate=fs, channels=1)に変えるだけである.
下の例ではz2が録音されたデータの列になっている.

注意すべき点は,秒単位ではタイミングがずれることである.タイミング関係は使用している環境や負荷によるかもしれない.
import numpy as np
import sounddevice as sd
import matplotlib.pyplot as plt

fs = 44100
fbase = 4000;
t = np.linspace(0, 44099, num=44100, endpoint=False);
z = 0.2 * np.sin(t * 2 * np.pi * (fbase)) + 0.2 * np.sin(t * 2 * np.pi * (fbase + 1)) + 0.2 * np.sin(t * 2 * np.pi * (fbase + 2)) + 0.2 * np.sin(t * 2 * np.pi * (fbase + 3));

z2 = sd.playrec(4 * z, fs, channels=1)#sd.rec(int(duration * fs), samplerate=fs, channels=1)
sd.wait()

sd.play(z2, fs);
# 表示
Fz = np.fft.fft(z2) / z2.shape[0] * 2; # 折り返すのでパワーが2分の1になっている.
Fz[0] = Fz[0] / 2; # 平均成分は折り返さない.
Fz_abs = np.abs(Fz);

freq = np.fft.fftfreq(len(z), d=1.0/fs);
tim = np.arange(0, z2.shape[0]) * 1.0 / fs;
plt.figure(1)
plt.subplot(211);
plt.plot(tim, z2);

plt.subplot(212);
plt.plot(freq, Fz_abs * 1e6);
plt.xlim([0, 20000])

plt.show();


 

参考: sounddeviceでPythonを使って録音する

≫ 続きを読む

2019/07/21 コンピュータ   TakeMe
タグ:Python

Python numpyでFFTを実行する.周波数軸はどうしたら2

以前の記事「Python numpyでFFTを実行する.周波数軸はどうしたら」ではlinspaceを使って周波数リストを出力していたが,numpy.fft.fftfreqでもよい.

以下のようになる.実は,折り返しが始まった周波数より上はnumpy.fft.fftfreqで作った方が正しい.というのはlinspaceで周波数リストを作ると折り返しは再現されないのだ.
fftfreqで作成すると絶対値だけは周波数を再現する.負符号で折り返しを表現する.

import numpy as np
import matplotlib.pyplot as plt

# 例の信号を作成
t = np.linspace(0.001, 4, 4000);
z = 0.1 + 0.2 * np.sin(t * 10 * 2 * np.pi) + 0.2 * np.sin(t * 33 * 2 * np.pi);

# サンプリング周波数
fsmp = 1 / (t[1] - t[0]);
# 解析時間
t_len = t.max() - t.min();

Fz = np.fft.fft(z) / z.shape[0] * 2; # 折り返すのでパワーが2分の1になっている.
Fz[0] = Fz[0] / 2; # 平均成分は折り返さない.
Fz_abs = np.abs(Fz);

freq = np.linspace(0, fsmp - 1/(t_len + t[1] - t[0]), num=len(t));
freq2 = np.fft.fftfreq(len(t), d=1.0/fsmp);

plt.figure(1)
plt.plot(freq, freq2 - freq);

plt.show();

≫ 続きを読む

2019/07/15 コンピュータ   TakeMe

Pythonのsounddevice

Pythonでnumpyの信号をスピーカーから出力するのはどうすればよいのかを探していると,sounddeviceというのが見つかった.
これを使ってこの後 仕事で少し遊んでみることにした...

音を出力する例としては以下のようになる.
zがnumpy.arrayでこの例では正弦波の重ね合わせになっている.

import numpy as np
import sounddevice as sd

fs = 44100

t = np.linspace(0, 44099, num=44100, endpoint=False);
z = 0.2 * np.sin(t * 2 * np.pi * 11000) + 0.2 * np.sin(t * 2 * np.pi * 11001) + 0.2 * np.sin(t * 2 * np.pi * 11002) + 0.2 * np.sin(t * 2 * np.pi * 11003) + 0.2 * np.sin(t * 2 * np.pi * 11004) + 0.2 * np.sin(t * 2 * np.pi * 11005);
sd.play(z, fs)

この例は再生だけなので後で,録音も以下のように行える.

import numpy as np
import sounddevice as sd

fs = 44100

duration = 5  # seconds
z2 = sd.rec(int(duration * fs), samplerate=fs, channels=1)
sd.wait()

sd.play(z2, fs); # 録音したものを再生

参考: sounddeviceでPythonを使って録音する

≫ 続きを読む

2019/07/14 コンピュータ   TakeMe

Visual Studio Express 2017 for Windows DesktopがVisual Studio Expressの最後のバージョン

Visual Studio 2019が出た後,Expressはどうなったのか気になっていたがしばらく放置していた.
「Visual Studio Express 2017 for Windows DesktopがVisual Studio Expressの最後のバージョン」というのが見解のようだ.

Visual Studio 2019ではExpressは提供されない
Communityへの切り替えを促されている.SharpDevelopの開発が終了した今Expressが無償で手に入る.NETアプリケーションの商用開発の最新ツール的な位置づけだったが,また状況が変化した.

学習用途では無料で問題ないが,ライセンスが若干異なるので,仕事で使う分にはライセンスの比較が必要だ.

必要に応じてProfessionalのライセンスが必要になる案件が生じるということかもしれない.
最近知ったが,Visual Studio MarketplaceにてVisual Studio Professionalの月額サブスクリプションを取り扱っているらしい.本当に必要な時にはこちらも調査したい.現在の為替だと月5千円強となる.
通常Visual Studio Professionalを購入する場合に比べると一度に支払う金額が抑えられるか...

≫ 続きを読む

2019/07/14 コンピュータ   TakeMe

C#からCOMに接続 CreateObjectとGetObject

C# からCOMオートメーションを使用していたら,いつもはCreateObjectに相当する操作しかしていなかったので,毎回アプリケーションが起動していたが,GetObjectを使用すればすでに起動しているものに接続できる.

C#からCOMオブジェクトを使用したい場合には,サンプルにCreateObjectというものが必ずと言っていいほどでてくる.
しかし,Createと言っているので毎回新しいインスタンスが作成される(アプリケーションが起動する).

いままでそういうものだと思っていたが,どうも違うらしい.
すでに起動したあアプリケーションに接続する方法があるらしい.

ただし,マイクロソフトのサイトに「ほとんどの場合、Office アプリケーションをオートメーションで実行するには CreateObject (Visual Basic) または CoCreateInstance (Visual C++) を使用して Office アプリケーションの新規インスタンスを起動する必要があります。」という仕様になっているという記事があり,万能ではない.

こんな感じ

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 Excel = Microsoft.Office.Interop.Excel;

namespace WindowsFormsApp1
{
    public partial class Form1 : Form
    {
        private Excel.Application appExcel = null;
        private Excel.Workbook objWorkbook = null;
        private Excel.Worksheet objWorksheet = null;

        public Form1()
        {
            InitializeComponent();

            try
            {
                this.appExcel = (Microsoft.Office.Interop.Excel.Application)Microsoft.VisualBasic.Interaction.GetObject(null, "Excel.Application");
                this.objWorkbook = this.appExcel.ActiveWorkbook;
            }
            catch (Exception)
            {
                this.appExcel = new Excel.Application();
                this.appExcel.Visible = true;
                this.objWorkbook = this.appExcel.Workbooks.Add();
            }

            this.objWorksheet = (Excel.Worksheet)this.objWorkbook.Sheets[1];
        }

        private void Form1_FormClosing(object sender, FormClosingEventArgs e)
        {
            if (objWorksheet != null)
            {
                try
                {
                    System.Runtime.InteropServices.Marshal.ReleaseComObject(objWorksheet);
                }
                catch
                {
                }
            }

            /*if (objWorkbook != null)
            {
                try
                {
                    objWorkbook.Close(true, Type.Missing, Type.Missing);
                }
                catch
                {
                }
            }

            if (appExcel != null)
            {
                try
                {
                    appExcel.Quit();
                }
                catch
                {
                }
            }*/
        }

        private Int64 count = 0;
        private void button1_Click(object sender, EventArgs e)
        {
            this.objWorksheet.Range["A1"].Value = count++;
        }
    }
}
 

≫ 続きを読む

2019/06/08 コンピュータ   TakeMe

Windows 10 Fall Creators Update以降はSMBv1が勝手に無効化されることがある

最近 アイ・オー・データ機器のLAN DISK Sシリーズにつながらなくなったなーと思っていた.
でもいままでつかえていたのでWindows 10が原因とは気づかなかった.
原因に気付くまで時間がかかった.でも仕様らしい.

「Windows 10にしてもSMBv1を現に利用している環境ではSMBv1クライアント機能が有効になっている」はずだった.

しかし,どうも常識が変更されたようだ.しかも,無効になるタイミングはユーザが意識して変更したタイミングでもUpdateのタイミングでもなく,
SMBv1 クライアントが使用されていない期間 (コンピューターの電源が切れていた期間を除く) が合計 15 日間になると、SMBv1 は自動的にアンインストールされます。

マイクロソフトが設けた「時間の概念を設ける新しい仕組み」(初心者にはSMBv1を使う環境か使わない環境かを勝手に判断して選択する画期的な機能かのしれない)であるが,仕組みを知らない人には原因不明の不具合が発生しているように見える.

今回は,暫く外へ持ち出していたパソコンを戻したら使えなくなっていた.一応 LAN DISKのサポートページにはSMBv1クライアントを有効にするように書いてあったが,「前に有効にしたはず」との意識があったので再確認には至らなかった.
インストール時の操作が同じでも,環境に合わせて設定が変わるというのは便利な仕組みだが,中途半端に知っている人にとっては不具合を誘発しかねない...

≫ 続きを読む

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

open62541の開発ブランチには互換性がない変更が加わった

以前にopen62541のビルドの記事(1, 2)を書いていたが,その時と異なりGitHubのリポジトリの先頭にはいよいよ次のリリースへ向けて(?)大きな変更が入ってしまった.

GitHubのリポジトリをクローンして使っていると昨年9月のころできていたことができなくなっている.
Server用とClient用の区切りを設けようとしているのか詳しくはわからないが,大きく仕様が変わっており,マニュアルも整っていないようなので,特にWindows用の対応は難しい.試行錯誤でうまく動かすような時間が必要である.

GitHubのリポジトリをクローンして使う場合には,最終リリース版である0.3を使用されることをお勧めする.
ちなみにhttps://open62541.org/では0.3.0の配布になっているのでそちらの方が適当であろう.
昨年9月までは新しい仕様を取り込もうとGitHubからクローンした方がバグフィックスが入っていて便利ということも間違いとは言い難かったが,0.3.0のリリース直前だったからで0.3.0のリリース後は次のリリースへ向けて積極的に変更が入っている.

ファイルの構造が変わって,open62541.hなどの一つのファイルをインクルードすれば足りたファイルがなくなってしまっている.そして,開発版のドキュメントではそれに対応していそうに見えたが,少なくともVisual Studioではライブラリのビルドは成功するのだが,それを使う段階でチュートリアルの方法では失敗する
時間がたてば,もう少し整理されてくるはず.オープンソースでまともに動くOPC-UAの実装の一つなので期待している.

≫ 続きを読む

2019/04/24 コンピュータ   TakeMe

HttpClientは標準でProxy経由の通信になる

.NET FrameworkでHttpClientを使う機会があった.何も気にせずに使い始めると通信にProxyの設定が適用される.

(2023.06.11 追記 下の例のアプリではHttpClientを1回しか使わないから問題ないが、短時間に複数回使用していく用途ではusingで囲うとリソースが枯渇するリスクが上がる。特に最新の.NET Coreや.NET 5.0以降の使用例ではDisposeせずに残している。記事内でKeepAliveなどを気にせずと書いているが、usingブロックから出るときにインスタンスが破棄されるため、KeepAliveなどが持続しないので注意。)

.NET Framework 4.5からの機能だとおもうが,HttpClientというものが使えるようになった.TcpClientでは気にする必要があるKeepAlive/Httpsなどの実装を気にせずに使用できるようだ.参考となるページはHttpClientクラスでWebページを取得するには?[C#、VB]であろうか.
(ただこの記事が書かれた時と状況が異なる点がSystem.Net.ServicePointManager.SecurityProtocol |= System.Net.SecurityProtocolType.Tls12;の部分である.現在では脆弱性の懸念から,SSL 3やTLS1.1などが無効化され始めており,最初からTLS1.2でつなげに行かなければ失敗するサーバーが多くなっている点である.)
さて,外のサーバーに接続する場合には
HttpClientHandler handler = new HttpClientHandler();
handler.UseProxy = false;
もいらない(はずである).
しかし,ローカルにプロキシサーバーを設けている場合にはローカルアドレスに対してプロキシを使用しない設定にしても,http://192.168.1.1/などにリクエストを送ろうとすると,Windows の仕様(ほぼバグ)によりプロキシを経由しようとする.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Net.Http;

namespace ConsoleApp1
{
    class Program
    {
        static void Main(string[] args)
        {
            // 取得したいWebページのURI
            Uri webUri = new Uri("https://www.valuestar.work/");

            // Call the method "GetWebPageAsync"
            Task<string> webTask = GetWebPageAsync(webUri);
            webTask.Wait(); // Mainメソッド内でawaitのかわりの待機
            string result = webTask.Result;  // content of the result 

            Console.WriteLine(result);
#if DEBUG
            Console.ReadKey();
#endif
        }

        static async Task<string> GetWebPageAsync(Uri uri)
        {
            // Forced to use TLS1.2
            System.Net.ServicePointManager.SecurityProtocol |= System.Net.SecurityProtocolType.Tls12;

            // Setting: "Do not use proxy"
            HttpClientHandler handler = new HttpClientHandler();
            handler.UseProxy = false;

            using (HttpClient client = new HttpClient(handler))
            {

                // setting timeout (optional)
                client.Timeout = TimeSpan.FromSeconds(10.0);

                try
                {
                    // Main part of this function
                    return await client.GetStringAsync(uri);
                }
                catch (HttpRequestException e)
                {
                    // Related to HTTP
                    Console.WriteLine("\nHTTP Exception");
                    Exception ex = e;
                    while (ex != null)
                    {
                        Console.WriteLine(ex.Message);
                        ex = ex.InnerException;
                    }
                }
                catch (TaskCanceledException e)
                {
                    // Timeout
                    Console.WriteLine("\nTimeout");
                    Console.WriteLine(e.Message);
                }
                catch (Exception e)
                {
                    // Others
                    Console.WriteLine(e.Message);
                }
                return null;
            }
        }
    }
}

困った問題である.http://127.0.0.1/などはループバックなのにプロキシを経由されるというほぼバグ仕様によりデバッグ中に相当苦労させられた.

≫ 続きを読む

2019/04/24 コンピュータ   TakeMe

Windows FormsのDockプロパティFillはダブルバッファリングと相性が悪い

今回は,Windows Formsのアプリケーションを作成していた.
DataBindingを設定して,更新してみていたが どうもちらつく.原因はDockプロパティだった.
「Windows FormsのDockプロパティFillはダブルバッファリングと相性が悪い」ではなく「Windows FormsのDockプロパティFillはダブルバッファリングと相性が悪いかったかも」が正しいのかもしれない.実行環境を新しくしていくと問題が消えていく...

そもそも,本題の更新時のちらつきについて話を進める前に,
WPFのデータバインディングの場合には,バックグラウンドスレッドで更新しても普通に更新がかかるのだが,Windows Formsの場合にはUIスレッドで意図的にプロパティ変更イベントを出さないといけないようだ.
さて本題だが,Windows FormsのLabelは標準でダブルバッファリングが有効になったコントロールである.
しかし,DockプロパティをFillにしているとちらつく(ことがある).
ただし,Windows 10では問題ないように見える.例えば以下のようなコードはWindows 10で問題ない(っぽい)

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Windows.Forms;

namespace WindowsFormsApp1
{
    public partial class Form1 : Form
    {
        private Timer timer = new Timer();
        private Label label = new Label();
        private Label label2 = new Label();
        private TableLayoutPanel tableLayoutPanel = new TableLayoutPanel();
        private Int64 count = 0;

        private ViewModel vm = new ViewModel();

        public Form1()
        {
            InitializeComponent();

            this.Controls.Add(tableLayoutPanel);
            tableLayoutPanel.Dock = DockStyle.Fill;
            tableLayoutPanel.ColumnCount = 2;
            tableLayoutPanel.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 50F));
            tableLayoutPanel.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 50F));
            tableLayoutPanel.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 50F));
            tableLayoutPanel.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 50F));
            tableLayoutPanel.RowCount = 2;
            tableLayoutPanel.Controls.Add(label);
            tableLayoutPanel.SetColumn(label, 0);
            tableLayoutPanel.SetRow(label, 0);

            tableLayoutPanel.Controls.Add(label2);
            tableLayoutPanel.SetColumn(label2, 1);
            tableLayoutPanel.SetRow(label2, 1);

            this.label.DataBindings.Add(new Binding("Text", this.vm, "Text1", false));
            this.label2.DataBindings.Add(new Binding("Text", this.vm, "Text2", false));

            label.Font = new Font("MS Gothic", 40);
            label.Height = 50;
            label.Text = count.ToString();
            label.TextAlign = ContentAlignment.MiddleCenter;
            label.Dock = DockStyle.Fill;

            label2.Font = new Font("MS Gothic", 40);
            label2.Height = 50;
            label2.Text = count.ToString();
            label2.TextAlign = ContentAlignment.MiddleCenter;
            label2.Dock = DockStyle.Fill;

            timer.Interval = 100;
            timer.Tick += timer_Tick;
            timer.Start();
        }

        private void timer_Tick(object sender, EventArgs e)
        {
            count++;
            this.vm.Text1 = count.ToString();
            this.vm.Text2 = (-count).ToString();
        }
    }
}
using System;
using System.ComponentModel;

namespace WindowsFormsApp1
{
    public class ViewModel : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;
        private void RaisePropertyChanged(string propertyName)
        {
            if (PropertyChanged != null)
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }

        private string _text1 = "test";
        public string Text1
        {
            set
            {
                _text1 = value;
                RaisePropertyChanged("Text1");
            }
            get
            {
                return _text1;
            }
        }

        private string _text2 = "test";
        public string Text2
        {
            set
            {
                _text2 = value;
                RaisePropertyChanged("Text2");
            }
            get
            {
                return _text2;
            }
        }
    }
}

環境によってちらつきが発生する難しいバグ発生となった.
このバグが発生する場合には「コントロールのダブルバッファリングを有効にして、ちらつきを防止する」を実施しても関係ないようだ.
難しい.

≫ 続きを読む

2019/04/14 コンピュータ   TakeMe
タグ:Windows Forms