public void CheckTimeDomainSignal(int dftLength)
        {
            for (var delaySampleCount = 0; delaySampleCount < dftLength; delaySampleCount++)
            {
                var filter = Filtering.CreateFrequencyDomainDelayFilter(dftLength, delaySampleCount);

                var timeDomainSignal = new Complex[dftLength];
                timeDomainSignal[0] = filter[0];
                for (var w = 1; w < dftLength / 2; w++)
                {
                    timeDomainSignal[w]             = filter[w];
                    timeDomainSignal[dftLength - w] = filter[w].Conjugate();
                }
                timeDomainSignal[dftLength / 2] = filter[dftLength / 2];
                Fourier.Inverse(timeDomainSignal, FourierOptions.AsymmetricScaling);

                for (var t = 0; t < dftLength; t++)
                {
                    if (t == delaySampleCount)
                    {
                        Assert.AreEqual(1.0, timeDomainSignal[t].Real, 1.0E-6);
                        Assert.AreEqual(0.0, timeDomainSignal[t].Imaginary, 1.0E-6);
                    }
                    else
                    {
                        Assert.AreEqual(0.0, timeDomainSignal[t].Real, 1.0E-6);
                        Assert.AreEqual(0.0, timeDomainSignal[t].Imaginary, 1.0E-6);
                    }
                }
            }
        }
        public void CheckWithDelayFilter()
        {
            var channelCount = 3;

            var impulseResponses = new double[][]
            {
                new double[] { 0.0, 0.0, 0.0, 1.0 },
                new double[] { 0.0, 0.0, 1.0 },
                new double[] { 0.0, 0.0, 0.0, 0.0, 1.0 }
            };

            var delaySampleCounts = new int[]
            {
                3,
                2,
                4
            };

            var dftLength = 1024;

            var sv = SteeringVector.FromImpulseResponse(impulseResponses, dftLength);

            Assert.AreEqual(dftLength / 2 + 1, sv.Length);

            for (var ch = 0; ch < channelCount; ch++)
            {
                var expected = Filtering.CreateFrequencyDomainDelayFilter(dftLength, delaySampleCounts[ch]);

                for (var w = 0; w < dftLength / 2 + 1; w++)
                {
                    Assert.AreEqual(expected[w].Real, sv[w][ch].Real, 1.0E-6);
                    Assert.AreEqual(expected[w].Imaginary, sv[w][ch].Imaginary, 1.0E-6);
                }
            }
        }
        public void CheckWithDelayFilter_Case2()
        {
            var delaySampleCount = 3;

            var sampleRate = 16000;
            var dftLength  = 1024;

            var time     = (double)delaySampleCount / sampleRate;
            var distance = AcousticConstants.SoundSpeed * time;

            var soundSource = new SoundSource(1.0, 1.0, 1.0);

            var microphones = new Microphone[]
            {
                new Microphone(1.0 + 1 * distance, 1.0, 1.0),
                new Microphone(1.0 + 2 * distance, 1.0, 1.0),
                new Microphone(1.0 + 3 * distance, 1.0, 1.0)
            };

            var sv = SteeringVector.FromFarFieldGeometry(microphones, Math.PI / 4, 0.0, sampleRate, dftLength);

            Assert.AreEqual(dftLength / 2 + 1, sv.Length);

            var delayFilters = new Complex[][]
            {
                Filtering.CreateFrequencyDomainDelayFilter(dftLength, 0 / Math.Sqrt(2)),
                Filtering.CreateFrequencyDomainDelayFilter(dftLength, 3 / Math.Sqrt(2)),
                Filtering.CreateFrequencyDomainDelayFilter(dftLength, 6 / Math.Sqrt(2))
            };

            for (var w = 0; w < dftLength / 2 + 1; w++)
            {
                for (var ch = 0; ch < 3; ch++)
                {
                    var actual   = sv[w][ch];
                    var expected = delayFilters[ch][w];
                    Assert.AreEqual(expected.Real, actual.Real, 1.0E-6);
                    Assert.AreEqual(expected.Imaginary, actual.Imaginary, 1.0E-6);
                }
            }
        }
예제 #4
0
        /// <summary>
        /// Generate the room impulse response in the frequency domain.
        /// </summary>
        /// <param name="room">The room to be simulated.</param>
        /// <param name="soundSource">The sound source to be simulated.</param>
        /// <param name="microphone">The microphone to be simulated.</param>
        /// <param name="sampleRate">The sampling frequency of the impulse response.</param>
        /// <param name="dftLength">The length of the DFT.</param>
        /// <returns>
        /// The simulated impulse response in the frequency domain.
        /// Since the components higher than the Nyquist frequency are discarded,
        /// the length of the returned array is dftLength / 2 + 1.
        /// </returns>
        public static Complex[] GenerateFrequencyDomainImpulseResponse(Room room, SoundSource soundSource, Microphone microphone, int sampleRate, int dftLength)
        {
            if (room == null)
            {
                throw new ArgumentNullException(nameof(room));
            }
            if (soundSource == null)
            {
                throw new ArgumentNullException(nameof(soundSource));
            }
            if (microphone == null)
            {
                throw new ArgumentNullException(nameof(microphone));
            }

            if (sampleRate <= 0)
            {
                throw new ArgumentException(nameof(sampleRate), "The sampling frequency must be greater than zero.");
            }
            if (dftLength <= 0 || dftLength % 2 != 0)
            {
                throw new ArgumentException(nameof(dftLength), "The length of the DFT must be positive and even.");
            }

            var response = new Complex[dftLength / 2 + 1];

            foreach (var ray in GenerateSoundRays(room, soundSource, microphone))
            {
                var time                = ray.Distance / AcousticConstants.SoundSpeed;
                var delaySampleCount    = sampleRate * time;
                var delayFilter         = Filtering.CreateFrequencyDomainDelayFilter(dftLength, delaySampleCount);
                var distanceAttenuation = room.DistanceAttenuation(ray.Distance);
                for (var w = 0; w < response.Length; w++)
                {
                    var frequency             = (double)w / dftLength * sampleRate;
                    var reflectionAttenuation = Math.Pow(room.ReflectionAttenuation(frequency), ray.ReflectionCount);
                    response[w] += distanceAttenuation * reflectionAttenuation * delayFilter[w];
                }
            }
            return(response);
        }
