void QFilter::ProcessFilter(CPX &in, CPX &out, int bsize) { Q_UNUSED (bsize) memcpy(tmp0.data(), in.data(), sizeof(cpx) * m_size); ovlpfft->DoFFTWForward((cufftComplex *) tmp0.data(), (cufftComplex *) tmp1.data(), m_size * 2); DoConvolutionCPX(); ovlpfft->DoFFTWInverse((cufftComplex *) tmp0.data(), (cufftComplex *) tmp1.data(), m_size * 2); if (m_streamMode) { //Normalize(tmp1, tmp2, m_size * 2); // Overlap-Add for (int i = 0; i < m_size; i++) { out[i] = AddCPX(tmp1.at(i), ovlp.at(i)); ovlp[i] = tmp1.at(i + m_size); } //DoOverlapAddCPX(); //Normalize(tmp0, out, m_size * 2); //memcpy(out.data(), res.data(), sizeof(cpx) * m_size); } else { memcpy(out.data(), tmp1.data(), sizeof(cpx) * m_size); } }
int QFilter::ProcessAndDecimate(CPX &in, CPX &out, int bsize) { Q_UNUSED(in) Q_UNUSED(bsize) //memset(tmp0, 0, sizeof(CPX) * m_size * 2); //memset(tmp1, 0, sizeof(CPX) * m_size * 2); //memcpy(tmp0, in, sizeof(CPX) * m_size); tmp0.resize(m_size * 2); tmp1.resize(m_size * 2); tmp0.resize(m_size); ovlpfft->DoFFTWForward((cufftComplex *) tmp0.data(), (cufftComplex *) tmp1.data(), m_size * 2); DoConvolutionCPX(); ovlpfft->DoFFTWInverse((cufftComplex *) tmp0.data(), (cufftComplex *) tmp1.data(), m_size * 2); if (m_streamMode) { DoOverlapAddCPX(); for (int i = 0, j = 0; i < m_size; i+=2, j++) { *(out.data()+j) = *(tmp0.data()+i); } } else { for (int i = 0, j = 0; i < m_size; i+=2, j++) { *(out.data()+j) = *(tmp1.data()+i); } } return m_size/2; }
void IIRFilter::filter(CPX &c) { if (!ready) return; c.real(filter(c.real(),xv1,yv1)); c.imag(filter(c.imag(),xv2,yv2)); }
void QFilter::Normalize(CPX &in, CPX &out, int size) { float norm = 1.0f/size; for (int i = 0; i < size; i++) { out[i].re = in.at(i).re * norm; out[i].im = in.at(i).im * norm; } }
int C_FIR_filter::run (const CPX &in, CPX &out) { ibuffer[pointer] = in.real(); qbuffer[pointer] = in.imag(); counter++; if (counter == decimateratio) out = CPX ( mac(&ibuffer[pointer - length], ifilter, length), mac(&qbuffer[pointer - length], qfilter, length) ); pointer++; if (pointer == FIRBufferLen) { /// memmove is necessary if length >= FIRBufferLen/2 , theoretically possible. memmove (ibuffer, ibuffer + FIRBufferLen - length, length * sizeof (double) ); memmove (qbuffer, qbuffer + FIRBufferLen - length, length * sizeof (double) ); pointer = length; } if (counter == decimateratio) { counter = 0; return 1; } return 0; }
/* From Lynn 2nd ed pg 20 x[n] = sin(n * 2 * Pi * f / fs) f = desired frequency fs = sampling frequency or 1/sample rate We calculate 2Pif/fs once and save it as step so x[n] = sin(n * stepTone) ---------------- The number of samples per cycle is fixed, but the samples will be taken at different points in each cycle. We need to make sure that the spacing between each sample is consistent with the sample rate and frequency. A 10hz signal completes a full cycle ever 1/10 sec (1/Freg) At 48000 sps, this means we need 4800 samples for a complete cytle (sampleRate / freq) So a 24khz signal will have 2 samples per cycle (48000/24000), which is the Nyquist limit ----------------- */ void NCO::genSingle(CPX *_in, quint32 _numSamples, double _dbGain, bool _mix) { CPX cpx; for (quint32 i = 0; i < _numSamples; i++) { nextSample(cpx); cpx.real(cpx.real() * _dbGain); cpx.imag(cpx.imag() * _dbGain); if (_mix) { _in[i].real(_in[i].real() + cpx.real()); _in[i].imag(_in[i].imag() + cpx.imag()); } else { _in[i].real(cpx.real()); _in[i].imag(cpx.imag()); } } }
void QFilter::Decimate(CPX &in, CPX &out, int downrate) { int newsize = qRound((float) m_size/downrate); //memset(out, 0, newsize * sizeof(CPX)); //memset(tmp, 0, m_size * sizeof(CPX)); out.resize(newsize); tmp.resize(m_size); //memcpy(tmp, in, m_size * sizeof(CPX)); memcpy(tmp.data(), in.data(), m_size * sizeof(cpx)); for (int j = 0; j < newsize; j++) { for (int k = 0; k < downrate; k++) { //for (int k = 0; k < downrate - 1; k++) { if (j * downrate + k < m_size) { out[j].re += tmp.at(j * downrate + k).re; out[j].im += tmp.at(j * downrate + k).im; } } } }
void QFilter::ProcessForwardFilter(CPX &in, CPX &out, int bsize) { Q_UNUSED (bsize) //memcpy(tmp0, in, sizeof(CPX) * m_size); memcpy(tmp0.data(), in.data(), sizeof(cpx) * m_size); ovlpfft->DoFFTWForward((cufftComplex *) tmp0.data(), (cufftComplex *) tmp1.data(), m_size * 2); DoConvolutionCPX(); //ovlpfft->DoFFTWInverse(tmp0, tmp1, m_size * 2); if (m_streamMode) { DoOverlapAddCPX(); //memcpy(out, tmp0, sizeof(CPX) * m_size); memcpy(out.data(), tmp0.data(), sizeof(cpx) * m_size); } else { //memcpy(out, tmp1, sizeof(CPX) * m_size); memcpy(out.data(), tmp1.data(), sizeof(cpx) * m_size); } }
void QFFT::DoFFTWMagnForward(CPX &in, int size, float baseline, float correction, float *fbr) { memcpy(cpxbuf, in.data(), sizeof(cpx) * size); fftwf_execute(plan_fwd); for (int i = 0, j = size-1; i < size; i++, j--) { *(buf.data()+j) = *(cpx *)(cpxbuf+i); } for (int i = 0, j = half_sz; i < half_sz; i++, j++) { *(fbr+i) = 10.0 * log10(MagCPX(*(buf.data()+j)) + baseline) + correction; *(fbr+j) = 10.0 * log10(MagCPX(*(buf.data()+i)) + baseline) + correction; } }
void QDSPEngine::processDSP(CPX &in, CPX &out, int size) { m_mutex.lock(); switch (m_fftMultiplcator) { case 1: spectrum->ProcessSpectrum(in, size*2, 1); break; case 2: spectrum2->ProcessSpectrum(in, size*4, 3); break; case 4: spectrum4->ProcessSpectrum(in, size*8, 7); break; case 8: spectrum8->ProcessSpectrum(in, size*16, 15); break; } if (m_NcoFreq != 0) ProcessFrequencyShift(in, in, size); filter->ProcessFilter(in, tmp1CPX, size); signalmeter->ProcessBlock(tmp1CPX, size); wpagc->ProcessAGC(tmp1CPX, tmp2CPX, size); demod->ProcessBlock(tmp2CPX, out, size); //memcpy(out.data(), in.data(), size * sizeof(cpx)); //out = in; for (int i = 0; i < size; i++) { out[i] = ScaleCPX(out.at(i), m_volume); } m_mutex.unlock(); }
void QFFT::DoFFTWInverse(CPX &in, CPX &out, int size) { memcpy(cpxbuf, in.data(), sizeof(cpx) * size); fftwf_execute(plan_rev); memcpy(out.data(), cpxbuf, sizeof(cpx) * size); }
void QFFT::DoFFTWForward(CPX &in, CPX &out, int size) { memcpy(cpxbuf, in.data(), sizeof(cpx) * size); fftwf_execute(plan_fwd); memcpy(out.data(), cpxbuf, sizeof(cpx) * size); }
void QAGC::ProcessAGC(const CPX &in, CPX &out, int size) { if (m_agcMode == agcOFF) { for (int i = 0; i < size; i++) out[i] = ScaleCPX(in[i], m_gainFix); //memcpy(out.data(), in.data(), size * sizeof(cpx)); return; } unsigned int hangTime = (unsigned int)(m_samplerate * m_hangTime); unsigned int fastHangTime = (unsigned int)(m_samplerate * m_fastHangTime); float hangThresh = 0.0; if (m_hangThresh > 0.0) hangThresh = m_gainTop * m_hangThresh + m_gainBottom * (1.0 - m_hangThresh); for (int i = 0; i < m_size; i++) { G[m_index] = in.at(i); float tmp = 1.1 * SqrMagCPX(G.at(m_index)); if (tmp == 0.0) tmp = m_gainNow; else tmp = m_gainLimit / tmp; if (tmp < hangThresh) m_hangIndex = hangTime; if (tmp > m_gainNow) { if (m_hangIndex++ > (qint16)hangTime) m_gainNow = m_oneMDecay * m_gainNow + m_decay * qMin(m_gainTop, tmp); } else { m_hangIndex = 0; m_gainNow = m_oneMAttack * m_gainNow + m_attack * qMax(tmp, m_gainBottom); } tmp = 1.2 * SqrMagCPX(G[m_fastIndex]); if (tmp != 0.0) tmp = m_gainLimit / tmp; else tmp = m_gainFastNow; if (tmp > m_gainFastNow) { if (m_fastHang++ > (qint16)fastHangTime) m_gainFastNow = qMin(m_oneMFastDecay * m_gainFastNow + m_fastDecay * qMin(m_gainTop, tmp), m_gainTop); } else { m_fastHang = 0; m_gainFastNow = qMax(m_oneMFastAttack * m_gainFastNow + m_fastAttack * qMax(tmp, m_gainBottom), m_gainBottom); } m_gainFastNow = qMax(qMin(m_gainFastNow, m_gainTop), m_gainBottom); m_gainNow = qMax(qMin(m_gainNow, m_gainTop), m_gainBottom); out[i].re = Scale(G.at(m_sndex).re, qMin(m_gainFastNow, qMin(m_slope * m_gainNow, m_gainTop))); out[i].im = Scale(G.at(m_sndex).im, qMin(m_gainFastNow, qMin(m_slope * m_gainNow, m_gainTop))); m_index = (m_index + m_mask) & m_mask; m_sndex = (m_sndex + m_mask) & m_mask; m_fastIndex = (m_fastIndex + m_mask) & m_mask; } }