static autoCepstrum Spectrum_to_Cepstrum2 (Spectrum me) { try { autoNUMfft_Table fftTable; // originalNumberOfSamplesProbablyOdd irrelevant if (my x1 != 0.0) { Melder_throw (U"A Fourier-transformable Spectrum must have a first frequency of 0 Hz, not ", my x1, U" Hz."); } long numberOfSamples = 2 * my nx - 2; autoCepstrum thee = Cepstrum_create (0.5 / my dx, my nx); // my dx = 1 / (dT * N) = 1 / (duration of sound) thy dx = 1 / (my dx * numberOfSamples); // Cepstrum is on [-T/2, T/2] ! NUMfft_Table_init (&fftTable, numberOfSamples); autoNUMvector<double> fftbuf (1, numberOfSamples); fftbuf[1] = my v_getValueAtSample (1, 0, 2); for (long i = 2; i < my nx; i++) { fftbuf [i + i - 2] = my v_getValueAtSample (i, 0, 2); fftbuf [i + i - 1] = 0.0; } fftbuf [numberOfSamples] = my v_getValueAtSample (my nx, 0, 2); NUMfft_backward (&fftTable, fftbuf.peek()); for (long i = 1; i <= my nx; i++) { double val = fftbuf[i] / numberOfSamples; // scaling 1/n because ifft(fft(1))= n; thy z[1][i] = val * val; // power cepstrum } return thee; } catch (MelderError) { Melder_throw (me, U": not converted to Cepstrum."); } }
void Spectrum_drawInside (Spectrum me, Graphics g, double fmin, double fmax, double minimum, double maximum) { int autoscaling = minimum >= maximum; if (fmax <= fmin) { fmin = my xmin; fmax = my xmax; } long ifmin, ifmax; if (! Matrix_getWindowSamplesX (me, fmin, fmax, & ifmin, & ifmax)) return; autoNUMvector <double> yWC (ifmin, ifmax); /* * First pass: compute power density. */ if (autoscaling) maximum = -1e30; for (long ifreq = ifmin; ifreq <= ifmax; ifreq ++) { double y = my v_getValueAtSample (ifreq, 0, 2); if (autoscaling && y > maximum) maximum = y; yWC [ifreq] = y; } if (autoscaling) minimum = maximum - 60; /* Default dynamic range is 60 dB. */ /* * Second pass: clip. */ for (long ifreq = ifmin; ifreq <= ifmax; ifreq ++) { if (yWC [ifreq] < minimum) yWC [ifreq] = minimum; else if (yWC [ifreq] > maximum) yWC [ifreq] = maximum; } Graphics_setWindow (g, fmin, fmax, minimum, maximum); Graphics_function (g, yWC.peek(), ifmin, ifmax, Matrix_columnToX (me, ifmin), Matrix_columnToX (me, ifmax)); }
Cepstrum Spectrum_to_Cepstrum_hillenbrand (Spectrum me) { try { autoNUMfft_Table fftTable; // originalNumberOfSamplesProbablyOdd irrelevant if (my x1 != 0.0) { Melder_throw ("A Fourier-transformable Spectrum must have a first frequency of 0 Hz, not ", my x1, L" Hz."); } long numberOfSamples = my nx - 1; autoCepstrum thee = Cepstrum_create (0.5 / my dx, my nx); NUMfft_Table_init (&fftTable, my nx); autoNUMvector<double> amp (1, my nx); for (long i = 1; i <= my nx; i++) { amp [i] = my v_getValueAtSample (i, 0, 2); } NUMfft_forward (&fftTable, amp.peek()); for (long i = 1; i <= my nx; i++) { double val = amp[i] / numberOfSamples;// scaling 1/n because ifft(fft(1))= n; thy z[1][i] = val * val; // power cepstrum } return thee.transfer(); } catch (MelderError) { Melder_throw (me, ": not converted to Sound."); } }
long Sampled_countDefinedSamples (Sampled me, long ilevel, int unit) { long numberOfDefinedSamples = 0; for (long isamp = 1; isamp <= my nx; isamp ++) { double value = my v_getValueAtSample (isamp, ilevel, unit); if (value == NUMundefined) continue; numberOfDefinedSamples += 1; } return numberOfDefinedSamples; }
void BandFilterSpectrogram_drawSpectrumAtNearestTimeSlice (BandFilterSpectrogram me, Graphics g, double time, double fmin, double fmax, double dBmin, double dBmax, int garnish) { if (time < my xmin || time > my xmax) { return; } if (fmin == 0 && fmax == 0) { // autoscaling fmin = my ymin; fmax = my ymax; } if (fmax <= fmin) { fmin = my ymin; fmax = my ymax; } long icol = Matrix_xToNearestColumn (me, time); icol = icol < 1 ? 1 : (icol > my nx ? my nx : icol); autoNUMvector<double> spectrum (1, my ny); for (long i = 1; i <= my ny; i++) { spectrum[i] = my v_getValueAtSample (icol, i, 1); // dB's } long iymin, iymax; if (Matrix_getWindowSamplesY (me, fmin, fmax, &iymin, &iymax) < 2) { // too few values return; } if (dBmin == dBmax) { // autoscaling dBmin = spectrum[iymin]; dBmax = dBmin; for (long i = iymin + 1; i <= iymax; i++) { if (spectrum[i] < dBmin) { dBmin = spectrum[i]; } else if (spectrum[i] > dBmax) { dBmax = spectrum[i]; } } if (dBmin == dBmax) { dBmin -= 1; dBmax += 1; } } Graphics_setWindow (g, fmin, fmax, dBmin, dBmax); Graphics_setInner (g); double x1 = my y1 + (iymin -1) * my dy, y1 = spectrum[iymin]; for (long i = iymin + 1; i <= iymax - 1; i++) { double x2 = my y1 + (i -1) * my dy, y2 = spectrum[i]; double xo1, yo1, xo2, yo2; if (NUMclipLineWithinRectangle (x1, y1, x2, y2, fmin, dBmin, fmax, dBmax, &xo1, &yo1, &xo2, &yo2)) { Graphics_line (g, xo1, yo1, xo2, yo2); } x1 = x2; y1 = y2; } Graphics_unsetInner (g); if (garnish) { Graphics_drawInnerBox (g); Graphics_marksBottom (g, 2, 1, 1, 0); Graphics_marksLeft (g, 2, 1, 1, 0); Graphics_textLeft (g, 1, U"Power (dB)"); Graphics_textBottom (g, 1, Melder_cat (U"Frequency (", my v_getFrequencyUnit (), U")")); } }
// Hillenbrand subtracts dB values and if the result is negative it is made zero static void PowerCepstrum_subtractTiltLine_inline2 (PowerCepstrum me, double slope, double intercept, int lineType) { for (long j = 1; j <= my nx; j++) { double q = my x1 + (j - 1) * my dx; q = j == 1 ? 0.5 * my dx : q; // approximation double xq = lineType == 2 ? log(q) : q; double db_background = slope * xq + intercept; double db_cepstrum = my v_getValueAtSample (j, 1, 0); double diff = exp ((db_cepstrum - db_background) * NUMln10 / 10) - 1e-30; my z[1][j] = diff; } }
/* 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."); } }
double * Sampled_getSortedValues (Sampled me, long ilevel, int unit, long *return_numberOfValues) { long isamp, numberOfDefinedSamples = 0; autoNUMvector <double> values (1, my nx); for (isamp = 1; isamp <= my nx; isamp ++) { double value = my v_getValueAtSample (isamp, ilevel, unit); if (value == NUMundefined) continue; values [++ numberOfDefinedSamples] = value; } if (numberOfDefinedSamples) NUMsort_d (numberOfDefinedSamples, values.peek()); if (return_numberOfValues) *return_numberOfValues = numberOfDefinedSamples; return values.transfer(); }
autoSound BandFilterSpectrogram_as_Sound (BandFilterSpectrogram me, int unit) { try { autoSound thee = Sound_create (my ny, my xmin, my xmax, my nx, my dx, my x1); for (long i = 1; i <= my ny; i ++) { for (long j = 1; j <= my nx; j ++) thy z[i][j] = my v_getValueAtSample (j, i, unit); } return thee; } catch (MelderError) { Melder_throw (me, U": no Sound created."); } }
double Sampled_getValueAtX (Sampled me, double x, long ilevel, int unit, int interpolate) { if (x < my xmin || x > my xmax) return NUMundefined; if (interpolate) { double ireal = Sampled_xToIndex (me, x); long ileft = floor (ireal), inear, ifar; double phase = ireal - ileft; if (phase < 0.5) { inear = ileft, ifar = ileft + 1; } else { ifar = ileft, inear = ileft + 1; phase = 1.0 - phase; } if (inear < 1 || inear > my nx) return NUMundefined; // x out of range? double fnear = my v_getValueAtSample (inear, ilevel, unit); if (fnear == NUMundefined) return NUMundefined; // function value not defined? if (ifar < 1 || ifar > my nx) return fnear; // at edge? Extrapolate double ffar = my v_getValueAtSample (ifar, ilevel, unit); if (ffar == NUMundefined) return fnear; // neighbour undefined? Extrapolate return fnear + phase * (ffar - fnear); // interpolate } return Sampled_getValueAtSample (me, Sampled_xToNearestIndex (me, x), ilevel, unit); }
Matrix BandFilterSpectrogram_to_Matrix (BandFilterSpectrogram me, int to_dB) { try { int units = to_dB ? 1 : 0; autoMatrix thee = Matrix_create (my xmin, my xmax, my nx, my dx, my x1, my ymin, my ymax, my ny, my dy, my y1); for (long i = 1; i <= my ny; i++) { for (long j = 1; j <= my nx; j++) { thy z[i][j] = my v_getValueAtSample (j, i, units); } } return thee.transfer(); } catch (MelderError) { Melder_throw (me, U": not converted to Matrix."); } }
void PowerCepstrum_getMaximumAndQuefrency (PowerCepstrum me, double pitchFloor, double pitchCeiling, int interpolation, double *p_peakdB, double *p_quefrency) { double peakdB, quefrency; autoPowerCepstrum thee = Data_copy (me); double lowestQuefrency = 1.0 / pitchCeiling, highestQuefrency = 1.0 / pitchFloor; for (long i = 1; i <= my nx; i ++) { thy z[1][i] = my v_getValueAtSample (i, 1, 0); // 10 log val^2 } Vector_getMaximumAndX ((Vector) thee.get(), lowestQuefrency, highestQuefrency, 1, interpolation, & peakdB, & quefrency); // FIXME cast if (p_peakdB) { *p_peakdB = peakdB; } if (p_quefrency) { *p_quefrency = quefrency; } }
static void _Cepstrum_draw (Cepstrum me, Graphics g, double qmin, double qmax, double minimum, double maximum, int power, int garnish) { int autoscaling = minimum >= maximum; Graphics_setInner (g); if (qmax <= qmin) { qmin = my xmin; qmax = my xmax; } long imin, imax; if (! Matrix_getWindowSamplesX (me, qmin, qmax, & imin, & imax)) { return; } autoNUMvector<double> y (imin, imax); for (long i = imin; i <= imax; i++) { y[i] = my v_getValueAtSample (i, (power ? 1 : 0), 0); } if (autoscaling) { NUMvector_extrema (y.peek(), imin, imax, & minimum, & maximum); } else { for (long i = imin; i <= imax; i ++) { if (y[i] > maximum) { y[i] = maximum; } else if (y[i] < minimum) { y[i] = minimum; } } } Graphics_setWindow (g, qmin, qmax, minimum, maximum); Graphics_function (g, y.peek(), imin, imax, Matrix_columnToX (me, imin), Matrix_columnToX (me, imax)); Graphics_unsetInner (g); if (garnish) { Graphics_drawInnerBox (g); Graphics_textBottom (g, true, U"Quefrency (s)"); Graphics_marksBottom (g, 2, true, true, false); Graphics_textLeft (g, true, power ? U"Amplitude (dB)" : U"Amplitude"); Graphics_marksLeft (g, 2, true, true, false); } }
static void Cepstrum_getZ (Cepstrum me, long imin, long imax, double peakdB, double slope, double intercept, int lineType, double *z) { long ndata = imax - imin + 1; autoNUMvector<double> dabs (1, ndata); for (long i = imin; i <= imax; i ++) { double q = my x1 + (i - 1) * my dx; q = ( i == 1 ? 0.5 * my dx : q ); // approximation double xq = ( lineType == 2 ? log (q) : q ); double db_background = slope * xq + intercept; double db_cepstrum = my v_getValueAtSample (i, 1, 0); double diff = exp ((db_cepstrum - db_background) * NUMln10 / 10.0) - 1e-30; //double diff = fabs (db_cepstrum - db_background); dabs [i - imin + 1] = diff; } double q50 = NUMquantile (ndata, dabs.peek(), 0.5); double peak = exp (peakdB * NUMln10 / 10.0) - 1e-30; if (z) { *z = peak / q50; } }
/* Precondition: 1. CC object has been created but individual frames not yet initialized * 2. Domains and number of frames conform * Steps: * 1. transform power-spectra to dB-spectra * 2. cosine transform of dB-spectrum */ void BandFilterSpectrogram_into_CC (BandFilterSpectrogram me, CC thee, long numberOfCoefficients) { autoNUMmatrix<double> cosinesTable (NUMcosinesTable (my ny), 1, 1); autoNUMvector<double> x (1, my ny); autoNUMvector<double> y (1, my ny); numberOfCoefficients = numberOfCoefficients > my ny - 1 ? my ny - 1 : numberOfCoefficients; Melder_assert (numberOfCoefficients > 0); // 20130220 new interpretation of maximumNumberOfCoefficients necessary for inverse transform for (long frame = 1; frame <= my nx; frame++) { CC_Frame ccframe = (CC_Frame) & thy frame[frame]; for (long i = 1; i <= my ny; i++) { x[i] = my v_getValueAtSample (frame, i, 1); // z[i][frame]; } NUMcosineTransform (x.peek(), y.peek(), my ny, cosinesTable.peek()); CC_Frame_init (ccframe, numberOfCoefficients); for (long i = 1; i <= numberOfCoefficients; i++) { ccframe -> c[i] = y[i + 1]; } ccframe -> c0 = y[1]; } }
void Spectrum_drawLogFreq (Spectrum me, Graphics g, double fmin, double fmax, double minimum, double maximum, int garnish) { int autoscaling = minimum >= maximum; if (fmax <= fmin) { fmin = my xmin; fmax = my xmax; } long ifmin, ifmax; if (! Matrix_getWindowSamplesX (me, fmin, fmax, & ifmin, & ifmax)) return; if(ifmin==1)ifmin=2; /* BUG */ autoNUMvector <double> xWC (ifmin, ifmax); autoNUMvector <double> yWC (ifmin, ifmax); /* * First pass: compute power density. */ if (autoscaling) maximum = -1e6; for (long ifreq = ifmin; ifreq <= ifmax; ifreq ++) { xWC [ifreq] = log10 (my x1 + (ifreq - 1) * my dx); yWC [ifreq] = my v_getValueAtSample (ifreq, 0, 2); if (autoscaling && yWC [ifreq] > maximum) maximum = yWC [ifreq]; } if (autoscaling) minimum = maximum - 60; /* Default dynamic range is 60 dB. */ /* * Second pass: clip. */ for (long ifreq = ifmin; ifreq <= ifmax; ifreq ++) { if (yWC [ifreq] < minimum) yWC [ifreq] = minimum; else if (yWC [ifreq] > maximum) yWC [ifreq] = maximum; } Graphics_setInner (g); Graphics_setWindow (g, log10 (fmin), log10 (fmax), minimum, maximum); Graphics_polyline (g, ifmax - ifmin + 1, & xWC [ifmin], & yWC [ifmin]); Graphics_unsetInner (g); if (garnish) { Graphics_drawInnerBox (g); Graphics_textBottom (g, 1, L"Frequency (Hz)"); Graphics_marksBottomLogarithmic (g, 3, TRUE, TRUE, FALSE); Graphics_textLeft (g, 1, L"Sound pressure level (dB/Hz)"); Graphics_marksLeftEvery (g, 1.0, 20.0, TRUE, TRUE, FALSE); } }
double PowerCepstrum_getRNR (PowerCepstrum me, double pitchFloor, double pitchCeiling, double f0fractionalWidth) { double rnr = NUMundefined; double qmin = 1.0 / pitchCeiling, qmax = 1.0 / pitchFloor, peakdB, qpeak; PowerCepstrum_getMaximumAndQuefrency (me, pitchFloor, pitchCeiling, 2, &peakdB, &qpeak); long imin, imax; if (! Matrix_getWindowSamplesX (me, qmin, qmax, & imin, & imax)) { return rnr; } long ndata = imax - imin + 1; if (ndata < 2) { return rnr; } // how many peaks in interval ? long npeaks = 2; while (qpeak > 0 && qpeak * npeaks <= qmax) { npeaks++; } npeaks--; double sum = 0, sumr = 0; for (long i = imin; i <= imax; i++) { double val = my v_getValueAtSample (i, 0, 0); double qx = my x1 + (i - 1) * my dx; sum += val; // is qx within an interval around a multiple of the peak's q ? for (long j = 1; j <= npeaks; j ++) { double f0c = 1.0 / (j * qpeak); double f0clow = f0c * (1.0 - f0fractionalWidth); double f0chigh = f0c * (1.0 + f0fractionalWidth); double qclow = 1.0 / f0chigh; double qchigh = ( f0fractionalWidth >= 1 ? qmax : 1.0 / f0clow ); if (qx >= qclow && qx <= qchigh) { // yes in rahmonic interval sumr += val; break; } } } rnr = sumr >= sum ? 1000000 : sumr / (sum - sumr); return rnr; }
double Sampled_getQuantile (Sampled me, double xmin, double xmax, double quantile, long ilevel, int unit) { try { autoNUMvector <double> values (1, my nx); Function_unidirectionalAutowindow (me, & xmin, & xmax); if (! Function_intersectRangeWithDomain (me, & xmin, & xmax)) return NUMundefined; long imin, imax, numberOfDefinedSamples = 0; Sampled_getWindowSamples (me, xmin, xmax, & imin, & imax); for (long i = imin; i <= imax; i ++) { double value = my v_getValueAtSample (i, ilevel, unit); if (NUMdefined (value)) { values [++ numberOfDefinedSamples] = value; } } double result = NUMundefined; if (numberOfDefinedSamples >= 1) { NUMsort_d (numberOfDefinedSamples, values.peek()); result = NUMquantile (numberOfDefinedSamples, values.peek(), quantile); } return result; } catch (MelderError) { Melder_throw (me, ": quantile not computed."); } }
void Sampled_getMaximumAndX (Sampled me, double xmin, double xmax, long ilevel, int unit, int interpolate, double *return_maximum, double *return_xOfMaximum) { long imin, imax, i; double maximum = -1e301, xOfMaximum = 0.0; if (xmin == NUMundefined || xmax == NUMundefined) { maximum = xOfMaximum = NUMundefined; goto end; } Function_unidirectionalAutowindow (me, & xmin, & xmax); if (! Function_intersectRangeWithDomain (me, & xmin, & xmax)) { maximum = xOfMaximum = NUMundefined; // requested range and logical domain do not intersect goto end; } if (! Sampled_getWindowSamples (me, xmin, xmax, & imin, & imax)) { /* * No sample centres between tmin and tmax. * Try to return the greater of the values at these two points. */ double fleft = Sampled_getValueAtX (me, xmin, ilevel, unit, interpolate); double fright = Sampled_getValueAtX (me, xmax, ilevel, unit, interpolate); if (NUMdefined (fleft) && fleft > maximum) maximum = fleft, xOfMaximum = xmin; if (NUMdefined (fright) && fright > maximum) maximum = fright, xOfMaximum = xmax; } else { for (i = imin; i <= imax; i ++) { double fmid = my v_getValueAtSample (i, ilevel, unit); if (fmid == NUMundefined) continue; if (interpolate == FALSE) { if (fmid > maximum) maximum = fmid, xOfMaximum = i; } else { /* * Try an interpolation, possibly even taking into account a sample just outside the selection. */ double fleft = i <= 1 ? NUMundefined : my v_getValueAtSample (i - 1, ilevel, unit); double fright = i >= my nx ? NUMundefined : my v_getValueAtSample (i + 1, ilevel, unit); if (fleft == NUMundefined || fright == NUMundefined) { if (fmid > maximum) maximum = fmid, xOfMaximum = i; } else if (fmid > fleft && fmid >= fright) { double y [4], i_real, localMaximum; y [1] = fleft, y [2] = fmid, y [3] = fright; localMaximum = NUMimproveMaximum (y, 3, 2, NUM_PEAK_INTERPOLATE_PARABOLIC, & i_real); if (localMaximum > maximum) maximum = localMaximum, xOfMaximum = i_real + i - 2; } } } xOfMaximum = my x1 + (xOfMaximum - 1) * my dx; /* From index plus phase to time. */ /* Check boundary values. */ if (interpolate) { double fleft = Sampled_getValueAtX (me, xmin, ilevel, unit, TRUE); double fright = Sampled_getValueAtX (me, xmax, ilevel, unit, TRUE); if (NUMdefined (fleft) && fleft > maximum) maximum = fleft, xOfMaximum = xmin; if (NUMdefined (fright) && fright > maximum) maximum = fright, xOfMaximum = xmax; } if (xOfMaximum < xmin) xOfMaximum = xmin; if (xOfMaximum > xmax) xOfMaximum = xmax; } if (maximum == -1e301) maximum = xOfMaximum = NUMundefined; end: if (return_maximum) *return_maximum = maximum; if (return_xOfMaximum) *return_xOfMaximum = xOfMaximum; }
double Sampled_getValueAtSample (Sampled me, long isamp, long ilevel, int unit) { if (isamp < 1 || isamp > my nx) return NUMundefined; return my v_getValueAtSample (isamp, ilevel, unit); }
void PowerCepstrum_drawTiltLine (PowerCepstrum me, Graphics g, double qmin, double qmax, double dBminimum, double dBmaximum, double qstart, double qend, int lineType, int method) { Graphics_setInner (g); if (qmax <= qmin) { qmin = my xmin; qmax = my xmax; } if (dBminimum >= dBmaximum) { // autoscaling long imin, imax; if (! Matrix_getWindowSamplesX (me, qmin, qmax, & imin, & imax)) { return; } long numberOfPoints = imax - imin + 1; dBminimum = dBmaximum = my v_getValueAtSample (imin, 1, 0); for (long i = 2; i <= numberOfPoints; i++) { long isamp = imin + i - 1; double y = my v_getValueAtSample (isamp, 1, 0); dBmaximum = y > dBmaximum ? y : dBmaximum; dBminimum = y < dBminimum ? y : dBminimum; } } Graphics_setWindow (g, qmin, qmax, dBminimum, dBmaximum); qend = qend == 0 ? my xmax : qend; if (qend <= qstart) { qend = my xmax; qstart = my xmin; } qstart = qstart < my xmin ? my xmin : qstart; qend = qend > my xmax ? my xmax : qend; double a, intercept; PowerCepstrum_fitTiltLine (me, qstart, qend, &a, &intercept, lineType, method); /* * Don't draw part outside window */ double lineWidth = Graphics_inqLineWidth (g); Graphics_setLineWidth (g, 2); if (lineType == 2) { long n = 500; double dq = (qend - qstart) / (n + 1); double q1 = qstart; if (qstart <= 0) { qstart = 0.1 * dq; // some small offset to avoid log(0) n--; } autoNUMvector<double> y (1, n); for (long i = 1; i <= n; i++) { double q = q1 + (i - 1) * dq; y[i] = a * log (q) + intercept; } Graphics_function (g, y.peek(), 1, n, qstart, qend); } else { double y1 = a * qstart + intercept, y2 = a * qend + intercept; if (y1 >= dBminimum && y2 >= dBminimum) { Graphics_line (g, qstart, y1, qend, y2); } else if (y1 < dBminimum) { qstart = (dBminimum - intercept) / a; Graphics_line (g, qstart, dBminimum, qend, y2); } else if (y2 < dBminimum) { qend = (dBminimum - intercept) / a; Graphics_line (g, qstart, y1, qend, dBminimum); } else { // don't draw anything below lower limit? } } Graphics_setLineWidth (g, lineWidth); Graphics_unsetInner (g); }
static void Sampled_getSum2AndDefinitionRange (Sampled me, double xmin, double xmax, long ilevel, int unit, double mean, int interpolate, double *return_sum2, double *return_definitionRange) { /* This function computes the area under the linearly interpolated squared difference curve between xmin and xmax. Outside [x1-dx/2, xN+dx/2], the curve is undefined and neither times nor values are counted. In [x1-dx/2,x1] and [xN,xN+dx/2], the curve is linearly extrapolated. */ long imin, imax, isamp; double sum2 = 0.0, definitionRange = 0.0; Function_unidirectionalAutowindow (me, & xmin, & xmax); if (Function_intersectRangeWithDomain (me, & xmin, & xmax)) { if (interpolate) { if (Sampled_getWindowSamples (me, xmin, xmax, & imin, & imax)) { double leftEdge = my x1 - 0.5 * my dx, rightEdge = leftEdge + my nx * my dx; for (isamp = imin; isamp <= imax; isamp ++) { double value = my v_getValueAtSample (isamp, ilevel, unit); // a fast way to integrate a linearly interpolated curve; works everywhere except at the edges if (NUMdefined (value)) { value -= mean; value *= value; definitionRange += 1.0; sum2 += value; } } /* * Corrections within the first and last sampling intervals. */ if (xmin > leftEdge) { // otherwise, constant extrapolation over 0.5 sample is OK double phase = (my x1 + (imin - 1) * my dx - xmin) / my dx; // this fraction of sampling interval is still to be determined double rightValue = Sampled_getValueAtSample (me, imin, ilevel, unit); double leftValue = Sampled_getValueAtSample (me, imin - 1, ilevel, unit); if (NUMdefined (rightValue)) { rightValue -= mean; rightValue *= rightValue; definitionRange -= 0.5; // delete constant extrapolation over 0.5 sample sum2 -= 0.5 * rightValue; if (NUMdefined (leftValue)) { leftValue -= mean; leftValue *= leftValue; definitionRange += phase; // add current fraction sum2 += phase * (rightValue + 0.5 * phase * (leftValue - rightValue)); // interpolate to outside sample } else { if (phase > 0.5) phase = 0.5; definitionRange += phase; // add current fraction, but never more than 0.5 sum2 += phase * rightValue; } } else if (NUMdefined (leftValue) && phase > 0.5) { leftValue -= mean; leftValue *= leftValue; definitionRange += phase - 0.5; sum2 += (phase - 0.5) * leftValue; } } if (xmax < rightEdge) { // otherwise, constant extrapolation is OK double phase = (xmax - (my x1 + (imax - 1) * my dx)) / my dx; // this fraction of sampling interval is still to be determined double leftValue = Sampled_getValueAtSample (me, imax, ilevel, unit); double rightValue = Sampled_getValueAtSample (me, imax + 1, ilevel, unit); if (NUMdefined (leftValue)) { leftValue -= mean; leftValue *= leftValue; definitionRange -= 0.5; // delete constant extrapolation over 0.5 sample sum2 -= 0.5 * leftValue; if (NUMdefined (rightValue)) { rightValue -= mean; rightValue *= rightValue; definitionRange += phase; // add current fraction sum2 += phase * (leftValue + 0.5 * phase * (rightValue - leftValue)); // interpolate to outside sample } else { if (phase > 0.5) phase = 0.5; definitionRange += phase; // add current fraction, but never more than 0.5 sum2 += phase * leftValue; } } else if (NUMdefined (rightValue) && phase > 0.5) { rightValue -= mean; rightValue *= rightValue; definitionRange += phase - 0.5; sum2 += (phase - 0.5) * rightValue; } } } else { // no sample centres between xmin and xmax /* * Try to return the mean of the interpolated values at these two points. * Thus, a small (xmin, xmax) range gives the same value as the (xmin+xmax)/2 point. */ double leftValue = Sampled_getValueAtSample (me, imax, ilevel, unit); double rightValue = Sampled_getValueAtSample (me, imin, ilevel, unit); double phase1 = (xmin - (my x1 + (imax - 1) * my dx)) / my dx; double phase2 = (xmax - (my x1 + (imax - 1) * my dx)) / my dx; if (imin == imax + 1) { // not too far from sample definition region if (NUMdefined (leftValue)) { leftValue -= mean; leftValue *= leftValue; if (NUMdefined (rightValue)) { rightValue -= mean; rightValue *= rightValue; definitionRange += phase2 - phase1; sum2 += (phase2 - phase1) * (leftValue + 0.5 * (phase1 + phase2) * (rightValue - leftValue)); } else if (phase1 < 0.5) { if (phase2 > 0.5) phase2 = 0.5; definitionRange += phase2 - phase1; sum2 += (phase2 - phase1) * leftValue; } } else if (NUMdefined (rightValue) && phase2 > 0.5) { rightValue -= mean; rightValue *= rightValue; if (phase1 < 0.5) phase1 = 0.5; definitionRange += phase2 - phase1; sum2 += (phase2 - phase1) * rightValue; } } } } else { // no interpolation double rimin = Sampled_xToIndex (me, xmin), rimax = Sampled_xToIndex (me, xmax); if (rimax >= 0.5 && rimin < my nx + 0.5) { imin = rimin < 0.5 ? 0 : (long) floor (rimin + 0.5); imax = rimax >= my nx + 0.5 ? my nx + 1 : (long) floor (rimax + 0.5); for (isamp = imin + 1; isamp < imax; isamp ++) { double value = my v_getValueAtSample (isamp, ilevel, unit); if (NUMdefined (value)) { value -= mean; value *= value; definitionRange += 1.0; sum2 += value; } } if (imin == imax) { double value = my v_getValueAtSample (imin, ilevel, unit); if (NUMdefined (value)) { double phase = rimax - rimin; value -= mean; value *= value; definitionRange += phase; sum2 += phase * value; } } else { if (imin >= 1) { double value = my v_getValueAtSample (imin, ilevel, unit); if (NUMdefined (value)) { double phase = imin - rimin + 0.5; value -= mean; value *= value; definitionRange += phase; sum2 += phase * value; } } if (imax <= my nx) { double value = my v_getValueAtSample (imax, ilevel, unit); if (NUMdefined (value)) { double phase = rimax - imax + 0.5; value -= mean; value *= value; definitionRange += phase; sum2 += phase * value; } } } } } } if (return_sum2) *return_sum2 = sum2; if (return_definitionRange) *return_definitionRange = definitionRange; }