private double IntegrateInternal(double startTime, double endTime)
{
// calculate the the points that are included in the range, plus the point above and below
double p = (startTime - (double)gateStartTime) / (double)clockPeriod;
double q = (endTime - (double)gateStartTime) / (double)clockPeriod;
int lowest = (int)Math.Floor(p);
int highest = (int)Math.Ceiling(q);
// sum over all trapeziums included in the gate range, even those partially included
double sum = 0.0;
for (int i = lowest; i < highest; i++) sum += ((double)clockPeriod * 0.5) * (tofData[i] + tofData[i + 1]);
// correct the first and last trapeziums which may not be fully included
sum -= ((2 * tofData[lowest]) + (tofData[lowest + 1] - tofData[lowest])
* (p - Math.Floor(p))) * ((double)clockPeriod * 0.5 * (p - Math.Floor(p)));
sum -= ((2 * tofData[highest]) - (tofData[highest] - tofData[highest - 1])
* (Math.Ceiling(q) - q)) * ((double)clockPeriod * 0.5 * (Math.Ceiling(q) - q));
return sum;
}