Open Pepe-Marquez opened 2 months ago
do you have a formula to calculate the band gap?
do you have a formula to calculate the band gap?
We can us the same way that we do with the EQE. We want to treat the absorptance equivalently to the EQE. In this case, we do not derive Urbach energies because we cannot resolve those very low values well with this technique.
import json
import numpy as np
import matplotlib.pyplot as plt
from scipy.interpolate import interp1d
from scipy.signal import argrelextrema, savgol_filter
from scipy.optimize import curve_fit
# Constants
h = 6.62607015e-34 # Planck's constant in Js
c = 3e8 # Speed of light in m/s
eV = 1.60218e-19 # Electron charge in Coulombs
# Set plot defaults
plt.rcParams.update({
'axes.titlesize': 24,
'axes.labelsize': 24,
'xtick.labelsize': 24,
'ytick.labelsize': 24,
'legend.fontsize': 18,
'xtick.direction': 'in',
'ytick.direction': 'in',
})
def read_data(filename):
"""Read data from a JSON file."""
with open(filename, 'r') as file:
return json.load(file)
def interpolate_data(x, y, new_x, kind='linear'):
"""Interpolate y values at new x coordinates."""
f = interp1d(x, y, kind=kind, fill_value='extrapolate')
return f(new_x)
def convert_wavelengths_to_energy(wavelengths):
"""Convert wavelengths in nm to photon energies in eV."""
wavelengths_m = wavelengths * 1e-9
return (h * c) / (wavelengths_m * eV)
def calculate_absorptance(trans_intensities, reflectance):
"""Calculate absorptance from transmittance and reflectance."""
return 1.2 - np.array(trans_intensities) - reflectance
def smooth_data(y, window_length=101, polyorder=3):
"""Apply Savitzky-Golay filter to data."""
return savgol_filter(y, window_length=window_length, polyorder=polyorder)
def find_peaks_and_fit_gaussian(x, y):
"""Detect peaks and fit a Gaussian around the highest peak."""
peaks = argrelextrema(y, np.greater)[0]
if peaks.size > 0:
peak = peaks[np.argmax(y[peaks])]
peak_energy = x[peak]
fitting_range = (x > peak_energy - 0.1) & (x < peak_energy + 0.1)
popt, _ = curve_fit(
gaussian,
x[fitting_range],
y[fitting_range],
p0=[y[peak], peak_energy, 0.05],
)
return popt[1], popt, fitting_range
return None, None, None
def gaussian(x, amp, cen, wid):
"""Gaussian function used for peak fitting."""
return amp * np.exp(-((x - cen) ** 2) / (2 * wid**2))
def plot_results(photon_energies, absorptance, fine_photon_energies, smoothed_absorptance, first_derivative, bandgap_energy, popt, fitting_range):
"""Plot the results of the calculations."""
fig, axs = plt.subplots(1, 2, figsize=(12, 6))
axs[0].plot(photon_energies, absorptance, 'o', label='Original Absorptance', alpha=0.5)
axs[0].plot(fine_photon_energies, smoothed_absorptance, '-', color='r', label='Smoothed Absorptance')
axs[0].set_ylim(-0.5, 1.1)
axs[0].set_xlabel('Photon Energy (eV)')
axs[0].set_ylabel('Absorptance')
axs[1].plot(fine_photon_energies, first_derivative, '-', label='Smoothed First Derivative')
axs[1].set_xlabel('Photon Energy (eV)')
axs[1].set_ylabel('First Derivative')
if bandgap_energy:
axs[1].plot(
fine_photon_energies[fitting_range],
gaussian(fine_photon_energies[fitting_range], *popt),
'r-',
label='Gaussian Fit',
)
axs[1].axvline(
x=bandgap_energy,
color='r',
linestyle='--',
label=f'Bandgap ~ {bandgap_energy:.2f} eV',
)
axs[0].legend()
axs[1].legend()
plt.tight_layout()
plt.show()
return fig
def main(transmittance_file, reflectance_file, start_energy=1.25, end_energy=2.8):
trans_data = read_data(transmittance_file)
refl_data = read_data(reflectance_file)
trans_wavelengths = np.array(trans_data['wavelength'])
refl_wavelengths = np.array(refl_data['wavelength'])
reflectance = interpolate_data(refl_wavelengths, np.array(refl_data['intensity']), trans_wavelengths)
photon_energies = convert_wavelengths_to_energy(trans_wavelengths)
absorptance = calculate_absorptance(trans_data['intensity'], reflectance)
energy_range_mask = (photon_energies >= start_energy) & (photon_energies <= end_energy)
fine_photon_energies = np.linspace(start_energy, end_energy, 1000)
fine_absorptance = interpolate_data(photon_energies[energy_range_mask], absorptance[energy_range_mask], fine_photon_energies, kind='cubic')
smoothed_absorptance = smooth_data(fine_absorptance)
first_derivative = np.gradient(smoothed_absorptance, fine_photon_energies)
bandgap_energy, popt, fitting_range = find_peaks_and_fit_gaussian(fine_photon_energies, first_derivative)
fig = plot_results(photon_energies, absorptance, fine_photon_energies, smoothed_absorptance, first_derivative, bandgap_energy, popt, fitting_range)
return bandgap_energy, fig
# Example usage
bandgap_energy, fig = main('transmittance.json', 'reflectance.json')
print(f'Estimated Bandgap Energy: {bandgap_energy:.3f} eV')
from pepe
Great, we can also calculate the absorbed photon flux for the AM 1.5GT spectrum
import numpy as np
from scipy.interpolate import interp1d
from scipy.integrate import simps
def calculate_absorbed_photon_flux(energy, absorptance, flux_energy, flux):
# Interpolate the absorptance spectrum to match the photon flux energy points
absorptance_interpolator = interp1d(energy, absorptance, bounds_error=False, fill_value=0)
absorptance_interpolated = absorptance_interpolator(flux_energy)
# Calculate the absorbed photon flux at each energy point
absorbed_flux = absorptance_interpolated * flux
# Integrate the absorbed photon flux over the energy range to find the total absorption
total_absorbed_flux = simps(absorbed_flux, flux_energy)
return total_absorbed_flux
and convert it for an hypothetical J_sc:
def calculate_current_density(absorbed_photon_flux, q=1.60217662e-19):
"""
Calculate the current density generated by absorbed photons.
This function computes the current density based on the absorbed photon flux,
the area over which the photons are absorbed, and the charge of an electron.
Parameters:
- absorbed_photon_flux (float): The number of photons absorbed per unit time per unit area.
- q (float, optional): The charge of an electron in coulombs (C). Default value is 1.6e-19 C.
Returns:
- float: The current density).
"""
# Calculate the current density using the formula
current_density = (q / 1e-3) * absorbed_photon_flux
return current_density
For the solar spectrum, you can use the file we use in the eqe analysis (photon_energy) vs (photon_flux)
In this measurement we need to add the following:
You would need the AM1.5 GT spectrum already used in the EQE normalizer for this.