/// <summary>
        /// Runs a complex FFT on the interleaved time domain IQ samples and return the FFT's magnitude in dBFS
        /// </summary>
        /// <param name="timeDataInterleavedIq">Signed 16bit array interleaved with I and Q data.  First sample is I, second sample Q.</param>
        /// <param name="sampleRate_MHz">The sampling frequency, used to scale the analysis data.</param>
        /// <param name="runAnalysis">If true, will return a FftAnalysis structure with information about the FFT</param>
        /// <param name="sampleBitWidth"> Bit width of the converter sample (example: 16bit sample)</param>
        /// <param name="analysisData">FftAnalysis struture that is returned when runAnalysis = true</param>
        /// <returns></returns>
        public static double[] complexfftAndScale(short[] timeDataInterleavedIq, double sampleRate_MHz, byte sampleBitWidth, bool runAnalysis, out FftAnalysis analysisData)
        {
            int numSamples = timeDataInterleavedIq.Length / 2;

            double[] fftReal;
            double[] fftImag;
            double[] fftMagnitude_dB = new double[numSamples];
            analysisData = new FftAnalysis();
            double AdcFullScaleCode = System.Math.Pow(2, (sampleBitWidth - 1)); //2^(16-1) for 16bit converter ...assumming two's complement

            //ScaledWindowType window = ScaledWindowType.Hanning;
            ScaledWindow window = ScaledWindow.CreateHanningWindow();


            ComplexDouble[] complexSignal = new ComplexDouble[numSamples];
            int             j             = 0;

            //determine scaling value to normalize the time domain data.
            ComplexDouble scaleValue = new ComplexDouble(AdcFullScaleCode * (numSamples) * Math.Sqrt(window.EquivalentNoiseBandwidth), 0);

            //deinterleave IQ data array into complex number data type and normalize data.
            for (int i = 0; i < complexSignal.Length; i++)
            {
                complexSignal[i] = new ComplexDouble(timeDataInterleavedIq[j], timeDataInterleavedIq[j + 1]);
                complexSignal[i] = complexSignal[i].Divide(scaleValue);
                j = j + 2;
            }

            //Apply the Window (Default hanning)
            window.Apply(complexSignal);

            ComplexDouble[] fftData = Transforms.Fft(complexSignal, true);
            NationalInstruments.ComplexDouble.DecomposeArray(fftData, out fftReal, out fftImag);

            if (runAnalysis == true)
            {
                analysisData = analyzeFft(fftReal, fftImag, sampleRate_MHz);
            }
            else
            {
                analysisData = new FftAnalysis();
            }

            for (int i = 0; i < numSamples; i++)
            {
                fftMagnitude_dB[i] = 10.0 * System.Math.Log10(fftReal[i] * fftReal[i] + fftImag[i] * fftImag[i]);
            }

            return(fftMagnitude_dB);
        }
 void formFFTSource_FormClosing(object sender, FormClosingEventArgs e)
 {
     if (formFFTSource.isOKButton)
     {
         string selectedObject = formFFTSource.listBoxControlSource.SelectedValue.ToString();
         for (int i = 0; i < tbControlPanelAssignment.Rows.Count; i++)
         {
             if (((ObjectSignal)tbControlPanelAssignment.Rows[i]["control"]).ControlName == selectedObject)
             {
                 OSequence = (ObjectSequence)tbControlPanelAssignment.Rows[i]["control"];
                 break;
             }
         }
         windowType = GetSelectedWindow((ScaledWindowType)Enum.Parse(typeof(ScaledWindowType), formFFTSource.comboBoxEditWindow.SelectedItem.ToString()));
         outputType = formFFTSource.comboBoxEditOutput.SelectedText;
         SequenceSource = OSequence;
     }
 }
        public override void ToDo(object Arg)
        {
            b = new BoxController();
            b.Init("USB0::0x0957::0x1718::TW54334510::INSTR");

            var _ch = new AI_ChannelConfig[4]
            {
                new AI_ChannelConfig()
                {
                    ChannelName = AnalogInChannelsEnum.AIn1, Enabled = true, Mode = ChannelModeEnum.DC, Polarity = PolarityEnum.Polarity_Bipolar, Range = RangesEnum.Range_1_25
                },
                new AI_ChannelConfig()
                {
                    ChannelName = AnalogInChannelsEnum.AIn2, Enabled = false, Mode = ChannelModeEnum.DC, Polarity = PolarityEnum.Polarity_Bipolar, Range = RangesEnum.Range_1_25
                },
                new AI_ChannelConfig()
                {
                    ChannelName = AnalogInChannelsEnum.AIn3, Enabled = false, Mode = ChannelModeEnum.DC, Polarity = PolarityEnum.Polarity_Bipolar, Range = RangesEnum.Range_1_25
                },
                new AI_ChannelConfig()
                {
                    ChannelName = AnalogInChannelsEnum.AIn4, Enabled = false, Mode = ChannelModeEnum.DC, Polarity = PolarityEnum.Polarity_Bipolar, Range = RangesEnum.Range_1_25
                }
            };

            b.ConfigureAI_Channels(_ch);

            var freq      = 500000;
            var updNumber = 1;
            var avgNumber = 1000;

            double[] autoPSDLowFreq;
            double[] autoPSDHighFreq;

            Point[] noisePSD = new Point[] { };

            if (freq % 2 != 0)
            {
                throw new ArgumentException("The frequency should be an even number!");
            }

            b.AcquisitionInProgress = true;
            b.AI_ChannelCollection[AnalogInChannelsEnum.AIn1].DataReady += DefResistanceNoise_DataReady;

            var sb = new StringBuilder();

            double dtLowFreq = 0.0, dtHighFreq = 0.0;
            double dfLowFreq = 1.0, dfHighFreq = 0.0;
            double equivalentNoiseBandwidthLowFreq, equivalentNoiseBandwidthHighFreq;
            double coherentGainLowFreq, coherentGainHighFreq;

            Parallel.Invoke(
                () =>
            {
                b.StartAnalogAcquisition(freq);
                IsRunning = false;
            },
                () =>
            {
                while (true)
                {
                    if (!IsRunning)
                    {
                        b.AcquisitionInProgress = false;
                        break;
                    }
                    if (averagingCounter >= avgNumber)
                    {
                        b.AcquisitionInProgress = false;
                        break;
                    }

                    Point[] timeTrace;
                    var dataReadingSuccess = b.AI_ChannelCollection[AnalogInChannelsEnum.AIn1].ChannelData.TryDequeue(out timeTrace);

                    if (dataReadingSuccess)
                    {
                        var query = from val in timeTrace
                                    select val.Y;

                        var counter   = 0;
                        var traceData = new double[timeTrace.Length];
                        foreach (var item in query)
                        {
                            traceData[counter] = item;
                            ++counter;
                        }

                        var unit = new System.Text.StringBuilder("V", 256);
                        var sw   = ScaledWindow.CreateRectangularWindow();

                        // Calculation of the low-frequency part of the spectrum

                        sw.Apply(traceData, out equivalentNoiseBandwidthLowFreq, out coherentGainLowFreq);

                        dtLowFreq = 1.0 / (double)freq;

                        autoPSDLowFreq       = Measurements.AutoPowerSpectrum(traceData, dtLowFreq, out dfLowFreq);
                        var singlePSDLowFreq = Measurements.SpectrumUnitConversion(autoPSDLowFreq, SpectrumType.Power, ScalingMode.Linear, DisplayUnits.VoltsPeakSquaredPerHZ, dfLowFreq, equivalentNoiseBandwidthLowFreq, coherentGainLowFreq, unit);

                        // Calculation of the hugh-frequency part of the spectrum

                        var selection64Hz = PointSelector.SelectPoints(ref traceData, 64);

                        sw.Apply(selection64Hz, out equivalentNoiseBandwidthHighFreq, out coherentGainHighFreq);

                        dtHighFreq = 64.0 * 1.0 / (double)freq;

                        autoPSDHighFreq       = Measurements.AutoPowerSpectrum(selection64Hz, dtHighFreq, out dfHighFreq);
                        var singlePSDHighFreq = Measurements.SpectrumUnitConversion(autoPSDHighFreq, SpectrumType.Power, ScalingMode.Linear, DisplayUnits.VoltsPeakSquaredPerHZ, dfHighFreq, equivalentNoiseBandwidthHighFreq, coherentGainHighFreq, unit);

                        var lowFreqSpectrum  = singlePSDLowFreq.Select((value, index) => new Point((index + 1) * dfLowFreq, value)).Where(value => value.X <= 1064);
                        var highFreqSpectrum = singlePSDLowFreq.Select((value, index) => new Point((index + 1) * dfHighFreq, value)).Where(value => value.X > 1064);

                        noisePSD = new Point[lowFreqSpectrum.Count() + highFreqSpectrum.Count()];

                        counter = 0;
                        foreach (var item in lowFreqSpectrum)
                        {
                            noisePSD[counter].X  = item.X;
                            noisePSD[counter].Y += item.Y;

                            ++counter;
                        }
                        foreach (var item in highFreqSpectrum)
                        {
                            noisePSD[counter].X  = item.X;
                            noisePSD[counter].Y += item.Y;

                            ++counter;
                        }

                        //for (int i = 0; i < singlePSDLowFreq.Length; i++)
                        //    noisePSD[i] += singlePSDLowFreq[i];

                        if (averagingCounter % updNumber == 0)
                        {
                            sb = new StringBuilder();

                            for (int i = 0; i < noisePSD.Length; i++)
                            {
                                sb.AppendFormat("{0}\t{1}\r\n", (noisePSD[i].X).ToString(NumberFormatInfo.InvariantInfo), (noisePSD[i].Y / (double)averagingCounter).ToString(NumberFormatInfo.InvariantInfo));
                            }

                            onDataArrived(new ExpDataArrivedEventArgs(sb.ToString()));
                        }
                    }
                }

                //sb = new StringBuilder();

                //for (int i = 0; i < noisePSD.Length; i++)
                //    sb.AppendFormat("{0}\t{1}\r\n", (noisePSD[i].X).ToString(NumberFormatInfo.InvariantInfo), (noisePSD[i].Y / (double)averagingCounter).ToString(NumberFormatInfo.InvariantInfo));

                //onDataArrived(new ExpDataArrivedEventArgs(sb.ToString()));
            });

            b.Close();
        }
        public Point[] GetTwoPartsFFT(double[] timeTrace, int samplingFrequency = 500000, int nDataSamples = 1, double kAmpl = 1.0, double lowFreqStartFreq = 1.0, double cutOffLowFreq = 1600, double cutOffHighFreq = 102400, int filterOrder = 8, double filterFrequency = 6400, int lowFreqPeriod = 10, int highFreqPeriod = 10)
        {
            Point[] autoPSDLowFreq  = new Point[] { };
            Point[] autoPSDHighFreq = new Point[] { };

            if (filterFrequency == -1)
            {
                filterFrequency = cutOffLowFreq;
            }

            var sb = new StringBuilder();

            double dtLowFreq = 0.0, dtHighFreq = 0.0;
            double dfLowFreq = 0.0, dfHighFreq = 0.0;
            double equivalentNoiseBandwidthLowFreq, equivalentNoiseBandwidthHighFreq;
            double coherentGainLowFreq, coherentGainHighFreq;

            // Subsetting samples from the entire trace
            var timeTraceSelectionList = new LinkedList <double[]>();

            var range = (int)((timeTrace.Length) / nDataSamples);

            for (int i = 0; i != nDataSamples;)
            {
                var selection = timeTrace.Where((value, index) => index >= i * range && index < (i + 1) * range).Select(val => val);
                timeTraceSelectionList.AddLast(selection.ToArray());
                ++i;
            }

            var filter = new NationalInstruments.Analysis.Dsp.Filters.EllipticLowpassFilter(filterOrder, samplingFrequency, filterFrequency, 0.1, 100.0);

            var unit = new System.Text.StringBuilder("V", 256);

            var noisePSD = new Point[] { };

            // Calculating FFT in each sample
            foreach (var trace in timeTraceSelectionList)
            {
                // Calculation of the LOW-FREQUENCY part of the spectrum

                // Filtering data for low frequency selection

                var filteredData = filter.FilterData(trace);
                var sw           = ScaledWindow.CreateRectangularWindow();

                // Selecting lower amount of data points to reduce the FFT noise

                var selectionLowFreq = filteredData.Where((value, index) => (index) % lowFreqPeriod == 0).ToArray();

                sw.Apply(selectionLowFreq, out equivalentNoiseBandwidthLowFreq, out coherentGainLowFreq);

                dtLowFreq = lowFreqPeriod * 1.0 / (double)samplingFrequency;

                var singlePSD_LOW_Freq = Measurements.AutoPowerSpectrum(selectionLowFreq, dtLowFreq, out dfLowFreq);

                autoPSDLowFreq = (singlePSD_LOW_Freq.Select((value, index) => new Point(index * dfLowFreq, value)).Where(p => p.X >= 1 && p.X <= cutOffLowFreq)).ToArray();

                // Calculation of the HIGH-FREQUENCY part of the spectrum

                dtHighFreq = 1.0 / (double)samplingFrequency;

                var highFreqSelectionRange = (int)((timeTrace.Length) / highFreqPeriod);

                LinkedList <double[]> selectionList = new LinkedList <double[]>();

                for (int i = 0; i != highFreqPeriod;)
                {
                    var arr = new double[highFreqSelectionRange];
                    Array.Copy(timeTrace, i * highFreqSelectionRange, arr, 0, highFreqSelectionRange);
                    selectionList.AddLast(arr);
                    ++i;
                }

                var cumulativePSD_HIGH_Freq = new double[] { };

                foreach (var selection in selectionList)
                {
                    sw.Apply(selection, out equivalentNoiseBandwidthHighFreq, out coherentGainHighFreq);
                    var singlePSD_HIGH_Freq = Measurements.AutoPowerSpectrum(selection, dtHighFreq, out dfHighFreq);

                    if (cumulativePSD_HIGH_Freq.Length == 0)
                    {
                        cumulativePSD_HIGH_Freq = Enumerable.Repeat(0.0, singlePSD_HIGH_Freq.Length).ToArray();
                    }

                    for (int i = 0; i != singlePSD_HIGH_Freq.Length;)
                    {
                        cumulativePSD_HIGH_Freq[i] += singlePSD_HIGH_Freq[i];
                        ++i;
                    }
                }

                autoPSDHighFreq = (cumulativePSD_HIGH_Freq
                                   .Select((value, index) => new Point(index * dfHighFreq, value)))
                                  .Where(p => p.X > cutOffLowFreq && p.X <= cutOffHighFreq).ToArray();

                if (noisePSD == null || noisePSD.Length == 0)
                {
                    noisePSD = new Point[autoPSDLowFreq.Length + autoPSDHighFreq.Length];
                }

                var counter = 0;
                for (int i = 0; i != autoPSDLowFreq.Length;)
                {
                    var item = autoPSDLowFreq[i];
                    noisePSD[counter].X  = item.X;
                    noisePSD[counter].Y += item.Y;

                    ++counter;
                    ++i;
                }
                for (int i = 0; i != autoPSDHighFreq.Length;)
                {
                    var item = autoPSDHighFreq[i];
                    noisePSD[counter].X  = item.X;
                    noisePSD[counter].Y += item.Y / ((double)(highFreqPeriod * highFreqPeriod));

                    ++counter;
                    ++i;
                }
            }

            return((from item in noisePSD
                    select new Point(item.X, item.Y / (kAmpl * kAmpl))).ToArray());
        }