📑

ZYNQ (Petalinux) でサーミスタを使って温度を計測する①

2024/11/28に公開

目的

仕事でZYBOでサーミスタで計測した電圧から温度を計算する必要があったため、調査した。
B定数ではなく、Steinhart-Hart方程式を使用して、サーミスタの抵抗値から、ABC定数を算出。
Pythonで電圧から温度を計算し、その後、C++を用いてZYNQのPetalinux上で計算を実施しました。

Steinhart-Hart定数の計算

10、25、50度の時のサーミスタの抵抗値より、Steinhart-Hart定数を計算します。
定数は下記のサイトを使った。
https://www.thinksrs.com/downloads/programs/therm calc/ntccalibrator/ntccalculator.html

サーミスタ(103ET-1)のデータシート
https://www.semitec.co.jp/uploads/2021/11/et_thermistor2015.pdf

Pythonコード

以下のPythonコードは、実測電圧から温度を計算し、グラフをプロットします。

import numpy as np
import matplotlib.pyplot as plt

# Steinhart-Hart定数(調整が必要)
A = 0.6660322320e-3
B = 2.802546675e-4
C = 1.366198121e-7

# 実測電圧 (V)
measured_voltage = np.array([0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0, 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7, 1.8, 1.9, 2.0, 2.1, 2.2, 2.3, 2.4, 2.5])  # ここに実際の電圧データを入力

# バイアス電流
current = 100e-6  # 100µA

# 抵抗値を計算
calculated_resistance_ohm = measured_voltage / current

# Steinhart-Hart方程式を用いて温度を計算
calculated_temperature_kelvin = 1 / (A + B * np.log(calculated_resistance_ohm) + C * (np.log(calculated_resistance_ohm))**3)
calculated_temperature_celsius = calculated_temperature_kelvin - 273.15

# グラフをプロット
fig, ax1 = plt.subplots(figsize=(8, 6))

# 電圧に対する温度をプロット
ax1.plot(measured_voltage, calculated_temperature_celsius, marker='o', linestyle='-', label='Temperature', color='b')

ax1.set_xlabel('Voltage (V)')
ax1.set_ylabel('Temperature (°C)')
ax1.legend(loc='upper left')
ax1.grid(True)

plt.title('Temperature vs Measured Voltage')
plt.show()

ZYBOでの動作確認

ZYBOで動かすため、C++コードを生成。
電圧から温度を計算して表示します。

①25℃を中心として少しバラつきがある動作模擬しています。適当に乱数を入れた。

#include <iostream>
#include <iomanip>
#include <cmath>
#include <cstdlib>
#include <ctime>
#include <thread>

// Steinhart-Hart定数
const double A = 6.660322320e-4;
const double B = 2.802546675e-4;
const double C = 1.366198121e-7;

// バイアス電流
const double current = 100e-6; // 100µA

// 電圧から温度を計算
double calculateTemperature(double voltage) {
    double resistance = voltage / current;
    double temperature_kelvin = 1 / (A + B * log(resistance) + C * pow(log(resistance), 3));
    return temperature_kelvin - 273.15;
}

int main() {
    // 乱数の初期化
    std::srand(std::time(nullptr));

    // ラベルを表示
    std::cout << "Voltage (V), Temperature (°C), Hexadecimal" << std::endl;

    while (true) {
        // 1V ±0.000152588Vの範囲でランダムな電圧を生成
        double voltage = 1.0 + (std::rand() % 9 - 4) * 0.000038147; // 変更: ばらつきを±4ビットに設定

        // 温度計算
        double temperature = calculateTemperature(voltage);

        // 16ビットの範囲で電圧を変換
        int voltage_hex = static_cast<int>((voltage / 2.5) * 65535);

        // 結果を表示
        std::cout << std::fixed << std::setprecision(6) // 精度を上げる
                  << voltage << " V, " << temperature << " °C, "
                  << "0x" << std::hex << voltage_hex << std::dec << std::endl;

        // 1秒待機
        std::this_thread::sleep_for(std::chrono::seconds(1));
    }

    return 0;
}

ZYBO(Petalinux)で実行した結果

root@zybo:~# ./temp2
Voltage (V), Temperature (°C), Hexadecimal
1.000114 V, 24.996795 °C, 0x6668
1.000114 V, 24.996795 °C, 0x6668
1.000000 V, 25.000000 °C, 0x6666
0.999962 V, 25.001068 °C, 0x6665
0.999847 V, 25.004273 °C, 0x6662
0.999962 V, 25.001068 °C, 0x6665
0.999886 V, 25.003205 °C, 0x6663
1.000076 V, 24.997864 °C, 0x6667
1.000000 V, 25.000000 °C, 0x6666
1.000000 V, 25.000000 °C, 0x6666
0.999924 V, 25.002137 °C, 0x6664
1.000000 V, 25.000000 °C, 0x6666
0.999962 V, 25.001068 °C, 0x6665

②0から2.5Vまで+0.1Vずつカウントアップ

#include <iostream>
#include <iomanip>
#include <cmath>

// Steinhart-Hart定数
const double A = 6.660322320e-4;
const double B = 2.802546675e-4;
const double C = 1.366198121e-7;

// バイアス電流
const double current = 100e-6; // 100µA

// 電圧から温度を計算
double calculateTemperature(double voltage) {
    double resistance = voltage / current;
    double temperature_kelvin = 1 / (A + B * log(resistance) + C * pow(log(resistance), 3));
    return temperature_kelvin - 273.15;
}

int main() {
    // ラベルを表示
    std::cout << "Voltage (V) Temperature (°C) Hexadecimal" << std::endl;

    for (double voltage = 0.0; voltage <= 2.5 + 0.05; voltage += 0.1) { // 2.5Vまで表示
        // 温度計算
        double temperature = calculateTemperature(voltage);

        // 16ビットの範囲で電圧を変換
        int voltage_hex = static_cast<int>((voltage / 2.5) * 65535);

        // 結果を表示
        std::cout << std::fixed << std::setprecision(1) // 電圧の精度を0.1Vに設定
                  << voltage << " "
                  << std::setw(10) << std::setprecision(4) << temperature << " " // 温度の精度を0.0001度に設定
                  << "0x" << std::hex << voltage_hex << std::dec << std::endl;
    }

    return 0;
}

ZYBO(Petalinux)で実行した結果。ZYNQでちゃんと計算できた。

Discussion