This notebook discusses the behaviour of accuracy and stability of 2 types of clock generators (ceramic resonator & quartz) under influence of temperature for highly precision frequency measurements.
In [1]:
import numpy as np
import matplotlib.pyplot as plt
In [2]:
data_ceramic = np.genfromtxt('temp_and_freq_error_data_ceramic')
In [3]:
freq_error_ceramic = data_ceramic[:3600, 0]
temp_ceramic = data_ceramic[:, 1]
In [4]:
t = np.arange(0, len(freq_error_ceramic))
In [5]:
fig, ax1 = plt.subplots()
plt.title("Clock frequency accuracy at 26 °C (ceramic resonator)")
plt.grid()
ax1.plot(t / 60, freq_error_ceramic, color='b')
ax1.set_ylabel("Frequency Error / Hz", color='b')
ax1.set_xlabel("t / min")
ax1.tick_params('y', colors='b')
plt.ylim([7000,9000])
ax2 = ax1.twinx()
ax2.plot(t / 60, (freq_error_ceramic / 16000000) * 10**6, color='r')
ax2.set_ylabel('PPM', color='r')
ax2.tick_params('y', colors='r')
fig.tight_layout()
plt.show()
In [6]:
std_dev_ceramic = np.std(freq_error_ceramic)
In [7]:
average_ceramic = np.average(freq_error_ceramic)
In [8]:
ppm_average_ceramic = (average_ceramic / 16000000) * 10**6
In [9]:
ppm_average_ceramic
Out[9]:
The frequency tolerance of the used ceramic resonator of the Arduino UNO is approx. 500 ppm. Consequently, this means for mains frequency measurements:
In [10]:
(50 * 500 * 10**-6) * 1000 # (mains frequency * ppm) * 1000 in mHZ
Out[10]:
In [11]:
np.max(freq_error_ceramic)
Out[11]:
In [12]:
np.min(freq_error_ceramic)
Out[12]:
The error for mains frequency measurements is 25 mHz.
In [13]:
data_temp_ceramic = np.genfromtxt('ceramic_behaviour_increasing_temperature')
In [14]:
freq_error_temp_ceramic = data_temp_ceramic[:, 0]
increasing_temp_ceramic = data_temp_ceramic[:, 1]
In [17]:
fig, ax3 = plt.subplots()
plt.title("Clock frequency stability (ceramic resonator)")
plt.grid()
ax3.plot(increasing_temp_ceramic, freq_error_temp_ceramic, color='b')
ax3.set_ylabel("Frequency Error / Hz", color='b')
ax3.set_xlabel("T / °C")
ax3.tick_params('y', colors='b')
ax4 = ax3.twinx()
ax4.plot(increasing_temp_ceramic, (freq_error_temp_ceramic / 16000000) * 10**6, color='r')
ax4.set_ylabel('PPM', color='r')
ax4.tick_params('y', colors='r')
fig.tight_layout()
plt.show()
In [18]:
data_quartz = np.genfromtxt('temp_and_freq_error_data_quartz')
In [19]:
freq_error_quartz = data_quartz[:3600, 0]
temp_quartz = data_quartz[:, 1]
In [20]:
t = np.arange(0, len(freq_error_quartz))
In [22]:
fig, ax5 = plt.subplots()
plt.title("Clock frequency accuracy at 26 °C (quartz)")
plt.grid()
ax5.plot(t / 60, freq_error_quartz, color='b')
ax5.set_ylabel("Frequency Error / Hz", color='b')
ax5.tick_params('y', colors='b')
ax5.set_xlabel("t / min")
ax6 = ax5.twinx()
ax6.plot(t / 60, (freq_error_quartz / 16000000) * 10**6, color='r')
ax6.set_ylabel('PPM', color='r')
ax6.tick_params('y', colors='r')
fig.tight_layout()
plt.show()
In [23]:
std_dev_quartz = np.std(freq_error_quartz)
In [24]:
average_quartz = np.average(freq_error_quartz)
In [25]:
ppm_average_quartz = (average_quartz / 16000000) * 10**6
In [26]:
ppm_average_quartz
Out[26]:
In [31]:
average_quartz
Out[31]:
In [32]:
np.max(freq_error_quartz)
Out[32]:
In [33]:
np.min(freq_error_quartz)
Out[33]:
In [27]:
data_temp_quartz = np.genfromtxt('quartz_behaviour_increasing_temperature.txt')
In [28]:
freq_error_temp_quartz = data_temp_quartz[:, 0]
increasing_temp_quartz = data_temp_quartz[:, 1]
In [30]:
fig, ax7 = plt.subplots()
plt.title("Clock frequency stability (quartz)")
plt.grid()
ax7.plot(increasing_temp_quartz, freq_error_temp_quartz, color='b')
ax7.set_ylabel("Frequency Error / Hz", color='b')
ax7.tick_params('y', colors='b')
ax7.set_xlabel("T / °C")
ax8 = ax7.twinx()
ax8.plot(increasing_temp_quartz, (freq_error_temp_quartz / 16000000) * 10**6, color='r')
ax8.set_ylabel('PPM', color='r')
ax8.tick_params('y', colors='r')
fig.tight_layout()
plt.show()
In [ ]: