Bepaling van warmtecapaciteit van een onbekend materiaal
#import necessary libraries
import matplotlib.pyplot as plt
import numpy as np
import math
from scipy.optimize import curve_fit Introductie¶
Onbekende materialen kunnen geïdentificeerd worden door hun eigenschappen te meten. Een van deze eigenschappen is de warmtecapaciteit. In dit practicum gaan we de warmtecapaciteit van een onbekend materiaal bepalen door middel van een calorimeter experiment. Daarbij wordt een bepaalde massa van het materiaal naar een bekende temperatuur gebracht waarna het in een bekende hoeveelheid water met bekende temperatuur wordt geplaatst. Door de temperatuur van het water te meten na het mengen kan de warmtecapaciteit van het onbekende materiaal worden berekend.
Theorie¶
De soortelijke warmte van een materiaal is gedefinieerd als de hoeveelheid warmte die nodig is om de temperatuur van een kilogram van het materiaal met één graad Celsius (of één Kelvin) te verhogen:
Waarbij de hoeveelheid warmte in Joules is, de massa in kilogram is en de verandering in temperatuur is. Gegeven de wet van Black, die stelt dat de totale hoeveelheid warmte in een geïsoleerd systeem constant blijft, kunnen we de warmte die het onbekende materiaal verliest gelijkstellen aan de warmte die het water opneemt:
wanneer we de massa’s en de begintemperaturen van beide systemen kennen, maar slechts een van de twee soortelijke warmtes, kunnen we de onbekende soortelijke warmte berekenen. We combineren vergelijkingen (1) en (2) om de volgende vergelijking te krijgen:
Waarbij de subscripts en respectievelijk staan voor begintoestand en eindtoestand, voor water en voor het onbekende materiaal.
Bij metingen aan verschillende massa’s van het onbekende materiaal en vervolgens een least square fit aan bovenstaande vergelijking kunnen we een precieze waarde voor de soortelijke warmte van het onbekende materiaal bepalen. Dat is, wanneer de warmtecapaciteit van bijvoorbeeld de beker te verwaarlozen is.
Methode en materialen¶
Ontwerp¶
De bovenstaande theorie wordt gebruikt om de soortelijke warmte van een onbekend materiaal te bepalen. Het experiment bestaat uit het verwarmen van verschillende massa’s van het onbekende materiaal tot een bekende temperatuur, waarna het in een bekende hoeveelheid water met bekende temperatuur wordt geplaats. Door de temperatuur van het water te meten na het mengen kan de warmtecapaciteit van het onbekende materiaal worden berekend. Om de tijd voor het meten van meerdere materialen te reduceren, worden de data van de verschillende groepen in het lokaal samengevoegd. Van tevoren is afgesproken welke massa’s door welke groep worden gemeten, en hoeveel water er gebruikt wordt.
Materialen¶
Hieronder staat de lijst van benodigde materialen bij deze proef:
Calorimeter
Thermometer of temperatuursensor (±0.1K)
Verwarmingsbron
Diverse massablokjes van onbekend materiaal
Weegschaal (+/- 0.1 g)
Water
Maatcilinder () of maatbeker ()
Keukenpapier
Lange steel
Roerstaaf

