88import numpy as np
99import pandas as pd
1010
11+ from scipy .integrate import trapezoid , cumulative_trapezoid
1112from scipy .interpolate import interp1d
1213from scipy .optimize import curve_fit , minimize
1314from typing import List , Dict , Union # for type hints in functions
@@ -293,42 +294,108 @@ def combine_repetitions(database, condition, temp_program="constant_heating_rate
293294 return df_combined
294295
295296
296- def differential_conversion (differential_data , m_0 = None , m_f = None ):
297- # TODO: add differential conversion computation
298- raise ValueError (f" * Still under development." )
299- return
297+ def differential_conversion (time , differential_data ):
298+ """
299+ Calculate the conversion (alpha) from differential experimental data.
300+
301+ This function computes the conversion (alpha) for a series of
302+ differential experimental data, such as heat flow (DSC) or heat
303+ release rate (MCC), by integrating the signal over time and
304+ normalizing by the total integrated value.
305+
306+ For DSC-type data, the idea can be written as:
307+
308+ .. math::
309+
310+ \\ Delta H(t_i) = \\ int_{t_0}^{t_i} \\ frac{dH}{dt} \\ , dt
311+
312+ \\ Delta H_\\ text{tot} = \\ int_{t_0}^{t_f} \\ frac{dH}{dt} \\ , dt
313+
314+ \\ alpha(t_i) = \\ frac{\\ Delta H(t_i)}{\\ Delta H_\\ text{tot}}
315+
316+ where:
317+ \\ alpha = conversion,
318+ H = enthalpy (or another extensive quantity),
319+ t_0 = initial time,
320+ t_i = instantaneous time,
321+ t_f = final time.
322+
323+ Parameters
324+ ----------
325+ time : pd.Series or np.ndarray
326+ Time series of the experiment in seconds.
327+ differential_data : pd.Series or np.ndarray
328+ Experimental data representing differential quantities
329+ (e.g., heat flow (DSC) or heat release rate (MCC))
330+ used to calculate the conversion.
331+
332+ Returns
333+ -------
334+ np.ndarray
335+ Array of alpha values representing the conversion.
336+ """
337+
338+ # Convert the input data to NumPy arrays for calculations
339+ time = series_to_numpy (time )
340+ differential_data = series_to_numpy (differential_data )
341+
342+ # Check if proper data was provided
343+ if time .shape != differential_data .shape :
344+ raise ValueError (
345+ "time and differential_data must have the same shape "
346+ f"(got { time .shape } and { differential_data .shape } )."
347+ )
348+
349+ # Compute the total H (integral over the full signal)
350+ Delta_H_total = trapezoid (differential_data , time )
351+
352+ # Prevent division by zero
353+ if Delta_H_total == 0 :
354+ raise ValueError ("Total integral of differential_data is zero; cannot compute conversion (division by zero)." )
355+
356+ # Compute cumulative H over time (same length as input)
357+ Delta_H = cumulative_trapezoid (differential_data , time , initial = 0.0 )
358+
359+ # Compute the conversion
360+ alpha = Delta_H / Delta_H_total
361+
362+ return alpha
300363
301364
302365def integral_conversion (integral_data , m_0 = None , m_f = None ):
303366 """
304367 Calculate the conversion (alpha) from integral experimental data.
305368
306- This function computes the conversion (alpha) for a series of
307- integral experimental data, such as mass or concentration, based on the
308- formula:
369+ This function computes the conversion (alpha) from a series of
370+ integral experimental data, such as sample mass (TGA) or concentrations,
371+ by normalizing the change in the quantity with respect to its
372+ initial and final values.
373+
374+ For TGA-type data, the idea can be written as:
309375
310376 .. math::
311377
312- \\ alpha = \\ frac{m_0 - m_i}{m_0 - m_f}
378+ \\ alpha(t_i) = \\ frac{m_0 - m_i}{m_0 - m_f}
313379
314380 where:
315- m_0 = initial mass/concentration,
316- m_i = instantaneous mass/concentration,
317- m_f = final mass/concentration.
381+ \\ alpha = conversion,
382+ m_0 = initial mass ,
383+ m_i = instantaneous mass at time t_i,
384+ m_f = final mass (e.g., char or residue).
318385
319386 If `m_0` and `m_f` are not provided, they default to the first and last
320387 values of the `integral_data` series, respectively.
321388
322389 Parameters
323390 ----------
324391 integral_data : pd.Series or np.ndarray
325- Experimental data representing integral quantities
326- (e.g. , mass or concentration over time) to calculate the conversion .
392+ Experimental data representing an integral quantity
393+ (typically , mass over time in TGA, or concentration) .
327394 m_0 : float, optional
328- Initial mass/concentration . Defaults to the first
395+ Initial value (e.g., initial mass) . Defaults to the first
329396 value of `integral_data`.
330397 m_f : float, optional
331- Final mass/concentration . Defaults to the last
398+ Final value (e.g., residual mass) . Defaults to the last
332399 value of `integral_data`.
333400
334401 Returns
@@ -337,7 +404,7 @@ def integral_conversion(integral_data, m_0=None, m_f=None):
337404 Array of alpha values representing the conversion.
338405 """
339406
340- # Convert the input data to a numpy array for calculations
407+ # Convert the input data to a NumPy array for calculations
341408 m_i = series_to_numpy (integral_data )
342409
343410 # Use the provided m_0 or default to the first value in the series
0 commit comments