예제 #5
0
        private void EstimateCore(Microphone[] microphones, int sampleRate, int frameLength, double maxSpace)
        {
            var estimator = new GeneralPerFrequencyDoaEstimator2D(microphones, sampleRate, frameLength);

            for (var deg = 1; deg < 360; deg++)
            {
                var expectedDoa = Math.PI * deg / 180 - Math.PI;

                MathNet.Numerics.LinearAlgebra.Vector <double> dv = DenseVector.OfArray(new double[]
                {
                    Math.Cos(expectedDoa),
                    Math.Sin(expectedDoa),
                    0
                });

                var dfts = new Complex[frameLength][];
                for (var ch = 0; ch < microphones.Length; ch++)
                {
                    var distance         = microphones[ch].Position * dv;
                    var delaySampleCount = -distance / AcousticConstants.SoundSpeed * sampleRate;
                    var delayFilter      = Filtering.CreateFrequencyDomainDelayFilter(frameLength, delaySampleCount);
                    var dft = new Complex[frameLength];
                    Array.Copy(delayFilter, dft, delayFilter.Length);
                    dfts[ch] = dft;
                }

                var actualDoa = estimator.Estimate(dfts);

                for (var w = 1; w < frameLength / 2 + 1; w++)
                {
                    var waveLength = (double)frameLength / w / sampleRate * AcousticConstants.SoundSpeed;

                    if (maxSpace + 1.0E-6 < waveLength / 2)
                    {
                        Assert.AreEqual(expectedDoa, actualDoa[w], 1.0E-6);
                    }
                }
            }
        }
예제 #6
0
        /// <summary>
        /// Create steering vectors geometrically for each discrete frequency under the near-field assumption.
        /// </summary>
        /// <param name="microphones">The microphones.</param>
        /// <param name="soundSource">The sound source.</param>
        /// <param name="sampleRate">The sampling frequency.</param>
        /// <param name="dftLength">The length of the DFT.</param>
        /// <returns>
        /// The steering vectors for each discrete frequency.
        /// Since the components higher than the Nyquist frequency are discarded,
        /// the length of the returned array is dftLength / 2 + 1.
        /// </returns>
        public static Vector <Complex>[] FromNearFieldGeometry(IReadOnlyList <Microphone> microphones, SoundSource soundSource, int sampleRate, int dftLength)
        {
            if (microphones == null)
            {
                throw new ArgumentNullException(nameof(microphones));
            }
            if (microphones.Count == 0)
            {
                throw new ArgumentException(nameof(microphones), "The number of microphones must be greater than zero.");
            }
            if (microphones.Any(mic => mic == null))
            {
                throw new ArgumentException(nameof(microphones), "All the microphone object must be non-null.");
            }

            if (soundSource == null)
            {
                throw new ArgumentNullException(nameof(soundSource));
            }

            if (sampleRate <= 0)
            {
                throw new ArgumentException(nameof(sampleRate), "The sampling frequency must be greater than zero.");
            }

            if (dftLength <= 0 || dftLength % 2 != 0)
            {
                throw new ArgumentException(nameof(dftLength), "The length of the DFT must be positive and even.");
            }

            var channelCount = microphones.Count;

            var destination = new Vector <Complex> [dftLength / 2 + 1];

            for (var w = 0; w < destination.Length; w++)
            {
                destination[w] = new DenseVector(channelCount);
            }

            var distances = new double[channelCount];

            for (var ch = 0; ch < channelCount; ch++)
            {
                distances[ch] = (soundSource.Position - microphones[ch].Position).L2Norm();
            }
            var offset = distances.Min();

            for (var ch = 0; ch < channelCount; ch++)
            {
                distances[ch] -= offset;
            }

            for (var ch = 0; ch < channelCount; ch++)
            {
                var distance         = distances[ch];
                var time             = distance / AcousticConstants.SoundSpeed;
                var delaySampleCount = sampleRate * time;
                var delayFilter      = Filtering.CreateFrequencyDomainDelayFilter(dftLength, delaySampleCount);

                for (var w = 0; w < destination.Length; w++)
                {
                    destination[w][ch] = delayFilter[w];
                }
            }

            return(destination);
        }