From a5e4e28f067d1d86a127146ede49ded4ed3b4a0d Mon Sep 17 00:00:00 2001
From: Rob van Nieuwpoort <nieuwpoort@astron.nl>
Date: Wed, 27 Jun 2012 10:00:34 +0000
Subject: [PATCH] Task #1611: working on online flagger that flags in frequency
 even if there are no channels

---
 .gitattributes                                |   2 +
 RTCP/CNProc/src/CMakeLists.txt                |   1 +
 RTCP/CNProc/src/CN_Processing.cc              |  26 ++
 RTCP/CNProc/src/CN_Processing.h               |   3 +
 RTCP/CNProc/src/InversePPF.cc                 |  17 +-
 RTCP/CNProc/src/InversePPF.h                  |   6 +-
 RTCP/CNProc/src/PPF.cc                        |   2 +-
 .../src/PreCorrelationNoChannelsFlagger.cc    | 270 ++++++++++++++++++
 .../src/PreCorrelationNoChannelsFlagger.h     |  63 ++++
 RTCP/CNProc/test/FlaggerTest.parset           |  14 +-
 RTCP/CNProc/test/RFI-test.parset              |   4 +-
 RTCP/CNProc/test/tInversePPF.cc               |   9 +-
 RTCP/Interface/include/Interface/Parset.h     |   6 +
 13 files changed, 397 insertions(+), 26 deletions(-)
 create mode 100644 RTCP/CNProc/src/PreCorrelationNoChannelsFlagger.cc
 create mode 100644 RTCP/CNProc/src/PreCorrelationNoChannelsFlagger.h

diff --git a/.gitattributes b/.gitattributes
index 86e1ca97270..5251397a6a0 100644
--- a/.gitattributes
+++ b/.gitattributes
@@ -3421,6 +3421,8 @@ RTCP/CNProc/src/PostCorrelationFlagger.cc -text
 RTCP/CNProc/src/PostCorrelationFlagger.h -text
 RTCP/CNProc/src/PreCorrelationFlagger.cc -text
 RTCP/CNProc/src/PreCorrelationFlagger.h -text
+RTCP/CNProc/src/PreCorrelationNoChannelsFlagger.cc -text
+RTCP/CNProc/src/PreCorrelationNoChannelsFlagger.h -text
 RTCP/CNProc/src/Ring.h -text
 RTCP/CNProc/src/Stokes.cc -text
 RTCP/CNProc/src/Stokes.h -text
diff --git a/RTCP/CNProc/src/CMakeLists.txt b/RTCP/CNProc/src/CMakeLists.txt
index 1dcdbfdc2da..3a868609839 100644
--- a/RTCP/CNProc/src/CMakeLists.txt
+++ b/RTCP/CNProc/src/CMakeLists.txt
@@ -29,6 +29,7 @@ set(cnproc_LIB_SRCS
   PPF.cc
   Flagger.cc
   PreCorrelationFlagger.cc
+  PreCorrelationNoChannelsFlagger.cc
   PostCorrelationFlagger.cc
   Stokes.cc)
 
diff --git a/RTCP/CNProc/src/CN_Processing.cc b/RTCP/CNProc/src/CN_Processing.cc
index 82d68a74877..b8cac2aa629 100644
--- a/RTCP/CNProc/src/CN_Processing.cc
+++ b/RTCP/CNProc/src/CN_Processing.cc
@@ -208,6 +208,12 @@ template <typename SAMPLE_TYPE> CN_Processing<SAMPLE_TYPE>::CN_Processing(const
         LOG_DEBUG_STR("Online PreCorrelation flagger enabled");
     }
 
+    if (parset.onlineFlagging() && parset.onlinePreCorrelationNoChannelsFlagging()) {
+      itsPreCorrelationNoChannelsFlagger = new PreCorrelationNoChannelsFlagger(parset, itsNrStations, itsNrSubbands, itsNrChannels, itsNrSamplesPerIntegration);
+      if (LOG_CONDITION)
+        LOG_DEBUG_STR("Online PreCorrelation no channels flagger enabled");
+    }
+
     if (parset.outputCorrelatedData()) {
       itsCorrelator	      = new Correlator(itsBeamFormer->getStationMapping(), itsNrChannels, itsNrSamplesPerIntegration);
       itsCorrelatedData       = (CorrelatedData*)newStreamableData(parset, CORRELATED_DATA, -1, itsBigAllocator);
@@ -726,6 +732,23 @@ template <typename SAMPLE_TYPE> void CN_Processing<SAMPLE_TYPE>::preCorrelationF
 }
 
 