Figure 1:Een schematische weergave van de opstelling
Procedure¶
Bespreek wie welke massa’s van het onbekende materiaal gaat meten. Bespreek ook hoeveel water er gebruikt gaat worden. Bepaal de begintemperaturen. Hevel het aantal afgesproken massa’s in de maatbeker. Roer voorzicht zodat de temperatuur homogeen is. Noteer de hoogste gemeten temperatuur, dit is . Wissel de metingen uit met de andere groepen en voer de data-analyse uit.
Weeg vijf verschillende massa’s van de onbekende stof nauwkeurig af en noteer deze ( tot met onzekerheid +/- 0.0001 kg). Zorg voor een zo breed mogelijk bereik in massa’s. Weeg het bekerglas voordat het water wordt toegevoegd. Meet water af met de maatcilinder en giet dit in het bekerglas. De hoeveelheid water in de maatcilinder moet niet te klein zijn, omdat er anders een grote systematsche fout wordt gemaakt door warmteverlies aan de lucht. De hoeveelheid water moet ook niet te groot zijn, omdat er anders geen homogene temperatuursverandering meetbaar is. Voor elke meting wordt vers kraanwater gebruikt. Weeg telkens het bekerglas met water om de massa van het water te bepalen. Laat de onbekende stof lang genoeg, circa 5 minuten, in het verwarmingselement/ in de calorimeter zodat deze een stabiele, bekende temperatuur bereikt. Je meet de begintemperatuur van het water met een thermometer en de begintemperatuur van de onbekende stof lees je af op het verwarmingselement (aanname: T_onbekende stof = T_water in verwarmingselement). Meet de temperatuur van de water in het bekerglas vlak voor toevoeging en noteer deze, inclusief de onzekerheid van 0.1 K. Voeg, met een lange steel, de afgewogen massa van de onbekende stof zo snel en beheerst mogelijk toe aan het bekerglas om warmteverlies aan de omgeving tijdens deze stap te minimaliseren. Vervolgens roer je met een roerstaaf om gelijkmatige warmte-uitwisseling te garanderen. Zorg er hierbij voor dat de sensor vrij en stil in het water zweeft en dat de thermometer de massa of de bodem/wand niet raakt, om onjuiste lokale temperatuurmetingen te voorkomen. Blijf de temperatuur noteren totdat deze begint af te nemen na het bereiken van het maximum, of totdat de temperatuur stabiel is. De maximale temperatuur is . Noteer de onzekerheid van . Nadat de eindtemperatuur is afgelezen, wordt de thermometer telkens gedroogd. Dit voorkomt dat waterresten van een eerdere meting de volgende meting beïnvloeden. De meetresultaten vormen een dataset van massa’s () en de bijbehorende eindtemperaturen (). Deze data worden geplot in de -grafiek om de soortelijke warmte van de onbekende stof te bepalen door middel van curve-fitting.
Resultaten¶
# eerste 3 metingen met 250 ml water
# Constanten en Onzekerheden
u_massa = 0.0001 # kg
u_T = 0.1 # K
T_stof_start = 69.9
c_water = 4186
# Data: [m_beker, m_beker_water, T_start, m_stof, T_eind]
metingen = [
[0.1456, 0.3919, 20.6, 0.0388, 21.4],
[0.1899, 0.4290, 20.5, 0.0391, 21.4],
[0.1456, 0.3869, 19.2, 0.0260, 20.1]
]
# 3 metingen overzichtelijk printen
print(f"{'Nr':<4} | {'m_water (kg)':<15} | {'m_stof (kg)':<12} | {'dT (K)':<10} | {'c_stof (J/kgK)':<15}")
print("-" * 75)
# Loop door de metingen en bereken de benodigde waarden
for i, m in enumerate(metingen, 1):
m_w = m[1] - m[0]
m_s = m[3]
dT = m[4] - m[2]
# Berekening per punt
# c_s = (c_w * m_w * dT) / (m_s * (T_start_m - T_eind))
c_s = (c_water * m_w * dT) / (m_s * (T_stof_start - m[4]))
# Foutberekening (Propagatie van fouten)
u_c_s = c_s * np.sqrt((u_massa / m_w)**2 + (u_massa / m_s)**2 + (2 * u_T / dT)**2)
u_m_water = np.sqrt(u_massa**2 + u_massa**2)
print(f"{i:<4} | {m_w:>7.4f} ±{u_m_water:.4f} kg | {m_s:>7.4f} ±{u_massa:.4f} kg | {dT:>4.1f} ±{u_T*2:.1f} K | {c_s:>8.1f} ± {u_c_s:>6.1f} J/kgK")
# Voor curve_fit
m_w_array = np.array([m[1]-m[0] for m in metingen])
m_s_array = np.array([m[3] for m in metingen])
T_e_array = np.array([m[4] for m in metingen])
T_b_array = np.array([m[2] for m in metingen])Nr | m_water (kg) | m_stof (kg) | dT (K) | c_stof (J/kgK)
---------------------------------------------------------------------------
1 | 0.2463 ±0.0001 kg | 0.0388 ±0.0001 kg | 0.8 ±0.2 K | 438.3 ± 109.6 J/kgK
2 | 0.2391 ±0.0001 kg | 0.0391 ±0.0001 kg | 0.9 ±0.2 K | 475.0 ± 105.6 J/kgK
3 | 0.2413 ±0.0001 kg | 0.0260 ±0.0001 kg | 0.9 ±0.2 K | 702.1 ± 156.0 J/kgK
# eerste 3 metingen met circa 250 mL water
# berekening gemiddelde watermassa en begintemperatuur
m_w_gem = (m_w_array[0] + m_w_array[1] + m_w_array[2]) / 3
u_m_w_gem = u_massa / np.sqrt(3)
print(f"m_water_gem: {m_w_gem:.4f} ± {u_m_w_gem:.4f} kg")
T_w_b_gem = (20.6 + 20.5 + 19.2) /3
u_T_w_b_gem = u_T / np.sqrt(3)
print(f"T_water_begin_gem: {T_w_b_gem:.2f} ± {u_T_w_b_gem:.2f} °C")
m_w_gem = 0.24223333333333333 # Massa water in kg
T_w_b_gem = 20.099999999999998 # Begintemperatuur water in graden
# DATA
m_onbekende_stof1 = m_s_array
T_eind1 = np.array([21.4, 21.4, 20.1])
soortelijke_warmte_water = 4186 # J/(kg * K)
# De functie neemt alleen de onafhankelijke variabele (m_m) en de fitte parameter (c_m) als argumenten
def function_fit(m_m, c_m):
# Evenwichtstemperatuur: T_eind = (c_w * m_w * T_w_b + c_m * m_m * T_start_m) / (c_w * m_w + c_m * m_m)
teller = soortelijke_warmte_water * m_w_gem * T_w_b_gem + c_m * m_m * T_onbekende_stof_start
noemer = soortelijke_warmte_water * m_w_gem + c_m * m_m
return teller / noemer
# c_m is nu de enige parameter, dus p0=[500] als initiële gok. Koper heeft bijv. c_m ~ 385 J/(kg*K)
values, pcov = curve_fit(function_fit, m_onbekende_stof1, T_eind1, p0=[500])
c_m_fit = values[0] # c_m is nu de eerste gefitte parameter
print(f"soortelijke warmte onbekende stof: {c_m_fit:.1f} ± {np.sqrt(pcov[0,0]):.1f} J/(kg * K)")
x_test = np.linspace(min(m_onbekende_stof1)* 0.8, max(m_onbekende_stof1)*1.1, 500)
plt.figure(figsize=(8, 6), dpi=450)
plt.xlabel('$m_{m}$ (kg) - Massa onbekende stof')
plt.ylabel('$T_{eind}$ ($\\,^\circ\\text{C}$) - Evenwichtstemperatuur', rotation=0, labelpad=100, va='center')
plt.title('Eindtemperatuur versus massa onbekende stof (met watermassa ~ 0.25 kg)')
plt.ylim(19, 22)
plt.errorbar(m_onbekende_stof1, T_eind1,
xerr=u_massa, # Foutbalk op de x-as (massa)
yerr=u_T, # Foutbalk op de y-as (temperatuur)
fmt='+', # Markeringstype (het kruisje)
color='black', # Kleur van de punten en balkjes
capsize=3, # De breedte van de 'hoedjes' op de balkjes
label='Meetpunten met onzekerheid')
plt.plot(x_test, function_fit(x_test, c_m_fit), '-', label=f'Fit ($c_{{m}} \\approx {c_m_fit:.1f}\\, \\text{{J/(kg·K)}}$)')
plt.grid(True, linestyle='--', alpha=0.6)
plt.axhline(0, color='black', linewidth=0.8)
plt.axvline(0, color='black', linewidth=0.8)
plt.legend()
plt.tight_layout()
plt.savefig("fitting_result.png")
plt.show()m_water_gem: 0.2422 ± 0.0001 kg
T_water_begin_gem: 20.10 ± 0.06 °C
soortelijke warmte onbekende stof: 565.6 ± 194.3 J/(kg * K)

