From Friday, April 19th (11:00 PM CDT) through Saturday, April 20th (2:00 PM CDT), 2024, ni.com will undergo system upgrades that may result in temporary service interruption.
We appreciate your patience as we improve our online experience.
From Friday, April 19th (11:00 PM CDT) through Saturday, April 20th (2:00 PM CDT), 2024, ni.com will undergo system upgrades that may result in temporary service interruption.
We appreciate your patience as we improve our online experience.
03-23-2017 01:39 PM
Hello,
No matter what I pass through to the Chebyshev low-pass filter, I am getting an attenuating sine wave back.
I have tried passing double values derived from an FFT based on the code below:
FFTFrequency = Index * ForcingFunctionSampleRate / ForcingFunctionBlockSize FFTMagnitude = ComplexDataArray(Index).Magnitude FFTGraphedMagnitude = 2 / ForcingFunctionBlockSize * FFTMagnitude
I then use the X and Y Values of "FFTFrequency" and FFTGraphedMagnitude and pass those into the LPF function. I use the FFTGraphedMagnitude values as the input for the LPF function.
I have also attempted to completely skip this code, and pass in the ComplexDouble data from the FFT directly to the LPF function. It, again, gives me an attenuating sine wave for the .Real values.
What am I doing wrong?
Sample Rate is 1623.377 Hz, block size is 8192. Passband ripple is 1 db. Filter order is 10.
I am trying to LPF (cutoff frequency) at 140 Hz.
Here is my original function, a combination of multiple sine waves at frequencies of 180.3752, 162.3377, 147.5797, 124.8751, 108.2251, 90.18759, 81.16883, 70.58159, 60.12506, 50.73052, 40.58442, 30.06253, 20.04169, and 10.02084 Hz.
Here's the FFT graph based off of the code that gives me the X and Y values I pasted above:
And here is where it always goes sideways, regardless of the input data into the LPF function:
I am completely baffled at what to do next, or what to test. Any and all help is greatly appreciated. I am using .NET 4.0 inside of Visual Studio 2013. I have the Professional edition.
Thank you,
John Lindsay
03-24-2017 03:38 PM
Hi John,
Could you post a complete small reproducing case of your code? It will help me understand better.
thanks,
Pat
03-24-2017 03:52 PM
Here's a basic set of what I'm trying to do:
Imports System.Math Imports NationalInstruments Imports NationalInstruments.Analysis.Dsp.Transforms Public Class Frequency Const ForcingFunctionBlockSize As Integer = 8192 Const Timestep As Single = 0.000616 Const ForcingFunctionSampleRate As Double = 1623.377 Friend Function GenerateSineWave() As Double() Dim PulseAdded As Boolean = False Dim NumberOfPulsedTimeSteps As Integer = 2 Dim ReturnedDataSet(ForcingFunctionBlockSize - 1) As Double Dim SineIncrement(14) As Double For BlockStep As Integer = 0 To ForcingFunctionBlockSize Select Case BlockStep Case 9 '180.3752 SineIncrement(0) = 2 * PI / BlockStep Case 10 '162.3377 SineIncrement(1) = 2 * PI / BlockStep Case 11 '147.5797 SineIncrement(2) = 2 * PI / BlockStep Case 13 '124.8751 SineIncrement(3) = 2 * PI / BlockStep Case 15 '108.2251 SineIncrement(4) = 2 * PI / BlockStep Case 18 '90.18759 SineIncrement(5) = 2 * PI / BlockStep Case 20 '81.16883 SineIncrement(6) = 2 * PI / BlockStep Case 23 '70.58159 SineIncrement(7) = 2 * PI / BlockStep Case 27 '60.12506 SineIncrement(8) = 2 * PI / BlockStep Case 32 '50.73052 SineIncrement(9) = 2 * PI / BlockStep Case 40 '40.58442 SineIncrement(10) = 2 * PI / BlockStep Case 54 '30.06253 SineIncrement(11) = 2 * PI / BlockStep Case 81 '20.04169 SineIncrement(12) = 2 * PI / BlockStep Case 162 '10.02084 SineIncrement(13) = 2 * PI / BlockStep Exit For End Select Next For CurrentTimeStep As Integer = 0 To ForcingFunctionBlockSize - 1 Dim CurrentTime As Single = CurrentTimeStep * Timestep Dim YValue As Double For Each Value As Double In SineIncrement YValue += Sin(Value * CurrentTimeStep) Next ReturnedDataSet(CurrentTimeStep) = YValue Next Return ReturnedDataSet End Function Friend Function FFTPulse(ByVal RawDataSetIn() As Double) As Double() Dim ReturnedDataSet(RawDataSetIn.Length) As Double Dim FFTFrequency As Double Dim FFTMagnitude As Double Dim FFTGraphedMagnitude As Double Dim ComplexDataArray(RawDataSetIn.Length - 1) As ComplexDouble Dim ComplexPartAsZero(RawDataSetIn.Length - 1) As Double ComplexDataArray = ComplexDouble.ComposeArray(RawDataSetIn, ComplexPartAsZero) Fft(ComplexDataArray) For Index As Integer = 0 To ComplexDataArray.Length - 1 FFTFrequency = Index * ForcingFunctionSampleRate / ForcingFunctionBlockSize FFTMagnitude = ComplexDataArray(Index).Magnitude FFTGraphedMagnitude = 2 / ForcingFunctionBlockSize * FFTMagnitude ReturnedDataSet(Index) = FFTGraphedMagnitude Next LPFComplex(ComplexDataArray) Return ReturnedDataSet End Function Friend Function LPF(ByRef FFTMagnitudes() As Double) As Double() Dim FilterOrder As Integer = 10 Dim CutoffFrequency As Double = 140 Dim FilterRipple As Double = 1 Dim NewFilter As New NationalInstruments.Analysis.Dsp.Filters.ChebyshevLowpassFilter(FilterOrder, ForcingFunctionSampleRate, CutoffFrequency, FilterRipple) Dim FFTMagnitudesArray(FFTMagnitudes.Length - 1) As Double Dim LPFReturn() As Double Dim ReturnedRawDataSet(FFTMagnitudes.Length - 1) As Double FFTMagnitudesArray = FFTMagnitudes LPFReturn = NewFilter.FilterData(FFTMagnitudesArray) For Counter As Integer = 0 To ForcingFunctionBlockSize - 1 Dim Time As Double = Counter * Timestep Dim LPFYValue As Double LPFYValue = LPFReturn(Counter) ReturnedRawDataSet(Counter) = LPFYValue Next Return ReturnedRawDataSet End Function Friend Function LPFComplex(ByRef FFTComplexData() As ComplexDouble) Dim FilterOrder As Integer = 10 Dim ForcingFunctionSampleRate As Double = 1623.377 Dim CutoffFrequency As Double = 140 Dim FilterRipple As Double = 1 Dim NewFilter As New NationalInstruments.Analysis.Dsp.Filters.ChebyshevLowpassFilterComplex(FilterOrder, ForcingFunctionSampleRate, CutoffFrequency, FilterRipple) Dim FFTMagnitudesArray(FFTComplexData.Length) As Double Dim LPFReturn() As ComplexDouble Dim ReturnedDataSet(ForcingFunctionBlockSize - 1) As Double LPFReturn = NewFilter.FilterData(FFTComplexData) For Counter As Integer = 0 To (ForcingFunctionBlockSize - 1) Dim Time As Double = Counter * Timestep Dim LPFYValue As Double LPFYValue = LPFReturn(Counter).Real ReturnedDataSet(Counter) = LPFYValue Next Return ReturnedDataSet End Function End Class
I pass the previous function's return into the next function to continue the process along.
Note I have had to convert this code to more basic code - we are using classes to create "holding" variables that hold the X and Y values of the outputs so we can graph as you see above. This code is specific to our application and therefore wouldn't be of value if I included it, on top of being really hard to include since the supporting classes would be needed as well. I suppose I could have used a tuple or a dictionary, but I wanted to make it as easy as possible to read.