+template <typename SAMPLE_TYPE> void CN_Processing<SAMPLE_TYPE>::preCorrelationNoChannelsFlagging()
+{
+#if defined HAVE_MPI
+  if (LOG_CONDITION)
+    LOG_DEBUG_STR(itsLogPrefix << "Start pre correlation no channels flagger at t = " << blockAge());
+#endif // HAVE_MPI
+
+  static NSTimer timer("pre correlation no channels flagger", true, true);
+
+  timer.start();
+  computeTimer.start();
+  itsPreCorrelationNoChannelsFlagger->flag(itsFilteredData, *itsCurrentSubband);
+  computeTimer.stop();
+  timer.stop();
+}
+
+
 template <typename SAMPLE_TYPE> void CN_Processing<SAMPLE_TYPE>::mergeStations()
 {
 #if defined HAVE_MPI
@@ -930,6 +953,9 @@ template <typename SAMPLE_TYPE> void CN_Processing<SAMPLE_TYPE>::process(unsigne
     if (itsPPF != 0)
       filter();
 
+    if (itsPreCorrelationNoChannelsFlagger != 0)
+      preCorrelationNoChannelsFlagging();
+
     if (itsPreCorrelationFlagger != 0)
       preCorrelationFlagging();
 
diff --git a/RTCP/CNProc/src/CN_Processing.h b/RTCP/CNProc/src/CN_Processing.h
index 3ab1214816b..a3f10c2a141 100644
--- a/RTCP/CNProc/src/CN_Processing.h
+++ b/RTCP/CNProc/src/CN_Processing.h
@@ -47,6 +47,7 @@
 #include <LocationInfo.h>
 #include <PPF.h>
 #include <PreCorrelationFlagger.h>
+#include <PreCorrelationNoChannelsFlagger.h>
 #include <PostCorrelationFlagger.h>
 #include <Ring.h>
 #include <Stokes.h>
@@ -86,6 +87,7 @@ template <typename SAMPLE_TYPE> class CN_Processing : public CN_Processing_Base
     int			transposeBeams(unsigned block);
     void		filter();
     void		dedisperseAfterBeamForming(unsigned beam, double dm);
+    void		preCorrelationNoChannelsFlagging();
     void		preCorrelationFlagging();
     void		mergeStations();
     void		formBeams(unsigned sap, unsigned firstBeam, unsigned nrBeams);
@@ -168,6 +170,7 @@ template <typename SAMPLE_TYPE> class CN_Processing : public CN_Processing_Base
     SmartPtr<DedispersionAfterBeamForming>	itsDedispersionAfterBeamForming;
     SmartPtr<DedispersionBeforeBeamForming>	itsDedispersionBeforeBeamForming;
     SmartPtr<PreCorrelationFlagger>		itsPreCorrelationFlagger;
+    SmartPtr<PreCorrelationNoChannelsFlagger>	itsPreCorrelationNoChannelsFlagger;
     SmartPtr<PostCorrelationFlagger>		itsPostCorrelationFlagger;
     SmartPtr<Trigger>				itsTrigger;
 };
diff --git a/RTCP/CNProc/src/InversePPF.cc b/RTCP/CNProc/src/InversePPF.cc
index 49c5d7c1c53..5bf844a3d33 100644
--- a/RTCP/CNProc/src/InversePPF.cc
+++ b/RTCP/CNProc/src/InversePPF.cc
@@ -76,18 +76,13 @@ void InversePPF::destroyFFT() {
 #endif
 }
 
-// Reads itsFftOutData, writes to invertedFilteredData.
-void InversePPF::performFilter(InverseFilteredData& invertedFilteredData, unsigned time, unsigned minorTime) {
-  float sample = itsFftOutData[minorTime];
-  float result = itsFIRs[minorTime].processNextSample(sample);
-  invertedFilteredData.samples[time * itsOnStationFilterSize + minorTime] = result;
-}
-
 // Goes from tansposedBeamFormedData to itsFftInData.
 void InversePPF::createFFTInput(const TransposedBeamFormedData& transposedBeamFormedData, unsigned time) {
   fftInTimer.start();
 
   // First set the unselected subbands to zero.
+  // We have to do this every time, since the input is destroyed by the FFT.
+  // However, the time this takes is very small compared to the time to fill in the real data below.
   memset(itsFftInData, 0, itsOnStationFilterSize * sizeof(float));
 
   // Fill input buffer, using "half complex" format.
@@ -98,7 +93,7 @@ void InversePPF::createFFTInput(const TransposedBeamFormedData& transposedBeamFo
     fcomplex sample = transposedBeamFormedData.samples[sb][0 /* channel, but there only is 1 now */][time];
 
     itsFftInData[sb] = real(sample);
-    itsFftInData[itsOnStationFilterSize - sb] = imag(sample);
+    itsFftInData[itsOnStationFilterSize - sb - 1] = imag(sample);
   }
 
   fftInTimer.stop();
@@ -119,11 +114,15 @@ void InversePPF::performInverseFFT() {
   fftTimer.stop();
 }
 
+// Reads itsFftOutData, writes to invertedFilteredData.
 void InversePPF::performFiltering(InverseFilteredData& invertedFilteredData, unsigned time) {
   firTimer.start();
 
+  unsigned index = time * itsOnStationFilterSize;
   for (unsigned minorTime = 0; minorTime < itsOnStationFilterSize; minorTime++) {
-    performFilter(invertedFilteredData, time, minorTime);
+    const float sample = itsFftOutData[minorTime];
+    const float result = itsFIRs[minorTime].processNextSample(sample);
+    invertedFilteredData.samples[index++] = result;
   }
 
   firTimer.stop();
diff --git a/RTCP/CNProc/src/InversePPF.h b/RTCP/CNProc/src/InversePPF.h
index 00b67065dda..db9ac15e343 100644
--- a/RTCP/CNProc/src/InversePPF.h
+++ b/RTCP/CNProc/src/InversePPF.h
@@ -30,7 +30,7 @@
  * Input must be in "half complex" format.
 
  This consists of the non-redundant half of the complex output for a 1d real-input DFT of size n,
- stored as a sequence of n  real numbers (double) in the format:
+ stored as a sequence of n real numbers (double) in the format:
 
  r0, r1, r2, ..., rn/2, i(n+1)/2-1, ..., i2, i1
 
@@ -105,7 +105,6 @@ private:
 
   void initFFT();
   void destroyFFT();
-  void performFilter(InverseFilteredData& invertedFilteredData, unsigned time, unsigned minorTime);
   void createFFTInput(const TransposedBeamFormedData& transposedBeamFormedData, unsigned time);
   void performInverseFFT();
   void performFiltering(InverseFilteredData& invertedFilteredData, unsigned time);
@@ -127,10 +126,9 @@ private:
   unsigned itsNrSubbands;
   unsigned itsNrTaps; // 16
   unsigned itsNrSamplesPerIntegration;
-  unsigned itsOnStationFilterSize; // 1204
+  unsigned itsOnStationFilterSize; // 1024
 
   bool itsVerbose;
-
 };
 
 } // namespace RTCP
diff --git a/RTCP/CNProc/src/PPF.cc b/RTCP/CNProc/src/PPF.cc
index 2500173d38d..60054befef8 100644
--- a/RTCP/CNProc/src/PPF.cc
+++ b/RTCP/CNProc/src/PPF.cc
@@ -385,7 +385,7 @@ template <typename SAMPLE_TYPE> void PPF<SAMPLE_TYPE>::bypass(unsigned stat, dou
 #if defined PPF_C_IMPLEMENTATION
   for (unsigned time = 0; time < itsNrSamplesPerIntegration; time ++) {
     for (unsigned pol = 0; pol < NR_POLARIZATIONS; pol ++) {
-      if (filteredData->flags[1][stat].test(time)) {
+      if ((itsNrChannels > 1 && filteredData->flags[1][stat].test(time)) || (itsNrChannels == 1 && filteredData->flags[0][stat].test(time))) {
 	filteredData->samples[0][stat][time][pol] = makefcomplex(0, 0);
       } else {
 	SAMPLE_TYPE currSample = transposedData->samples[stat][time + alignmentShift][pol];
diff --git a/RTCP/CNProc/src/PreCorrelationNoChannelsFlagger.cc b/RTCP/CNProc/src/PreCorrelationNoChannelsFlagger.cc
new file mode 100644
index 00000000000..98124e03c0f
--- /dev/null
+++ b/RTCP/CNProc/src/PreCorrelationNoChannelsFlagger.cc
@@ -0,0 +1,270 @@
+//# Always #include <lofar_config.h> first!
+#include <lofar_config.h>
+
+#include <Common/Timer.h>
+
+#include <PreCorrelationNoChannelsFlagger.h>
+
+// history is kept per subband, as we can get different subbands over time on this compute node.
+// Always flag poth polarizations as a unit.
+
+// FFT followed by an inverse FFT multiplies all samples by N. Thus, we have to divide by N after we are done.
+
+
+/*
+   First, we flag in the time direction, while integrating to imrove signal-to-noise.
+   This was empirically verified to work much better than flagging on the raw data.
+   We can then replace flagged samples with 0s or mean/ median.
+
+   Two options for frequency flagging:
+
+   - integrate until we have FFTSize samples, so we improve signal-to-noise
+   - do FFT
+   - flag, keep frequency ranges that are flagged.
+   - move over the raw data at full time resolution; FFT, replace with 0, mean or median; inverse FFT
+ 
+   or
+
+   - do not integrate, but move over raw data in full time resolution
+   - do fft
+   - flag on this data only
+   - replace with 0, mean or median
+   - inverse fft
+
+   In all these cases replacing with median would be best, but expensive.
+   Also, which median? compute it once on the raw data for all samples, or once per fft?
+
+   Option 1 is cheaper, since we flag only once, instead of integrationFactor times.
+   It may also be better due to the improved signal-to-noise ratio.
+*/
+
+namespace LOFAR {
+namespace RTCP {
+
+PreCorrelationNoChannelsFlagger::PreCorrelationNoChannelsFlagger(const Parset& parset, const unsigned nrStations, const unsigned nrSubbands, const unsigned nrChannels, 
+					     const unsigned nrSamplesPerIntegration, const float cutoffThreshold)
+:
+  Flagger(parset, nrStations, nrSubbands, nrChannels, cutoffThreshold, /*baseSentitivity*/ 1.0f, 
+	  getFlaggerStatisticsType(parset.onlinePreCorrelationFlaggingStatisticsType(getFlaggerStatisticsTypeString(FLAGGER_STATISTICS_WINSORIZED)))),
+  itsNrSamplesPerIntegration(nrSamplesPerIntegration)
+{
+  assert(itsNrSamplesPerIntegration % itsFFTSize == 0);
+  assert(nrChannels == 1);
+
+  itsIntegrationFactor = itsNrSamplesPerIntegration / itsFFTSize;
+
+  itsSamples.resize(itsFFTSize);
+  itsPowers.resize(itsFFTSize);
+  itsFlagsTime.resize(itsFFTSize);
+  itsFlagsFrequency.resize(itsFFTSize);
+  itsFFTBuffer.resize(itsFFTSize);
+}
+
+
+void PreCorrelationNoChannelsFlagger::initFFT()
+{
+#if defined HAVE_FFTW3
+  itsFFTWforwardPlan =  fftwf_plan_dft_1d(itsFFTSize, (fftwf_complex *) &itsSamples[0], (fftwf_complex *) &itsFFTBuffer[0], FFTW_FORWARD, FFTW_MEASURE);
+  itsFFTWbackwardPlan = fftwf_plan_dft_1d(itsFFTSize, (fftwf_complex *) &itsFFTBuffer[0], (fftwf_complex *) &itsSamples[0], FFTW_FORWARD, FFTW_MEASURE);
+#elif defined HAVE_FFTW2
+#error TODO // @@@ TODO
+//  itsFFTWforwardPlan  = fftw_create_plan_specific(itsFFTsize, FFTW_FORWARD,  FFTW_ESTIMATE | FFTW_USE_WISDOM, (fftw_complex *) &itsSamples[0], 2, (fftw_complex *) &itsFFTBuffer[0], 1);
+//  itsFFTWbackwardPlan = fftw_create_plan_specific(itsFFTsize, FFTW_BACKWARD, FFTW_ESTIMATE | FFTW_USE_WISDOM, (fftw_complex *) &itsFFTBuffer[0], 1, (fftw_complex *) &itsSamples[0], 2);
+#endif
+}
+
+
+void PreCorrelationNoChannelsFlagger::forwardFFT()
+{
+#if defined HAVE_FFTW3
+  fftwf_execute(itsFFTWforwardPlan);
+#elif defined HAVE_FFTW2
+  fftw(itsFFTWforwardPlan, 2, (fftw_complex *) data, 2, 1, (fftw_complex *) &itsFFTedBuffer[0][0], 1, itsFFTsize);
+#endif
+}
+
+
+void PreCorrelationNoChannelsFlagger::backwardFFT()
+{
+#if defined HAVE_FFTW3
+  fftwf_execute(itsFFTWbackwardPlan);
+#elif defined HAVE_FFTW2
+  fftw(itsFFTWbackwardPlan, 2, (fftw_complex *) &itsFFTedBuffer[0][0], 1, itsFFTsize, (fftw_complex *) data, 2, 1);
+#endif
+}
+
+
+void PreCorrelationNoChannelsFlagger::flag(FilteredData* filteredData, unsigned currentSubband)
+{
+  NSTimer flaggerTimer("RFI noChannels flagger total", true, true);
+  NSTimer flaggerTimeTimer("RFI noChannels time flagger", true, true);
+  NSTimer flaggerFrequencyTimer("RFI noChannels time flagger", true, true);
+
+  flaggerTimer.start();
+
+  for(unsigned station = 0; station < itsNrStations; station++) {
+    initFlagsTime(station, filteredData); // copy flags to my local format
+    filteredData->resetFlags();           // Wipe original flags
+
+    // init frequency flags
+    for (unsigned i = 0; i < itsFFTSize; i++) {
+      itsFlagsFrequency[i] = false;
+    }
+
+    for (unsigned pol = 0; pol < NR_POLARIZATIONS; pol++) {
+      integrateAndCalculatePowers(station, pol, filteredData);
+
+      flaggerTimeTimer.start();
+      sumThresholdFlagger1D(itsPowers, itsFlagsTime, itsBaseSensitivity); // flag in time direction
+      flaggerTimeTimer.stop();
+
+      flaggerFrequencyTimer.start();
+      forwardFFT();
+
+      for (unsigned i = 0; i < itsFFTSize; i++) { // compute powers from FFT-ed data
+	fcomplex sample = itsFFTBuffer[i];
+	float power = real(sample) * real(sample) + imag(sample) * imag(sample);
+	itsPowers[i] = power;
+      }
+
+      sumThresholdFlagger1D(itsPowers, itsFlagsFrequency, itsBaseSensitivity); // flag in freq direction
+      flaggerFrequencyTimer.stop();
+    }
+
+    applyFlagsTime(station, filteredData); // copy flags from my original format into FilteredData again.
+    applyFlagsFrequency(station, filteredData); // do forward FFT; fix samples; backward FFT on the original samples in full resolution
+  }
+
+  flaggerTimer.stop();
+}
+
+
+void PreCorrelationNoChannelsFlagger::integrateAndCalculatePowers(unsigned station, unsigned pol, FilteredData* filteredData)
+{
+  for(unsigned i=0; i<itsFFTSize; i++) {
+    itsSamples[i] = makefcomplex(0, 0);
+  }
+ 
+  for(unsigned t=0; t<itsNrSamplesPerIntegration; t++) {
+    itsSamples[t/itsIntegrationFactor] += filteredData->samples[0][station][t][pol];
+  }
+
+  for (unsigned i = 0; i < itsFFTSize; i++) {
+    fcomplex sample = itsSamples[i];
+    float power = real(sample) * real(sample) + imag(sample) * imag(sample);
+    itsPowers[i] = power;
+  }
+}
+
+
+void PreCorrelationNoChannelsFlagger::initFlagsTime(unsigned station, FilteredData* filteredData)
+{
+  for (unsigned i = 0; i < itsFFTSize; i++) {
+    itsFlagsTime[i] = false;
+  }
+
+  // Use the original flags to initialize the flags.
+  // This could be done much faster by just iterating over the windows in the sparse flags set. // TODO
+  for (unsigned time = 0; time < itsNrSamplesPerIntegration; time++) {
+    if(filteredData->flags[0][station].test(time)) {
+      itsFlagsTime[time/itsIntegrationFactor] = true;
+    }
+  }
+}
+
+
+void PreCorrelationNoChannelsFlagger::applyFlagsTime(unsigned station, FilteredData* filteredData)
+{
+  const fcomplex zero = makefcomplex(0, 0);
+
+  for (unsigned i = 0; i < itsFFTSize; i++) {
+    if(itsFlagsTime[i]) {
+      unsigned startIndex = i * itsIntegrationFactor;
+	
+      filteredData->flags[0][station].include(startIndex, startIndex+itsIntegrationFactor);
+
+      for (unsigned time = 0; time < itsIntegrationFactor; time++) {
+	unsigned globalIndex = i * itsIntegrationFactor + time;
+	for (unsigned pol = 0; pol < NR_POLARIZATIONS; pol++) {
+	  filteredData->samples[0][station][globalIndex][pol] = zero;
+	}
+      }
+    }
+  }
+}
+
+// Do forward FFT; fix samples; backward FFT on the original samples in full resolution. Flags are already set in itsFlagsFrequency.
+// FFT followed by an inverse FFT multiplies all samples by N. Thus, we have to divide by N after we are done.
+void PreCorrelationNoChannelsFlagger::applyFlagsFrequency(unsigned station, FilteredData* filteredData)
+{
+  const fcomplex zero = makefcomplex(0, 0);
+
+  for (unsigned time = 0; time < itsIntegrationFactor; time++) {
+    unsigned startIndex = time * itsFFTSize;
+    for (unsigned pol = 0; pol < NR_POLARIZATIONS; pol++) {
+      for(unsigned minorTime=0; minorTime < itsFFTSize; minorTime++) {
+	itsSamples[minorTime] = filteredData->samples[0][station][startIndex+minorTime][pol];
+      }
+      forwardFFT();
+      for(unsigned minorTime=0; minorTime < itsFFTSize; minorTime++) {
+	if(itsFlagsFrequency[minorTime]) {
+	  itsFFTBuffer[minorTime] = zero;
+	}
+      }
+      backwardFFT();
+      for(unsigned minorTime=0; minorTime < itsFFTSize; minorTime++) {
+	filteredData->samples[0][station][startIndex+minorTime][pol] = makefcomplex(real(itsSamples[minorTime]) / itsFFTSize, imag(itsSamples[minorTime]) / itsFFTSize);
+      }
+    }
+  }
+}
+
+fcomplex PreCorrelationNoChannelsFlagger::computeMedianSample(unsigned station, FilteredData* filteredData)
+{
+  // we have to copy the vector, nth_element changes the ordering, also, we want the median of both polarizations
+  std::vector<fcomplex> copy(itsNrSamplesPerIntegration * NR_POLARIZATIONS);
+  memcpy(copy.data(), &filteredData->samples[0][station][0][0], itsNrSamplesPerIntegration * NR_POLARIZATIONS * sizeof(fcomplex));
+
+  std::vector<float> powers(itsNrSamplesPerIntegration * NR_POLARIZATIONS);
+  for(unsigned i=0; i<itsNrSamplesPerIntegration * NR_POLARIZATIONS; i++) {
+    fcomplex sample = copy[i];
+    powers[i] = real(sample) * real(sample) + imag(sample) * imag(sample);
+  }
+
+  // calculate median, expensive, but nth_element is guaranteed to be O(n)
+  std::vector<float>::iterator it = powers.begin() + (powers.size() / 2);
+  std::nth_element(powers.begin(), it, powers.end());
+
+  float median = *it;
+  
+  for(unsigned i=0; i<itsNrSamplesPerIntegration * NR_POLARIZATIONS; i++) {
+    if(powers[i] == median) {
+      return filteredData->samples[0][station][i/NR_POLARIZATIONS][i%NR_POLARIZATIONS];
+    }
+  }
+
+  return makefcomplex(0, 0);
+}
+
+
+PreCorrelationNoChannelsFlagger::~PreCorrelationNoChannelsFlagger()
+{
+#if defined HAVE_FFTW3
+  if(itsFFTWforwardPlan != 0) {
+    fftwf_destroy_plan(itsFFTWforwardPlan);
+  }
+  if(itsFFTWbackwardPlan != 0) {
+    fftwf_destroy_plan(itsFFTWbackwardPlan);
+  }
+#else
+  if(itsFFTWforwardPlan != 0) {
+    fftw_destroy_plan(itsFFTWforwardPlan);
+  }
+  if(itsFFTWbackwardPlan != 0) {
+    fftw_destroy_plan(itsFFTWbackwardPlan);
+  }
+#endif
+}
+
+} // namespace RTCP
+} // namespace LOFAR
diff --git a/RTCP/CNProc/src/PreCorrelationNoChannelsFlagger.h b/RTCP/CNProc/src/PreCorrelationNoChannelsFlagger.h
new file mode 100644
index 00000000000..b1014915863
--- /dev/null
+++ b/RTCP/CNProc/src/PreCorrelationNoChannelsFlagger.h
@@ -0,0 +1,63 @@
+#ifndef LOFAR_CNPROC_PRE_CORRELATION_NO_CHANNELS_FLAGGER_H
+#define LOFAR_CNPROC_PRE_CORRELATION_NO_CHANNELS_FLAGGER_H
+
+#include <Flagger.h>
+#include <Interface/FilteredData.h>
+
+#if defined HAVE_FFTW3
+#include <fftw3.h>
+#elif defined HAVE_FFTW2
+#include <fftw.h>
+#else
+#error Should have FFTW3 or FFTW2 installed
+#endif
+
+namespace LOFAR {
+namespace RTCP {
+
+// integrate in time untill we have itsFFTSize elements.
+// Flag on that in time direction.
+// Next, do FFT, flag in frequency direction, replace samples with median, inverseFFT
+class PreCorrelationNoChannelsFlagger : public Flagger {
+  public:
+  PreCorrelationNoChannelsFlagger(const Parset& parset, const unsigned nrStations, const unsigned nrSubbands, const unsigned nrChannels, const unsigned nrSamplesPerIntegration, float cutoffThreshold = 7.0f);
+
+  void flag(FilteredData* filteredData, unsigned currentSubband);
+
+  ~PreCorrelationNoChannelsFlagger();
+
+  private:
+
+  static const unsigned itsFFTSize = 256;
+
+  const unsigned itsNrSamplesPerIntegration;
+  unsigned itsIntegrationFactor; 
+
+  void integrateAndCalculatePowers(unsigned station, unsigned pol, FilteredData* filteredData);
+  void initFlagsTime(unsigned station, FilteredData* filteredData);
+  void applyFlagsTime(unsigned station, FilteredData* filteredData);
+  void applyFlagsFrequency(unsigned station, FilteredData* filteredData);
+  fcomplex computeMedianSample(unsigned station, FilteredData* filteredData);
+
+  void initFFT();
+  void forwardFFT();
+  void backwardFFT();
+
+  vector<fcomplex> itsSamples; // [itsFFTSize]
+  vector<float> itsPowers; // [itsFFTSize]
+  vector<bool> itsFlagsTime;   // [itsFFTSize]
+  vector<bool> itsFlagsFrequency;   // [itsFFTSize]
+  vector<fcomplex> itsFFTBuffer; // [itsFFTSize]
+
+#if defined HAVE_FFTW3
+  fftwf_plan itsFFTWforwardPlan, itsFFTWbackwardPlan;
+#elif defined HAVE_FFTW2
+  fftw_plan  itsFFTWforwardPlan, itsFFTWbackwardPlan;
+#endif
+
+};
+
+} // namespace RTCP
+} // namespace LOFAR
+
+#endif // LOFAR_CNPROC_PRE_CORRELATION_NO_CHANNELS_FLAGGER_H
diff --git a/RTCP/CNProc/test/FlaggerTest.parset b/RTCP/CNProc/test/FlaggerTest.parset
index a8aebb97fb7..9e5debbabf9 100644
--- a/RTCP/CNProc/test/FlaggerTest.parset
+++ b/RTCP/CNProc/test/FlaggerTest.parset
@@ -1,4 +1,4 @@
-OLAP.CNProc.integrationSteps		 = 12208
+OLAP.CNProc.integrationSteps		 = 12288
 OLAP.CNProc.phaseOnePsets		 = [0..4]
 OLAP.CNProc.phaseTwoPsets		 = [0..4]
 OLAP.CNProc.phaseThreePsets		 = [0..4]
@@ -9,11 +9,13 @@ OLAP.CNProc.tabList			 = []
 
 OLAP.CNProc.onlineFlagging               = F # enable or disable all online flagging
 
-OLAP.CNProc.onlinePreCorrelationFlagging = T
+OLAP.CNProc.onlinePreCorrelationNoChannelsFlagging = F
+
+OLAP.CNProc.onlinePreCorrelationFlagging = F
 #OLAP.CNProc.onlinePreCorrelationFlaggingType = INTEGRATED_THRESHOLD
 OLAP.CNProc.onlinePreCorrelationFlaggingType = INTEGRATED_SUM_THRESHOLD_2D_WITH_HISTORY # THRESHOLD, INTEGRATED_THRESHOLD, INTEGRATED_THRESHOLD_2D, SUM_THRESHOLD, INTEGRATED_SUM_THRESHOLD, INTEGRATED_SUM_THRESHOLD_WITH_HISTORY, INTEGRATED_SMOOTHED_SUM_THRESHOLD, INTEGRATED_SMOOTHED_SUM_THRESHOLD_WITH_HISTORY, INTEGRATED_SUM_THRESHOLD_2D, INTEGRATED_SUM_THRESHOLD_2D_WITH_HISTORY
 OLAP.CNProc.onlinePreCorrelationFlaggingStatisticsType = WINSORIZED  # NORMAL, WINSORIZED
-OLAP.CNProc.onlinePostCorrelationFlaggingIntegration = 763
+OLAP.CNProc.onlinePostCorrelationFlaggingIntegration = 768
 
 OLAP.CNProc.onlinePostCorrelationFlagging= F
 OLAP.CNProc.onlinePostCorrelationFlaggingType = SMOOTHED_SUM_THRESHOLD_WITH_HISTORY  # THRESHOLD, SUM_THRESHOLD, SMOOTHED_SUM_THRESHOLD, SMOOTHED_SUM_THRESHOLD_WITH_HISTORY
@@ -46,8 +48,8 @@ Observation.Beam[0].TiedArrayBeam[0].dispersionMeasure = 0
 OLAP.IONProc.integrationSteps		 = 1
 OLAP.CNProc_CoherentStokes.timeIntegrationFactor = 1
 OLAP.CNProc_IncoherentStokes.timeIntegrationFactor = 1
-OLAP.CNProc_CoherentStokes.channelsPerSubband = 16
-OLAP.CNProc_IncoherentStokes.channelsPerSubband = 16
+OLAP.CNProc_CoherentStokes.channelsPerSubband = 32
+OLAP.CNProc_IncoherentStokes.channelsPerSubband = 32
 #OLAP.CNProc_CoherentStokes.which	 = IQUV
 #OLAP.CNProc_IncoherentStokes.which	 = IQUV
 OLAP.CNProc_CoherentStokes.which	 = I
@@ -74,7 +76,7 @@ Observation.subbandList			 = [200..231]
 Observation.beamList			 = [32*0]
 Observation.rspBoardList		 = [32*0]
 Observation.rspSlotList		 	 = [0..31]
-Observation.channelsPerSubband		 = 16
+Observation.channelsPerSubband		 = 32
 Observation.sampleClock			 = 200
 Observation.nrSlotsInFrame		 = 32
 Observation.ObsID			 = 1000000
diff --git a/RTCP/CNProc/test/RFI-test.parset b/RTCP/CNProc/test/RFI-test.parset
index aeecbe565e0..3c5a01111d7 100644
--- a/RTCP/CNProc/test/RFI-test.parset
+++ b/RTCP/CNProc/test/RFI-test.parset
@@ -9,7 +9,9 @@ OLAP.CNProc.tabList			 = []
 
 OLAP.CNProc.onlineFlagging               = T # enable or disable all online flagging
 
-OLAP.CNProc.onlinePreCorrelationFlagging = T
+OLAP.CNProc.onlinePreCorrelationNoChannelsFlagging = T
+
+OLAP.CNProc.onlinePreCorrelationFlagging = F
 OLAP.CNProc.onlinePreCorrelationFlaggingType = INTEGRATED_SMOOTHED_SUM_THRESHOLD_WITH_HISTORY  # THRESHOLD, INTEGRATED_THRESHOLD, SUM_THRESHOLD, INTEGRATED_SUM_THRESHOLD, INTEGRATED_SMOOTHED_SUM_THRESHOLD, INTEGRATED_SMOOTHED_SUM_THRESHOLD_WITH_HISTORY
 OLAP.CNProc.onlinePreCorrelationFlaggingStatisticsType = WINSORIZED  # NORMAL, WINSORIZED
 
diff --git a/RTCP/CNProc/test/tInversePPF.cc b/RTCP/CNProc/test/tInversePPF.cc
index 27c8b321edf..1217b19d129 100644
--- a/RTCP/CNProc/test/tInversePPF.cc
+++ b/RTCP/CNProc/test/tInversePPF.cc
@@ -52,7 +52,8 @@ const static unsigned nrTaps = 16;
 static unsigned nrSubbands = 248;
 //static unsigned nrSubbands = 4;
 static unsigned nrChannels = 1; // for the NuMoon pipeline, there are no separate channels.
-static unsigned nrSamplesPerIntegration = 768 * 256 / 4; // one quarter of a second
+//static unsigned nrSamplesPerIntegration = 768 * 256 / 4; // one quarter of a second
+static unsigned nrSamplesPerIntegration = 19648; // roughly 0.1 seconds
 //static unsigned nrSamplesPerIntegration = 64;
 static double sampleRate = 195312.5;
 static double centerFrequency = (nrSamplesPerIntegration / 2) * sampleRate;
@@ -110,7 +111,7 @@ static void performStationFFT(TransposedBeamFormedData& transposedBeamFormedData
   // Put data in the right order, go from half complex to normal format
   for (unsigned subbandIndex = 0; subbandIndex < subbandList.size(); subbandIndex++) {
     unsigned subband = subbandList[subbandIndex];
-    fcomplex sample = makefcomplex(fftOutData[subband], fftOutData[onStationFilterSize - subband]);
+    fcomplex sample = makefcomplex(fftOutData[subband], fftOutData[onStationFilterSize - subband - 1]);
     transposedBeamFormedData.samples[subband][0 /* channel, but there is only one now */][time] = sample;
   }
 }
@@ -180,7 +181,7 @@ static void fftTest() {
 #if 0
   // Put data in the right order, go from half complex to normal format
   for (unsigned subband = 0; subband < nrSubbands; subband++) {
-    fcomplex sample = makefcomplex(fftOutData[subband], fftOutData[onStationFilterSize - subband]);
+    fcomplex sample = makefcomplex(fftOutData[subband], fftOutData[onStationFilterSize - subband - 1]);
     transposedBeamFormedData.samples[subband][0 /* channel */][time] = sample;
   }
 #endif
@@ -190,12 +191,10 @@ static void fftTest() {
   float maxError = 0.0f;
 
   for (unsigned time = 0; time < onStationFilterSize; time++) {
-
     float error = fabsf(inputData[time] - (fftInData[time]/((float)onStationFilterSize))); // the error
     if(error > maxError) {
       maxError = error;
     }
-
 //    fprintf(stdout, "%20.10lf\n", error);
 //    fprintf(stdout, "%20.10lf\n", fftInData[time]);
   }
diff --git a/RTCP/Interface/include/Interface/Parset.h b/RTCP/Interface/include/Interface/Parset.h
index 86117d77816..8b049dd76c7 100644
--- a/RTCP/Interface/include/Interface/Parset.h
+++ b/RTCP/Interface/include/Interface/Parset.h
@@ -167,6 +167,7 @@ class Parset: public ParameterSet
 
     bool                        onlineFlagging() const;
     bool                        onlinePreCorrelationFlagging() const;
+    bool                        onlinePreCorrelationNoChannelsFlagging() const;
     bool                        onlinePostCorrelationFlagging() const;
     bool                        onlinePostCorrelationFlaggingDetectBrokenStations() const;
     unsigned                    onlinePreCorrelationFlaggingIntegration() const;
@@ -780,6 +781,11 @@ inline bool Parset::onlinePreCorrelationFlagging() const
   return getBool("OLAP.CNProc.onlinePreCorrelationFlagging", false);
 }
 
+inline bool Parset::onlinePreCorrelationNoChannelsFlagging() const
+{
+  return getBool("OLAP.CNProc.onlinePreCorrelationNoChannelsFlagging", false);
+}
+
 inline bool Parset::onlinePostCorrelationFlagging() const
 {
   return getBool("OLAP.CNProc.onlinePostCorrelationFlagging", false);
-- 
GitLab