4
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Fletを使った簡易計測のひな型

Posted at

Fletを使った簡易な計測GUIのひな型(シミュレーション)を作ったので、覚えとして記載します。

仕様

  • ある値を徐々に変えて、その応答を測定する
    (今回の例では、分光器を制御して試料に当てる光のエネルギーを変えていき、その時に試料から放出される電子を測定する。光電子収量(Photonelectron Yield Spectroscopy: PYS)と呼ばれる測定)
  • リアルタイム(100ms程度)でグラフを更新する
  • 途中で測定をキャンセルできるようにする

開発環境

  • windows 11 pro
  • miniconda
    (minicondaで最低限のファイルと仮想環境を作り、それ以外はすべてpipでインストール)
  • Python=3.10
  • Flet (GUIとして)
  • 測定によって、pyserial, pyvisa, nidaqmxなどをインストール

コード

import time
import datetime
from pathlib import Path

import matplotlib
matplotlib.use('Agg') 
matplotlib.use("svg")
import matplotlib.pyplot as plt

import numpy as np
import pandas as pd
import flet as ft
from flet.matplotlib_chart import MatplotlibChart


# -----
def ramp_func(start,end,step):
    # 測定点を作る配列
    s_d = len(str(step).split('.')[1]) # 小数点以下の桁数を調べる
    ramp_ = np.round(np.arange(start,end+step,step),s_d) # 数の丸めを行う。
    ramp_= ramp_[np.where(ramp_ <= end)]
    # print(ramp_)
    return ramp_
# -----


# global変数(途中で測定を止めるために利用する)
flag= False # False:続行、True:停止とする


def main(page: ft.Page):
    
    out_file_name = ft.Ref[ft.Text]()
    fig, ax = plt.subplots()
    ui_rows = []
    
    # callback
    def goto_clicked(e):
        ct_ene.value = float(move_ene.value)
        time.sleep(0.5)
        page.update()
        
    def current_clicked(e):
        ct_ene.value = float(move_ene.value)
        page.update()
        
    def start_clicked(e):
        measure_plot(fig, ax )
     
    def abort_clicked(e):
        # For loopを途中で止めるため
        global flag
        flag = True
    
    # GUI 設定        
    title_txt = ft.Text("PYS Measurement System",size=20)
    start_ene = ft.TextField(label="Start[eV]", value="4",width=100)
    end_ene = ft.TextField(label="End[eV]", value="6.2",width=100)
    step = ft.TextField(label="Step[eV]", value="0.05",width=100)
    move_ene = ft.TextField(label="Move[eV]", value="4",width=100)
    ct_ene =  ft.TextField(label="Current[eV]", value="0",width=100)
    out_file =  ft.Text(ref=out_file_name)
    
    goto_btn = ft.ElevatedButton("Goto", on_click=goto_clicked)
    current_btn = ft.ElevatedButton("Current", on_click=current_clicked)
    start_btn = ft.ElevatedButton("Start", on_click=start_clicked)
    abort_btn = ft.ElevatedButton("Abort", on_click=abort_clicked)
    

    ui_rows.append(ft.Row(controls=[title_txt]))
    ui_rows.append(ft.Row(controls=[current_btn,ct_ene, goto_btn, move_ene]))
    ui_rows.append(ft.Row(controls=[start_btn, abort_btn]))
    ui_rows.append(ft.Row(controls=[start_ene, end_ene, step]))
    ui_rows.append(ft.Row(controls=[out_file]))
    
    fig_draw = MatplotlibChart(fig,expand=True)
                  
    ui_controls = ft.Column(controls=ui_rows)
    page.add(ui_controls, fig_draw) 
    
    # 測定 Realtimeでグラフを更新する    
    def measure_plot(fig, ax):
        global flag
        flag = False
        
        # スキャンするXの範囲
        start_f = float(start_ene.value)
        end_f = float(end_ene.value)
        step_f = float(step.value)

        xs = []
        ys = []
        
        for x in ramp_func(start_f,end_f,step_f):
            ax.cla()
            
            # ---測定する命令を書く
            # 例えばエネルギーを設定する。
            # 測定器から帰ってくる値をとる
            x1 = x 
            y1 = x1**4 # デモとして4乗の値を返す
            
            # ---
            
            xs.append(x1)
            ys.append(y1)
            
            ax.plot(xs, ys,'ro-')
            ax.set_xlabel('Energy[eV]')
            ax.set_ylabel('Yield')
            ax.grid()
            
            fig_draw.update()

            if flag:
                break
            
            time.sleep(0.5)
        
        # data Save 測定が終わると自動でデータをSaveする
        save_path_name = 'results'
        Path(f'./{save_path_name}').mkdir(exist_ok=True)
        now = datetime.datetime.now()
        ext_file_name = f'./{save_path_name}/{out_file.value}_{now.strftime("%Y%m%d_%H%M%S")}'
        ext_csv = ext_file_name + '.csv' 
        ext_png = ext_file_name + '.png' 
        
        df_ = pd.DataFrame({"x":xs,"y":ys})
        df_.to_csv(ext_csv,index=False)
        fig.savefig(ext_png)
        # plt.close(fig)
        

if __name__ == '__main__':
    ft.app(target=main)   
    # ft.app(target=main, view=ft.WEB_BROWSER)

測定画面と測定結果(シミュレーション)

GUI001.png

測定をスタートする

GUI002.png

4
5
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?