# laatste 4 metingen met circa 50 mL water
# Data serie 2: [m_beker, m_beker_water, T_start, m_stof, T_eind]
metingen_50ml = [
[0.0502, 0.0990, 19.9, 0.0133, 21.5], # Meting 4
[0.0326, 0.0777, 19.1, 0.0262, 21.9], # Meting 5
[0.0502, 0.0945, 19.6, 0.0131, 20.5], # Meting 6
[0.0326, 0.0854, 19.0, 0.0654, 25.1] # Meting 7
]
print(f"\n{'Nr':<4} | {'m_water (kg)':<15} | {'m_stof (kg)':<12} | {'dT (K)':<10} | {'c_stof (J/kgK)':<15}")
print("-" * 75)
for i, m in enumerate(metingen_50ml, 4):
m_w = m[1] - m[0]
m_s = m[3]
dT = m[4] - m[2]
# Berekening c_s en onzekerheden
c_s = (c_water * m_w * dT) / (m_s * (T_stof_start - m[4]))
u_c_s = c_s * np.sqrt((u_massa / m_w)**2 + (u_massa / m_s)**2 + (2 * u_T / dT)**2)
u_m_water = np.sqrt(u_massa**2 + u_massa**2)
print(f"{i:<4} | {m_w:>7.4f} ±{u_m_water:.4f} kg | {m_s:>7.4f} ±{u_massa:.4f} kg | {dT:>4.1f} ±{u_T*2:.1f} K | {c_s:>8.1f} ± {u_c_s:>6.1f} J/kgK")
# Voor je curve_fit later:
m_w_array_50ml = np.array([m[1]-m[0] for m in metingen_50ml])
m_s_array_50ml = np.array([m[3] for m in metingen_50ml])
T_e_array_50ml = np.array([m[4] for m in metingen_50ml])
T_b_array_50ml = np.array([m[2] for m in metingen_50ml])
Nr | m_water (kg) | m_stof (kg) | dT (K) | c_stof (J/kgK)
---------------------------------------------------------------------------
4 | 0.0488 ±0.0001 kg | 0.0133 ±0.0001 kg | 1.6 ±0.2 K | 507.7 ± 63.6 J/kgK
5 | 0.0451 ±0.0001 kg | 0.0262 ±0.0001 kg | 2.8 ±0.2 K | 420.3 ± 30.1 J/kgK
6 | 0.0443 ±0.0001 kg | 0.0131 ±0.0001 kg | 0.9 ±0.2 K | 257.9 ± 57.3 J/kgK
7 | 0.0528 ±0.0001 kg | 0.0654 ±0.0001 kg | 6.1 ±0.2 K | 460.2 ± 15.1 J/kgK
# laatste 4 metingen met circa 50 mL water
# berekening gemiddelde watermassa en begintemperatuur
m_w_gem = (0.0488 + 0.04510000000000001 + 0.0443 + 0.05280000000000001) / 4
u_m_w_gem = u_massa / np.sqrt(4)
print(f"m_w_gem: {m_w_gem:.5f} ± {u_m_w_gem:.5f} kg")
T_w_b_gem = (19.9 + 19.1 + 19.6 + 19.0) /4
u_T_w_b_gem = u_T / np.sqrt(4)
print(f"T_w_b_gem: {T_w_b_gem:.2f} ± {u_T_w_b_gem:.2f} graden")
m_w_gem = 0.04775 # Massa water in kg
T_w_b_gem = 19.4 # Begintemperatuur water in graden
# DATA
m_onbekende_stof2 = m_s_array_50ml
T_eind2 = np.array([21.5, 21.9, 20.5, 25.1])
# c_m is nu de enige parameter, dus p0=[500] als initiële gok
values, pcov = curve_fit(function_fit, m_onbekende_stof2, T_eind2, p0=[500])
c_m_fit = values[0] # c_m is nu de eerste (en enige) gefitte parameter (index 0)
u_c_m_fit = np.sqrt(pcov[0,0])
print(f"soortelijke warmte onbekende stof: {c_m_fit:.0f} ± {u_c_m_fit:.0f} J/(kg * K)")
x_test = np.linspace(min(m_onbekende_stof2)* 0.8, max(m_onbekende_stof2)*1.1, 500)
plt.figure(figsize=(8, 6), dpi=450)
plt.xlabel('$m_{m}$ (kg) - Massa onbekende stof')
plt.ylabel('$T_{eind}$ ($\\,^\circ\\text{C}$) - Evenwichtstemperatuur', rotation=0, labelpad=100, va='center')
plt.title('Eindtemperatuur versus Massa Onbekende Stof (met watermassa ~ 0.05 kg)')
plt.ylim(20, 26)
plt.errorbar(m_onbekende_stof2, T_eind2,
xerr=u_massa, # Foutbalkje horizontaal
yerr=u_T, # Foutbalkje verticaal
fmt='+', # Markering is een plusje
color='black', # Kleur van de punten en balkjes
capsize=3, # Horizontale streepjes op de balkjes
label='Meetpunten (incl. onzekerheid)')
plt.plot(x_test, function_fit(x_test, c_m_fit), '-', label=f'Fit ($c_{{m}} \\approx {c_m_fit:.1f}\\, \\text{{J/(kg·K)}}$)')
plt.grid(True, linestyle='--', alpha=0.6)
plt.axhline(0, color='black', linewidth=0.8)
plt.axvline(0, color='black', linewidth=0.8)
plt.legend()
plt.tight_layout()
plt.savefig("fitting_result.png")
plt.show()m_w_gem: 0.04775 ± 0.00005 kg
T_w_b_gem: 19.40 ± 0.05 graden
soortelijke warmte onbekende stof: 400 ± 32 J/(kg * K)

