MatrixXd Spectrogram::make_spectrogram(VectorXd signal, qint32 window_size = 0) { if(window_size == 0) window_size = signal.rows()/4; Eigen::FFT<double> fft; MatrixXd tf_matrix = MatrixXd::Zero(signal.rows()/2, signal.rows()); for(qint32 translate = 0; translate < signal.rows(); translate++) { VectorXd envelope = gauss_window(signal.rows(), window_size, translate); VectorXd windowed_sig = VectorXd::Zero(signal.rows()); VectorXcd fft_win_sig = VectorXcd::Zero(signal.rows()); VectorXd real_coeffs = VectorXd::Zero(signal.rows()/2); for(qint32 sample = 0; sample < signal.rows(); sample++) windowed_sig[sample] = signal[sample] * envelope[sample]; fft.fwd(fft_win_sig, windowed_sig); for(qint32 i= 0; i<signal.rows()/2; i++) { qreal value = pow(abs(fft_win_sig[i]), 2.0); real_coeffs[i] = value; } tf_matrix.col(translate) = real_coeffs; } return tf_matrix; }
QPair<int,double> ConnectivityMeasures::calcCrossCorrelation(const RowVectorXd& vecFirst, const RowVectorXd& vecSecond) { Eigen::FFT<double> fft; int N = std::max(vecFirst.cols(), vecSecond.cols()); //Compute the FFT size as the "next power of 2" of the input vector's length (max) int b = ceil(log2(2.0 * N - 1)); int fftsize = pow(2,b); // int end = fftsize - 1; // int maxlag = N - 1; //Zero Padd RowVectorXd xCorrInputVecFirst = RowVectorXd::Zero(fftsize); xCorrInputVecFirst.head(vecFirst.cols()) = vecFirst; RowVectorXd xCorrInputVecSecond = RowVectorXd::Zero(fftsize); xCorrInputVecSecond.head(vecSecond.cols()) = vecSecond; //FFT for freq domain to both vectors RowVectorXcd freqvec; RowVectorXcd freqvec2; fft.fwd(freqvec, xCorrInputVecFirst); fft.fwd(freqvec2, xCorrInputVecSecond); //Create conjugate complex freqvec2.conjugate(); //Main step of cross corr for (int i = 0; i < fftsize; i++) { freqvec[i] = freqvec[i] * freqvec2[i]; } RowVectorXd result; fft.inv(result, freqvec); //Will get rid of extra zero padding RowVectorXd result2 = result;//.segment(maxlag, N); QPair<int,int> minMaxRange; int idx = 0; result2.minCoeff(&idx); minMaxRange.first = idx; result2.maxCoeff(&idx); minMaxRange.second = idx; // std::cout<<"result2(minMaxRange.first)"<<result2(minMaxRange.first)<<std::endl; // std::cout<<"result2(minMaxRange.second)"<<result2(minMaxRange.second)<<std::endl; // std::cout<<"b"<<b<<std::endl; // std::cout<<"fftsize"<<fftsize<<std::endl; // std::cout<<"end"<<end<<std::endl; // std::cout<<"maxlag"<<maxlag<<std::endl; //Return val int resultIndex = minMaxRange.second; double maxValue = result2(resultIndex); return QPair<int,double>(resultIndex, maxValue); }
RowVectorXd FilterData::applyFFTFilter(const RowVectorXd& data, bool keepOverhead, CompensateEdgeEffects compensateEdgeEffects) const { #ifdef EIGEN_FFTW_DEFAULT fftw_make_planner_thread_safe(); #endif if(data.cols()<m_dCoeffA.cols() && compensateEdgeEffects==MirrorData) { qDebug()<<QString("Error in FilterData: Number of filter taps(%1) bigger then data size(%2). Not enough data to perform mirroring!").arg(m_dCoeffA.cols()).arg(data.cols()); return data; } // std::cout<<"m_iFFTlength: "<<m_iFFTlength<<std::endl; // std::cout<<"2*m_dCoeffA.cols() + data.cols(): "<<2*m_dCoeffA.cols() + data.cols()<<std::endl; if(2*m_dCoeffA.cols() + data.cols()>m_iFFTlength) { qDebug()<<"Error in FilterData: Number of mirroring/zeropadding size plus data size is bigger then fft length!"; return data; } //Do zero padding or mirroring depending on user input RowVectorXd t_dataZeroPad = RowVectorXd::Zero(m_iFFTlength); switch(compensateEdgeEffects) { case MirrorData: t_dataZeroPad.head(m_dCoeffA.cols()) = data.head(m_dCoeffA.cols()).reverse(); //front t_dataZeroPad.segment(m_dCoeffA.cols(), data.cols()) = data; //middle t_dataZeroPad.tail(m_dCoeffA.cols()) = data.tail(m_dCoeffA.cols()).reverse(); //back break; case ZeroPad: t_dataZeroPad.head(data.cols()) = data; break; default: t_dataZeroPad.head(data.cols()) = data; break; } //generate fft object Eigen::FFT<double> fft; fft.SetFlag(fft.HalfSpectrum); //fft-transform data sequence RowVectorXcd t_freqData; fft.fwd(t_freqData,t_dataZeroPad); //perform frequency-domain filtering RowVectorXcd t_filteredFreq = m_dFFTCoeffA.array()*t_freqData.array(); //inverse-FFT RowVectorXd t_filteredTime; fft.inv(t_filteredTime,t_filteredFreq); //Return filtered data if(!keepOverhead) return t_filteredTime.segment(m_dCoeffA.cols()/2, data.cols()); return t_filteredTime.head(data.cols()+m_dCoeffA.cols()); }
Vector<Pointf> DataSource::FFT(Getdatafun getdata, double tSample, bool frequency, int type, bool window) { int numData = int(GetCount()); VectorXd timebuf(numData); int num = 0; for (int i = 0; i < numData; ++i) { double data = Membercall(getdata)(i); if (!IsNull(data)) { timebuf[i] = Membercall(getdata)(i); num++; } } Vector<Pointf> res; if (num < 3) return res; timebuf.resize(num); double windowSum = 0; if (window) { for (int i = 0; i < numData; ++i) { double windowDat = 0.54 - 0.46*cos(2*M_PI*i/numData); windowSum += windowDat; timebuf[i] *= windowDat; // Hamming window } } else windowSum = numData; VectorXcd freqbuf; try { Eigen::FFT<double> fft; fft.SetFlag(fft.HalfSpectrum); fft.fwd(freqbuf, timebuf); } catch(...) { return res; } if (frequency) { for (int i = 0; i < int(freqbuf.size()); ++i) { double xdata = i/(tSample*numData); switch (type) { case T_PHASE: res << Pointf(xdata, std::arg(freqbuf[i])); break; case T_FFT: res << Pointf(xdata, 2*std::abs(freqbuf[i])/windowSum); break; case T_PSD: res << Pointf(xdata, 2*sqr(std::abs(freqbuf[i]))/(windowSum/tSample)); } } } else { for (int i = int(freqbuf.size()) - 1; i > 0; --i) { double xdata = (tSample*numData)/i; switch (type) { case T_PHASE: res << Pointf(xdata, std::arg(freqbuf[i])); break; case T_FFT: res << Pointf(xdata, 2*std::abs(freqbuf[i])/windowSum); break; case T_PSD: res << Pointf(xdata, 2*sqr(std::abs(freqbuf[i]))/(windowSum/tSample)); } } } return res; }
void FilterData::fftTransformCoeffs() { #ifdef EIGEN_FFTW_DEFAULT fftw_make_planner_thread_safe(); #endif //zero-pad m_dCoeffA to m_iFFTlength RowVectorXd t_coeffAzeroPad = RowVectorXd::Zero(m_iFFTlength); t_coeffAzeroPad.head(m_dCoeffA.cols()) = m_dCoeffA; //generate fft object Eigen::FFT<double> fft; fft.SetFlag(fft.HalfSpectrum); //fft-transform filter coeffs m_dFFTCoeffA = RowVectorXcd::Zero(m_iFFTlength); fft.fwd(m_dFFTCoeffA,t_coeffAzeroPad); }
QList<QList<GaborAtom> > AdaptiveMp::matching_pursuit(MatrixXd signal, qint32 max_iterations, qreal epsilon, bool fix_phase = false, qint32 boost = 0, qint32 simplex_it = 1E3, qreal simplex_reflection = 1.0, qreal simplex_expansion = 0.2 , qreal simplex_contraction = 0.5, qreal simplex_full_contraction = 0.5, bool trial_separation = false) { //stop_running = false; std::cout << "\nAdaptive Matching Pursuit Algorithm started...\n"; max_it = max_iterations; Eigen::FFT<double> fft; MatrixXd residuum = signal; //residuum initialised with signal qint32 sample_count = signal.rows(); qint32 channel_count = signal.cols(); signal_energy = 0; qreal residuum_energy = 0; qreal energy_threshold = 0; //calculate signal_energy for(qint32 channel = 0; channel < channel_count; channel++) { for(qint32 sample = 0; sample < sample_count; sample++) signal_energy += (signal(sample, channel) * signal(sample, channel)); energy_threshold = 0.01 * epsilon * signal_energy; residuum_energy = signal_energy; } std::cout << "absolute energy of signal: " << residuum_energy << "\n"; while(it < max_iterations && (energy_threshold < residuum_energy) && sample_count > 1) { channel_count = channel_count * (boost / 100.0); //reducing the number of observed channels in the algorithm to increase speed performance if(boost == 0 || channel_count == 0) channel_count = 1; //variables for dyadic sampling qreal s = 1; //scale qint32 j = 1; VectorXd max_scalar_product = VectorXd::Zero(channel_count); //inner product for choosing the best matching atom qreal k = 0; //for modulation 2*pi*k/N qint32 p = floor(sample_count / 2); //translation GaborAtom *gabor_Atom = new GaborAtom(); gabor_Atom->sample_count = sample_count; gabor_Atom->energy = 0; qreal phase = 0; while(s < sample_count) { k = 0; //for modulation 2*pi*k/N p = floor(sample_count / 2); //translation VectorXd envelope = GaborAtom::gauss_function(sample_count, s, p); VectorXcd fft_envelope = RowVectorXcd::Zero(sample_count); fft.fwd(fft_envelope, envelope); while(k < sample_count/2) { p = floor(sample_count/2); VectorXcd modulation = modulation_function(sample_count, k); VectorXcd modulated_resid = VectorXcd::Zero(sample_count); VectorXcd fft_modulated_resid = VectorXcd::Zero(sample_count); VectorXcd fft_m_e_resid = VectorXcd::Zero(sample_count); VectorXd corr_coeffs = VectorXd::Zero(sample_count); //iteration for multichannel, depending on boost setting for(qint32 chn = 0; chn < channel_count; chn++) { qint32 max_index = 0; qreal maximum = 0; phase = 0; p = floor(sample_count/2);//here is difference to dr. gratkowski´s code (he didn´t reset parameter p) //complex correlation of signal and sinus-modulated gaussfunction for(qint32 l = 0; l< sample_count; l++) modulated_resid[l] = residuum(l, chn) * modulation[l]; fft.fwd(fft_modulated_resid, modulated_resid); for( qint32 m = 0; m < sample_count; m++) fft_m_e_resid[m] = fft_modulated_resid[m] * conj(fft_envelope[m]); fft.inv(corr_coeffs, fft_m_e_resid); maximum = corr_coeffs[0]; //find index of maximum correlation-coefficient to use in translation for(qint32 i = 1; i < corr_coeffs.rows(); i++) if(maximum < corr_coeffs[i]) { maximum = corr_coeffs[i]; max_index = i; } //adapting translation p to create atomtranslation correctly if(max_index >= p) p = max_index - p + 1; else p = max_index + p; VectorXd atom_parameters = calculate_atom(sample_count, s, p, k, chn, residuum, RETURNPARAMETERS, fix_phase); qreal temp_scalar_product = 0; if(trial_separation) temp_scalar_product = max_scalar_product[chn]; else temp_scalar_product = max_scalar_product[0]; if(abs(atom_parameters[4]) >= abs(temp_scalar_product)) { //set highest scalarproduct, in comparison to best matching atom gabor_Atom->scale = atom_parameters[0]; gabor_Atom->translation = atom_parameters[1]; gabor_Atom->modulation = atom_parameters[2]; gabor_Atom->phase = atom_parameters[3]; gabor_Atom->max_scalar_product = atom_parameters[4]; gabor_Atom->bm_channel = chn; if(trial_separation) { max_scalar_product[chn] = atom_parameters[4]; if(atoms_in_chns.length() < channel_count) atoms_in_chns.append(*gabor_Atom); else atoms_in_chns.replace(chn, *gabor_Atom); } else max_scalar_product[0] = atom_parameters[4]; } } k += pow(2.0,(-j))*sample_count/2; } j++; s = pow(2.0,j); } std::cout << "\n" << "===============" << " found parameters " << it + 1 << "===============" << ":\n\n"<< "scale: " << gabor_Atom->scale << " trans: " << gabor_Atom->translation << " modu: " << gabor_Atom->modulation << " phase: " << gabor_Atom->phase << " sclr_prdct: " << gabor_Atom->max_scalar_product << "\n"; //replace atoms with s==N and p = floor(N/2) by such atoms that do not have an envelope k = 0; s = sample_count; p = floor(sample_count / 2); j = floor(log10(sample_count)/log10(2));//log(sample_count) / log(2)); phase = 0; //iteration for multichannel, depending on boost setting for(qint32 chn = 0; chn < channel_count; chn++) { k = 0; while(k < sample_count / 2) { VectorXd parameters_no_envelope = calculate_atom(sample_count, s, p, k, chn, residuum, RETURNPARAMETERS, fix_phase); qreal temp_scalar_product = 0; if(trial_separation) temp_scalar_product = max_scalar_product[chn]; else temp_scalar_product = max_scalar_product[0]; if(abs(parameters_no_envelope[4]) > abs(temp_scalar_product)) { //set highest scalarproduct, in comparison to best matching atom gabor_Atom->scale = parameters_no_envelope[0]; gabor_Atom->translation = parameters_no_envelope[1]; gabor_Atom->modulation = parameters_no_envelope[2]; gabor_Atom->phase = parameters_no_envelope[3]; gabor_Atom->max_scalar_product = parameters_no_envelope[4]; gabor_Atom->bm_channel = chn; if(trial_separation) { max_scalar_product[chn] = parameters_no_envelope[4]; atoms_in_chns.replace(chn, *gabor_Atom); } else max_scalar_product[0] = parameters_no_envelope[4]; } k += pow(2.0,(-j))*sample_count/2; } } std::cout << " after comparison to NoEnvelope " << ":\n"<< "scale: " << gabor_Atom->scale << " trans: " << gabor_Atom->translation << " modu: " << gabor_Atom->modulation << " phase: " << gabor_Atom->phase << " sclr_prdct: " << gabor_Atom->max_scalar_product << "\n\n"; //simplexfunction to find minimum of target among parameters s, p, k if(trial_separation && simplex_it != 0) { for(qint32 chn = 0; chn < atoms_in_chns.length(); chn++) { *gabor_Atom = atoms_in_chns.at(chn); simplex_maximisation(simplex_it, simplex_reflection, simplex_expansion, simplex_contraction, simplex_full_contraction, gabor_Atom, max_scalar_product, sample_count, fix_phase, residuum, trial_separation, chn); } } else if(simplex_it != 0) simplex_maximisation(simplex_it, simplex_reflection, simplex_expansion, simplex_contraction, simplex_full_contraction, gabor_Atom, max_scalar_product, sample_count, fix_phase, residuum, trial_separation, gabor_Atom->bm_channel); //calc multichannel parameters phase and max_scalar_product channel_count = signal.cols(); VectorXd best_match = VectorXd::Zero(sample_count); for(qint32 chn = 0; chn < channel_count; chn++) { if(trial_separation) { *gabor_Atom = atoms_in_chns.at(chn); gabor_Atom->energy = 0; best_match = gabor_Atom->create_real(gabor_Atom->sample_count, gabor_Atom->scale, gabor_Atom->translation, gabor_Atom->modulation, gabor_Atom->phase); } else { VectorXd channel_params = calculate_atom(sample_count, gabor_Atom->scale, gabor_Atom->translation, gabor_Atom->modulation, chn, residuum, RETURNPARAMETERS, fix_phase); gabor_Atom->phase_list.append(channel_params[3]); gabor_Atom->max_scalar_list.append(channel_params[4]); best_match = gabor_Atom->create_real(gabor_Atom->sample_count, gabor_Atom->scale, gabor_Atom->translation, gabor_Atom->modulation, gabor_Atom->phase_list.at(chn)); } //substract best matching Atom from Residuum in each channel for(qint32 j = 0; j < gabor_Atom->sample_count; j++) { if(!trial_separation) { residuum(j,chn) -= gabor_Atom->max_scalar_list.at(chn) * best_match[j]; gabor_Atom->energy += pow(gabor_Atom->max_scalar_list.at(chn) * best_match[j], 2); } else { residuum(j,chn) -= gabor_Atom->max_scalar_product * best_match[j]; gabor_Atom->energy += pow(gabor_Atom->max_scalar_product * best_match[j], 2); } } if(trial_separation) { atoms_in_chns.replace(chn, *gabor_Atom); // change energy residuum_energy -= atoms_in_chns.at(chn).energy;// / channel_count;; current_energy += atoms_in_chns.at(chn).energy;// / channel_count;; } } if(!trial_separation) { residuum_energy -= gabor_Atom->energy; current_energy += gabor_Atom->energy; } else /*for(qint32 i = 0; i < atoms_in_chns.length(); i++) { residuum_energy -= atoms_in_chns.at(i).energy / channel_count; current_energy += atoms_in_chns.at(i).energy / channel_count; }*/ std::cout << "absolute energy of residue: " << residuum_energy << "\n"; if(!trial_separation) atoms_in_chns.append(*gabor_Atom); atom_list.append(atoms_in_chns); atoms_in_chns.clear(); delete gabor_Atom; it++; emit current_result(it, max_it, current_energy, signal_energy, residuum, atom_list, fix_dict_list); if( QThread::currentThread()->isInterruptionRequested()) { send_warning(10); break; } }//end iterations std::cout << "\nAdaptive Matching Pursuit Algorithm finished.\n"; emit finished_calc(); return atom_list; }
// calc scalarproduct of Atom and Signal FixDictAtom FixDictMp::correlation(Dictionary current_pdict, MatrixXd current_resid, qint32 boost) { qint32 channel_count = current_resid.cols() * (boost / 100.0); //reducing the number of observed channels in the algorithm to increase speed performance if(boost == 0 || channel_count == 0) channel_count = 1; Eigen::FFT<double> fft; std::ptrdiff_t max_index; VectorXcd fft_atom = VectorXcd::Zero(current_resid.rows()); FixDictAtom best_matching; qreal max_scalar_product = 0; for(qint32 i = 0; i < current_pdict.atoms.length(); i++) { VectorXd fitted_atom = VectorXd::Zero(current_resid.rows()); qint32 p = floor(current_resid.rows() / 2);//translation VectorXd resized_atom = VectorXd::Zero(current_resid.rows()); if(current_pdict.atoms.at(i).atom_samples.rows() > current_resid.rows()) for(qint32 k = 0; k < current_resid.rows(); k++) resized_atom[k] = current_pdict.atoms.at(i).atom_samples[k + floor(current_pdict.atoms.at(i).atom_samples.rows() / 2) - floor(current_resid.rows() / 2)]; else resized_atom = current_pdict.atoms.at(i).atom_samples; if(resized_atom.rows() < current_resid.rows()) for(qint32 k = 0; k < resized_atom.rows(); k++) fitted_atom[(k + p - floor(resized_atom.rows() / 2))] = resized_atom[k]; else fitted_atom = resized_atom; //normalization qreal norm = 0; norm = fitted_atom.norm(); if(norm != 0) fitted_atom /= norm; fft.fwd(fft_atom, fitted_atom); for(qint32 chn = 0; chn < channel_count; chn++) { p = floor(current_resid.rows() / 2);//translation VectorXd corr_coeffs = VectorXd::Zero(current_resid.rows()); VectorXcd fft_signal = VectorXcd::Zero(current_resid.rows()); VectorXcd fft_sig_atom = VectorXcd::Zero(current_resid.rows()); fft.fwd(fft_signal, current_resid.col(chn)); for( qint32 m = 0; m < current_resid.rows(); m++) fft_sig_atom[m] = fft_signal[m] * conj(fft_atom[m]); fft.inv(corr_coeffs, fft_sig_atom); //find index of maximum correlation-coefficient to use in translation max_scalar_product = corr_coeffs.maxCoeff(&max_index); if(i == 0) { best_matching = current_pdict.atoms.at(i); best_matching.max_scalar_product = max_scalar_product; //adapting translation p to create atomtranslation correctly if(max_index >= p && current_resid.rows() % (2) == 0) p = max_index - p; else if(max_index >= p && current_resid.rows() % (2) != 0) p = max_index - p - 1; else p = max_index + p; best_matching.translation = p; } else if(abs(max_scalar_product) > abs(best_matching.max_scalar_product)) { best_matching = current_pdict.atoms.at(i); best_matching.max_scalar_product = max_scalar_product; //adapting translation p to create atomtranslation correctly if(max_index >= p && current_resid.rows() % (2) == 0) p = max_index - p; else if(max_index >= p && current_resid.rows() % (2) != 0) p = max_index - p - 1; else p = max_index + p; best_matching.translation = p; } } } best_matching.atom_formula = current_pdict.atom_formula; best_matching.dict_source = current_pdict.source; best_matching.type = current_pdict.type; best_matching.sample_count = current_pdict.sample_count; return best_matching; }
CosineFilter::CosineFilter(int fftLength, float lowpass, float lowpass_width, float highpass, float highpass_width, double sFreq, TPassType type) { m_iFilterOrder = fftLength; int highpasss,lowpasss; int highpass_widths,lowpass_widths; int k,s,w; int resp_size = fftLength/2+1; //Take half because we are not interested in the conjugate complex part of the spectrum double pi4 = M_PI/4.0; float mult,add,c; RowVectorXcd filterFreqResp = RowVectorXcd::Ones(resp_size); //Transform frequencies into samples highpasss = ((resp_size-1)*highpass)/(0.5*sFreq); lowpasss = ((resp_size-1)*lowpass)/(0.5*sFreq); lowpass_widths = ((resp_size-1)*lowpass_width)/(0.5*sFreq); lowpass_widths = (lowpass_widths+1)/2; if (highpass_width > 0.0) { highpass_widths = ((resp_size-1)*highpass_width)/(0.5*sFreq); highpass_widths = (highpass_widths+1)/2; } else highpass_widths = 3; //Calculate filter freq response - use cosine //Build high pass filter if(type != LPF) { if (highpasss > highpass_widths + 1) { w = highpass_widths; mult = 1.0/w; add = 3.0; for (k = 0; k < highpasss-w+1; k++) filterFreqResp(k) = 0.0; for (k = -w+1, s = highpasss-w+1; k < w; k++, s++) { if (s >= 0 && s < resp_size) { c = cos(pi4*(k*mult+add)); filterFreqResp(s) = filterFreqResp(s).real()*c*c; } } } } //Build low pass filter if(type != HPF) { if (lowpass_widths > 0) { w = lowpass_widths; mult = 1.0/w; add = 1.0; for (k = -w+1, s = lowpasss-w+1; k < w; k++, s++) { if (s >= 0 && s < resp_size) { c = cos(pi4*(k*mult+add)); filterFreqResp(s) = filterFreqResp(s).real()*c*c; } } for (k = s; k < resp_size; k++) filterFreqResp(k) = 0.0; } else { for (k = lowpasss; k < resp_size; k++) filterFreqResp(k) = 0.0; } } m_dFFTCoeffA = filterFreqResp; //Generate windowed impulse response - invert fft coeeficients to time domain Eigen::FFT<double> fft; fft.SetFlag(fft.HalfSpectrum); //invert to time domain and fft.inv(m_dCoeffA, filterFreqResp);/* m_dCoeffA = m_dCoeffA.segment(0,1024).eval(); //window/zero-pad m_dCoeffA to m_iFFTlength RowVectorXd t_coeffAzeroPad = RowVectorXd::Zero(fftLength); t_coeffAzeroPad.head(m_dCoeffA.cols()) = m_dCoeffA; //fft-transform filter coeffs m_dFFTCoeffA = RowVectorXcd::Zero(fftLength); fft.fwd(m_dFFTCoeffA,t_coeffAzeroPad);*/ }