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); } } }
/// <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); }
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); } } } }
/// <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); }