📑
ZYNQ (Petalinux) でサーミスタを使って温度を計測する①
目的
仕事でZYBOでサーミスタで計測した電圧から温度を計算する必要があったため、調査した。
B定数ではなく、Steinhart-Hart方程式を使用して、サーミスタの抵抗値から、ABC定数を算出。
Pythonで電圧から温度を計算し、その後、C++を用いてZYNQのPetalinux上で計算を実施しました。
Steinhart-Hart定数の計算
10、25、50度の時のサーミスタの抵抗値より、Steinhart-Hart定数を計算します。
定数は下記のサイトを使った。
サーミスタ(103ET-1)のデータシート
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