// calculate the power spectrum of the incoming signal stored in data field by estimating linear model and applying the lookupTable on the model public double[] estimatePowerSpectrum() { // init power spectrum double[] powerSpectrum = new double[numBins]; // if filter is constructed properly and data filed is filled with suitable data if (allowRun && data != null && linModel != null) { // init variables int counter = 0; // counter to fill powerspectrum array // multiply power by a factor of sqrt(2) to account for positive and negative frequencies. linModel = linModel * Math.Sqrt(2.0); // perform power spectrum estimation: cycle through bins, per bin calculate for each sample, ie frequencyresolution. (in BCI2000 this was transferspectrum.evaluate function, based loosely on function evlmem in Press et al.) for (int bin = 0; bin < numBins; ++bin) { // init powerSpectrum[bin] = 0.0; int evalInBin = (int)bins[bin, 2]; // cycle through samples per bin for (int eval = 0; eval < evalInBin; eval++) { // get power estimate for given frequency in lookupTable and store in power spectrum output array Complex valueComplex = linModel.evaluate(lookupTable[counter]); powerSpectrum[bin] += ((valueComplex.Real * valueComplex.Real) + (valueComplex.Imaginary * valueComplex.Imaginary)); // it's actually the squared magnitude rather than a norm counter++; } // normalize spectral power to frequency resolution powerSpectrum[bin] /= evalInBin; // divide by two and take square root to get amplitudes powerSpectrum[bin] = Math.Sqrt(powerSpectrum[bin] / 2); } // output power spectrum estimation //logger.Debug("Power spectrum estimation of data:"); //logger.Debug("Frequency bin \t Power"); //for (int i = 0; i < numBins; i++) { // double startBin = (firstBinCenter + (binWidth * i)) - (binWidth / 2); // double endBin = (firstBinCenter + (binWidth * i)) + (binWidth / 2); // logger.Debug("{0} - {1} Hz \t {2}", startBin, endBin, powerSpectrum[i]); //} } else { logger.Error("ARFilter is not constructed properly or input data is not suitable. Power spectrum can not be determined. See log files for more information."); } // return powerspectrum return(powerSpectrum); }
// create linear prediction model based on input signal (in 'Numerical Recipes'and in BCI2000 this function was called memCof) // NB. this alters the data contained in filter public void createLinPredModel() { if (allowRun && data != null) { // init variables const double eps = Double.Epsilon; // minimal value that can be expressed in double type, used to check if value is close to zero double[] wkm = new double[modelOrder + 1]; // double[] coeff = new double[modelOrder + 1]; // holds coefficients of to be created linear prediction model coeff[0] = 1.0; // first coefficient of model is always 1 int N = data.Length; // length of input signal double[] mWk1 = new double[N]; // double[] mWk2 = new double[N]; // Array.Copy(data, mWk1, N); // copy one array instead of assigning to prevent both variables pointing to same memory location (arrays are reference types) mWk2 = data; double meanPower = 0; // mean power of signal double q = 1.0; // // calculate mean power of input signal for (int t = 0; t < N; t++) { meanPower += (mWk1[t] * mWk1[t]); } // initialize numerator and denominator double num = 0.0; double den = meanPower * 2; // normalize mean power meanPower /= N; // calculate coefficients for (int k = 1; k <= modelOrder; ++k) { // reset numerator num = 0; // calculate numerator and denominator for (int t = 0; t < N - k; t++) { num += mWk1[t + 1] * mWk2[t]; } den = den * q - mWk1[0] * mWk1[0] - mWk2[N - k] * mWk2[N - k]; // if denominator is close to zero (ie smaller than epsilon), set num and den to .5 and 1 respectively if (den < eps) { num = 0.5; den = 1.0; } else { if (coeff[k] >= 1 || coeff[k] <= -1) { den = 0; for (int t = 0; t < N - k; t++) { den += mWk1[t + 1] * mWk1[t + 1] + mWk2[t] * mWk2[t]; } } } // set coefficient based on numerator and denominator coeff[k] = 2 * num / den; // update all coefficients q = 1.0 - coeff[k] * coeff[k]; meanPower *= q; for (int i = 1; i < k; ++i) { coeff[i] = wkm[i] - coeff[k] * wkm[k - i]; } // update wkm and mWk arrays if (k < modelOrder) { for (int i = 1; i <= k; ++i) { wkm[i] = coeff[i]; } for (int j = 0; j < N - k; ++j) { mWk1[j] = mWk1[j + 1] - wkm[k] * mWk2[j]; mWk2[j] = mWk2[j] - wkm[k] * mWk1[j + 1]; } } } // if mean power is below zero, set to zero (power can not be negative) if (meanPower < 0.0) { meanPower = 0.0; } // update coefficients for (int k = 1; k <= modelOrder; k++) { coeff[k] *= -1; } // output linearmodel linModel = new RationalPolynomial(new Polynomial(Math.Sqrt(meanPower)), new Polynomial(coeff)); } else { logger.Error("ARFilter is not constructed properly or input data is not suitable. Linear model can not be determined. See log files for more information."); } }