Source
# Sla figuren op met
# plt.savefig("Figuren/naam.png", dpi=450)
# waarbij naam vervangen wordt door de bestandsnaam.
# Onderstaande voorbeeld code en output grafiek
# Gemiddelde begintemperatuur en gemiddelde massa water berekening
Output

Figure 2:Hier is het onderschrift van de figuur.
Discussie en conclusie¶
Op basis van de tweede meetserie is de soortelijke warmte van de onbekende stof bepaald op . Dit resultaat, verkregen door het watervolume te verkleinen naar voor een beter meetbare temperatuurstijging, komt sterk overeen met de literatuurwaarde van messing (). De eerste meetserie met water bleek onvoldoende nauwkeurig door een te kleine , wat resulteerde in een afwijkende waarde van . Na uitvoering van de eerste drie metingen, is het meetplan daarom lichtelijk aangepast ( -> ).
De betrouwbaarheid van het experiment wordt echter beperkt door diverse systematische fouten. De theoretische aanname van een volledig geïsoleerd systeem werd geschonden doordat warmte ontsnapte via geleiding naar de tafel en het glas, en via straling en verdamping naar de omgeving. Daarnaast introduceerde het overbrengen van het massablokje fouten: aanklevend heet water verstoorde zowel de eindtemperatuur als de totale watermassa. Ook de beperkte nauwkeurigheid van de weegschaal () en de temperatuursensor () droeg bij aan de onzekerheid, al was dit effect ondergeschikt aan het warmteverlies.
Voor vervolgonderzoek wordt aangeraden een geïsoleerde calorimeter te gebruiken om warmteverlies te minimaliseren. Daarnaast kan de homogeniteit van de watertemperatuur worden gewaarborgd door de inzet van een magnetische roerder en een roervlo, wat zorgt voor een constante roersnelheid en meer reproduceerbare resultaten. Concluderend is de huidige opstelling met een bekerglas onvoldoende om een valide en precieze bepaling van de soortelijke warmte te garanderen.