diff --git a/SignalProcessor/Filters/WindowedSyncFilter.cs b/SignalProcessor/Filters/WindowedSyncFilter.cs index ac839f7..d59b6a9 100644 --- a/SignalProcessor/Filters/WindowedSyncFilter.cs +++ b/SignalProcessor/Filters/WindowedSyncFilter.cs @@ -31,7 +31,7 @@ public WindowedSyncFilter() /// Note this filter kernel assumes samples are normalized by the caller /// /// - public virtual List ImpulseResponse() + public virtual List ImpulseResponse(bool normalize = true) { List impulseResponse; impulseResponse = new List(FilterLength + 1); @@ -54,10 +54,13 @@ public virtual List ImpulseResponse() normalizationFactor += impulseResponse[impulseResponse.Count - 1]; } - // Normalize for unity gain at DC - for (int idx = 0; idx < impulseResponse.Count; idx++) + if (normalize) { - impulseResponse[idx] = impulseResponse[idx] / normalizationFactor; + // Normalize for unity gain at DC + for (int idx = 0; idx < impulseResponse.Count; idx++) + { + impulseResponse[idx] = impulseResponse[idx] / normalizationFactor; + } } // Spectral inversion diff --git a/SignalProcessor/IWindowedSyncFilter.cs b/SignalProcessor/IWindowedSyncFilter.cs index 0f8d716..03377ef 100644 --- a/SignalProcessor/IWindowedSyncFilter.cs +++ b/SignalProcessor/IWindowedSyncFilter.cs @@ -9,6 +9,6 @@ public interface IWindowedSyncFilter double CutoffFrequencySamplingFrequencyPercentage { get; set; } int FilterLength { get; set; } - List ImpulseResponse(); + List ImpulseResponse(bool normalize = true); } } diff --git a/SignalProcessor/SignalProcessor.csproj b/SignalProcessor/SignalProcessor.csproj index 3fbcdf3..858e2e1 100644 --- a/SignalProcessor/SignalProcessor.csproj +++ b/SignalProcessor/SignalProcessor.csproj @@ -3,12 +3,12 @@ netstandard2.0 true - 0.1.12.0 - 0.1.12.0 - Stop cacheing impulse response, calculate every time ImpulseResponse is called, to avoid issues with changed parameters and stale impulse response. Callers should call and cache the value when performance is an issue + 0.1.14.0 + 0.1.14.0 + Add option to turn on / off normalization (default to on) for WindowedSyncFilter 2020 Brian Tabone Digital Signal Processing (FFT and Correlation) - 0.1.12 + 0.1.14 MIT true SignalProcessor.pfx @@ -17,7 +17,7 @@ https://github.com/hybridmachine/DSP git https://github.com/hybridmachine/DSP/projects/1 - signal processing fft analysis + signal processing fft analysis windowedsync diff --git a/Signals And Transforms/Models/WorkBook.cs b/Signals And Transforms/Models/WorkBook.cs index ec1b5c1..c2aafc6 100644 --- a/Signals And Transforms/Models/WorkBook.cs +++ b/Signals And Transforms/Models/WorkBook.cs @@ -74,7 +74,7 @@ public List ConvolvedFilterImpulseResponse() /// Band reject /// /// - public List SummedFilterImpulseResponse() + public List SummedFilterImpulseResponse(bool normalize = true) { List summedImpulseResponse = null; foreach (var filter in Filters.Values.Where(filt => filt.IsActive)) @@ -86,11 +86,11 @@ public List SummedFilterImpulseResponse() // Page 274 chapter 14 of "The Scientist and Engineer's Guide to Digital Signal Processing" if (null == summedImpulseResponse) { - summedImpulseResponse = filter.ImpulseResponse(); + summedImpulseResponse = filter.ImpulseResponse(normalize); } else { - List filterImpulseResponse = filter.ImpulseResponse(); + List filterImpulseResponse = filter.ImpulseResponse(normalize); // Ignore any filters that don't have the same filter length if (filterImpulseResponse.Count == summedImpulseResponse.Count) diff --git a/Signals And Transforms/Properties/Resources.Designer.cs b/Signals And Transforms/Properties/Resources.Designer.cs index 76e8dfd..199af1a 100644 --- a/Signals And Transforms/Properties/Resources.Designer.cs +++ b/Signals And Transforms/Properties/Resources.Designer.cs @@ -150,6 +150,15 @@ public static string FILTER_CUTOFF_PERCENTAGE { } } + /// + /// Looks up a localized string similar to Frequency Response (db). + /// + public static string FILTER_DECIBEL_RESPONSE_TITLE { + get { + return ResourceManager.GetString("FILTER_DECIBEL_RESPONSE_TITLE", resourceCulture); + } + } + /// /// Looks up a localized string similar to Frequency Response. /// @@ -186,6 +195,15 @@ public static string FILTER_NAME { } } + /// + /// Looks up a localized string similar to Step Response. + /// + public static string FILTER_STEP_RESPONSE_TITLE { + get { + return ResourceManager.GetString("FILTER_STEP_RESPONSE_TITLE", resourceCulture); + } + } + /// /// Looks up a localized string similar to High. /// @@ -348,15 +366,6 @@ public static string SIGNAL_PLOT_TITLE { } } - /// - /// Looks up a localized string similar to Step Response. - /// - public static string STEP_RESPONSE_TITLE { - get { - return ResourceManager.GetString("STEP_RESPONSE_TITLE", resourceCulture); - } - } - /// /// Looks up a localized string similar to .stw. /// diff --git a/Signals And Transforms/Properties/Resources.resx b/Signals And Transforms/Properties/Resources.resx index 7eab346..6d4c4fa 100644 --- a/Signals And Transforms/Properties/Resources.resx +++ b/Signals And Transforms/Properties/Resources.resx @@ -147,6 +147,9 @@ Sampling Frequency Cutoff % + + Frequency Response (db) + Frequency Response @@ -159,6 +162,9 @@ Filter Name + + Step Response + High @@ -214,9 +220,6 @@ Signal - - Step Response - .stw diff --git a/Signals And Transforms/SignalsAndTransforms.csproj b/Signals And Transforms/SignalsAndTransforms.csproj index a6c8634..2cbe893 100644 --- a/Signals And Transforms/SignalsAndTransforms.csproj +++ b/Signals And Transforms/SignalsAndTransforms.csproj @@ -83,8 +83,8 @@ ..\packages\OxyPlot.Wpf.2.0.0\lib\net45\OxyPlot.Wpf.dll - - packages\SignalProcessor.0.1.12\lib\netstandard2.0\SignalProcessor.dll + + packages\SignalProcessor.0.1.14\lib\netstandard2.0\SignalProcessor.dll packages\SQLitePCLRaw.bundle_e_sqlite3.2.0.2\lib\net461\SQLitePCLRaw.batteries_v2.dll diff --git a/Signals And Transforms/View Models/FilterViewModel.cs b/Signals And Transforms/View Models/FilterViewModel.cs index 7c83d45..7c91cee 100644 --- a/Signals And Transforms/View Models/FilterViewModel.cs +++ b/Signals And Transforms/View Models/FilterViewModel.cs @@ -9,6 +9,7 @@ using System.Collections.ObjectModel; using System.ComponentModel; using System.Linq; +using System.Numerics; using System.Text; using System.Threading.Tasks; @@ -31,6 +32,8 @@ public FilterViewModel() public IList FrequencyResponsePoints { get; private set; } + public IList DecibelResponsePoints { get; private set; } + public IList StepResponsePoints { get; private set; } public event PropertyChangedEventHandler PropertyChanged; @@ -50,7 +53,7 @@ public void AddFilter(Filter newFilter) private List GetStepData(int len) { List stepData = new List(); - int pointsOn = len / 3; // point at which signal switches from 0 to 1 + int pointsOn = len / 2; // point at which signal switches from 0 to 1 for (int idx = 0; idx < len; idx++) { @@ -61,7 +64,7 @@ private List GetStepData(int len) private void LoadFilterData() { - List summedFilterData = manager.ActiveWorkBook().SummedFilterImpulseResponse(); + List summedFilterData = manager.ActiveWorkBook().SummedFilterImpulseResponse(true); if (summedFilterData == null || summedFilterData.Count == 0) { return; @@ -82,12 +85,17 @@ private void LoadFilterData() Convolution convolver = new Convolution(); List stepResponse = convolver.Convolve(summedFilterData, GetStepData(summedFilterData.Count + 16), ConvolutionType.INPUTSIDE); FrequencyResponsePoints = new List(frequencyDomain.FrequencyAmplitudes.Count); + DecibelResponsePoints = new List(FrequencyResponsePoints.Count); // Load the frequency response graph data - List values = new List(frequencyDomain.FrequencyAmplitudes.Values); - for (int idx = 0; idx < frequencyDomain.FrequencyAmplitudes.Count; idx++) + // Only scan the first half of the coefficients (up to the Nyquist frequency) + int coefficientMax = (frequencyDomain.FourierCoefficients.Count / 2); + for (int idx = 0; idx < coefficientMax; idx++) { - FrequencyResponsePoints.Add(new DataPoint((((double)idx + 1.0) / summedFilterData.Count), values[idx])); + double coeffLen = Complex.Abs(frequencyDomain.FourierCoefficients[idx]); + double cuttoffFrequencyPercent = (((double)idx + 1.0) / summedFilterData.Count); + FrequencyResponsePoints.Add(new DataPoint(cuttoffFrequencyPercent, coeffLen)); + DecibelResponsePoints.Add(new DataPoint(cuttoffFrequencyPercent, 20 * Math.Log10(coeffLen))); } int startingOffset = (summedFilterData.Count / 2); @@ -111,6 +119,7 @@ private void LoadFilterData() NotifyPropertyChanged(nameof(ImpulseResponsePoints)); NotifyPropertyChanged(nameof(FrequencyResponsePoints)); + NotifyPropertyChanged(nameof(DecibelResponsePoints)); NotifyPropertyChanged(nameof(StepResponsePoints)); NotifyPropertyChanged(nameof(Filters)); } diff --git a/Signals And Transforms/Views/FilterView.xaml b/Signals And Transforms/Views/FilterView.xaml index 497a860..735881a 100644 --- a/Signals And Transforms/Views/FilterView.xaml +++ b/Signals And Transforms/Views/FilterView.xaml @@ -78,7 +78,7 @@ MarkerType="Square"/> - + + + + + + diff --git a/Signals And Transforms/packages.config b/Signals And Transforms/packages.config index e69c942..f3012a7 100644 --- a/Signals And Transforms/packages.config +++ b/Signals And Transforms/packages.config @@ -10,7 +10,7 @@ - + diff --git a/UnitTests/WindowedSyncFilterTest.cs b/UnitTests/WindowedSyncFilterTest.cs index e404254..606d469 100644 --- a/UnitTests/WindowedSyncFilterTest.cs +++ b/UnitTests/WindowedSyncFilterTest.cs @@ -26,6 +26,7 @@ public void LowPassWindowedSyncTest() List impulseResponse = filter.ImpulseResponse(); List secondImpulseResponseTest = filter.ImpulseResponse(); + List non_normalizedResponseTest = filter.ImpulseResponse(false); // Make sure back to back calls return the same data for the same parameters for (int idx = 0; idx < impulseResponse.Count; idx++) @@ -37,6 +38,7 @@ public void LowPassWindowedSyncTest() Assert.IsNotNull(impulseResponse); Assert.IsNotNull(highImpulseResponse); + Assert.IsNotNull(non_normalizedResponseTest); Assert.IsTrue(impulseResponse.Count == filter.FilterLength + 1); }