void Ltas_fitTiltLine (Ltas me, double fmin, double fmax, bool lnf, int method, double *a, double *b) { try { if (fmax <= fmin) { fmin = my xmin; fmax = my xmax; } long ifmin, ifmax, numberOfSamples = Sampled_getWindowSamples (me, fmin, fmax, &ifmin, &ifmax); if (numberOfSamples < 2) { Melder_throw ("There must be at least two data points to fit a line."); } autoNUMvector<double> x (1, numberOfSamples); autoNUMvector<double> y (1, numberOfSamples); for (long i = ifmin; i <= ifmax; i++) { long ixy = i - ifmin + 1; x[ixy] = my x1 + (i - 1) * my dx; if (lnf) { // For Ltas always x1 > 0 x[ixy] = log10 (x[ixy]); } y[ixy] = my z[1][i]; } NUMlineFit (x.peek(), y.peek(), numberOfSamples, a, b, method); } catch (MelderError) { Melder_throw ("Tilt line not determined."); } }
/* Fit line y = ax+b (lineType ==1) or y = a log(x) + b (lineType == 2) on interval [qmin,qmax] * method == 1 : Least squares fit * method == 2 : Theil's partial robust fit */ void PowerCepstrum_fitTiltLine (PowerCepstrum me, double qmin, double qmax, double *p_a, double *p_intercept, int lineType, int method) { try { double a, intercept; if (qmax <= qmin) { qmin = my xmin; qmax = my xmax; } long imin, imax; if (! Matrix_getWindowSamplesX (me, qmin, qmax, & imin, & imax)) { return; } imin = (lineType == 2 && imin == 1) ? 2 : imin; // log(0) is undefined! long numberOfPoints = imax - imin + 1; if (numberOfPoints < 2) { Melder_throw (U"Not enough points for fit."); } autoNUMvector<double> y (1, numberOfPoints); autoNUMvector<double> x (1, numberOfPoints); for (long i = 1; i <= numberOfPoints; i++) { long isamp = imin + i - 1; x[i] = my x1 + (isamp - 1) * my dx; if (lineType == 2) { x[i] = log (x[i]); } y[i] = my v_getValueAtSample (isamp, 1, 0); } if (method == 3) { // try local maxima first autoNUMvector<double> ym (1, numberOfPoints / 2 + 1); autoNUMvector<double> xm (1, numberOfPoints / 2 + 1); long numberOfLocalPeaks = 0; // forget y[1] if y[2]<y[1] and y[n] if y[n-1]<y[n] ! for (long i = 2; i <= numberOfPoints; i++) { if (y[i - 1] <= y[i] && y[i] > y[i + 1]) { ym[++numberOfLocalPeaks] = y[i]; xm[numberOfLocalPeaks] = x[i]; } } if (numberOfLocalPeaks > numberOfPoints / 10) { for (long i = 1; i <= numberOfLocalPeaks; i++) { x[i] = xm[i]; y[i] = ym[i]; } numberOfPoints = numberOfLocalPeaks; } method = 2; // robust fit of peaks } // fit a straight line through (x,y)'s NUMlineFit (x.peek(), y.peek(), numberOfPoints, & a, & intercept, method); if (p_intercept) { *p_intercept = intercept; } if (p_a) { *p_a = a; } } catch (MelderError) { Melder_throw (me, U": couldn't fit a line."); } }