From b127cc15e2a2ff28637398cd26080cd7f5c32a73 Mon Sep 17 00:00:00 2001 From: Dominik Demuth Date: Tue, 16 May 2023 19:22:50 +0200 Subject: [PATCH] dsc: only use low temperature to baseline correct calibration without enthalpy --- src/nmreval/io/dsc.py | 64 ++++++++++++++++++++++++------------------- 1 file changed, 36 insertions(+), 28 deletions(-) diff --git a/src/nmreval/io/dsc.py b/src/nmreval/io/dsc.py index 532df8f..19ee743 100644 --- a/src/nmreval/io/dsc.py +++ b/src/nmreval/io/dsc.py @@ -5,6 +5,8 @@ import re from collections import namedtuple import numpy as np +from matplotlib import pyplot as plt +from scipy.stats import linregress try: from scipy.integrate import simpson @@ -200,35 +202,24 @@ class DSCCalibrator: high_border = np.argmin(np.abs(measurement[0] - t_high_lim)) ref_zoom = measurement[:, low_border:high_border] - x_val = np.array([[ref_zoom[0, 0], 1], [ref_zoom[0, -1], 1]]) - y_val = np.array([ref_zoom[1, 0], ref_zoom[1, -1]]) - - sol = np.linalg.solve(x_val, y_val) - ref_zoom[1] -= (ref_zoom[0] * sol[0] + sol[1]) - - ref_grad = np.gradient(ref_zoom[1]) - crossing = np.where(np.diff(np.sign(np.abs(ref_grad)-0.001)))[0] - - almost_flat = np.sort(crossing-np.argmax(ref_zoom[1])) - integ_limit = (almost_flat[np.where((almost_flat < -20))[0][-1]]+np.argmax(ref_zoom[1]), - almost_flat[np.where((almost_flat > 20))[0][0]]+np.argmax(ref_zoom[1])) - - # subtract baseline around reference peak - sol = self.solve_linear_eq(integ_limit, ref_zoom) - ref_zoom[1] -= (ref_zoom[0] * sol[0] + sol[1]) - - # calculate onset slope (use points at position of maximum gradient - 100/rate (+50/rate)) - ref_grad = np.gradient(ref_zoom[1]) - max_grad = np.argmax(ref_grad) - - grad_pos = max_grad-max(1, int(160 / rate)), max_grad - - sol = self.solve_linear_eq(grad_pos, ref_zoom) - onset = sol[0] * ref_zoom[0] + sol[1] - - melts.append(-sol[1] / sol[0]) - if enthalpy is not None: + x_val = np.array([[ref_zoom[0, 0], 1], [ref_zoom[0, -1], 1]]) + y_val = np.array([ref_zoom[1, 0], ref_zoom[1, -1]]) + + sol = np.linalg.solve(x_val, y_val) + ref_zoom[1] -= (ref_zoom[0] * sol[0] + sol[1]) + + ref_grad = np.gradient(ref_zoom[1]) + crossing = np.where(np.diff(np.sign(np.abs(ref_grad)-0.001)))[0] + + almost_flat = np.sort(crossing-np.argmax(ref_zoom[1])) + integ_limit = (almost_flat[np.where((almost_flat < -40))[0][-1]]+np.argmax(ref_zoom[1]), + almost_flat[np.where((almost_flat > 40))[0][0]]+np.argmax(ref_zoom[1])) + + # subtract baseline around reference peak + sol = self.solve_linear_eq(integ_limit, ref_zoom) + ref_zoom[1] -= (ref_zoom[0] * sol[0] + sol[1]) + # integrate over peak to calibrate y axis # delta H in J/g: Integrate Peak over time and divide by weight area = simpson(ref_zoom[1, integ_limit[0]:integ_limit[1]], @@ -236,6 +227,23 @@ class DSCCalibrator: even='avg') * 1e-3 calib_y.append(enthalpy / (area / data.weight)) + else: + ref_grad = np.gradient(ref_zoom[1]) + res = linregress(ref_zoom[0, :len(ref_grad)//5], ref_zoom[1, :len(ref_grad)//5]) + + ref_zoom[1] -= (res.slope*ref_zoom[0] + res.intercept) + + # calculate onset slope (use points at position of maximum gradient - 100/rate (+50/rate)) + ref_grad = np.gradient(ref_zoom[1]) + max_grad = np.argmax(ref_grad) + + grad_pos = max_grad - max(1, int(160 / rate)), max_grad + + sol = self.solve_linear_eq(grad_pos, ref_zoom) + onset = sol[0] * ref_zoom[0] + sol[1] + + melts.append(-sol[1] / sol[0]) + results.append([ref_zoom, onset, ref_zoom[:, grad_pos]]) if len(melts) > 1: