Skip to content

Active Noise Cancelling Algorithms implementation

License

Notifications You must be signed in to change notification settings

iancraz/ANC-Implementation

 
 

Repository files navigation

Active Noise Cancelling Implementation

Nowadays, active noise cancellation is applied in the most diverse contexts, from industry to medicine and consumer products. This research work refers to the different noise cancellation systems commonly used. In addition, it analyzes the different adaptive algorithms that can be used for the implementation of these systems. The Paper emphasizes the Broadband Feedforward cancellation system both in its practical aspects and in its implementation. Its implementation is explored with the FxLMS algorithms and its recursive FxLMS algorithm variant, FxRLS.

Table of contents

Introduction

Table of contents

Active noise cancellation is a method for the elimination of one wave by the addition of another. It is implemented by means of an electroacoustic or electromechanical system that takes advantage of the phenomenon of destructive interference. To to achieve this, it uses a wave with equal amplitude but inverted phase with respect to the noise wave. Consequently, the combination of both waves results in the cancellation of both noises. As will be discussed later, noise cancellation systems, or ANC, are very effective in eliminating low frequency noise. This led to a great development of this topic in the industry because generally passive noise cancellation systems fail to eliminate low-frequency noise.

Noise can vary in frequency, amplitude, phase, speed of sound and can be caused by an infinite number of sources. This very nature of noise implies that ANC systems must have an adaptive filter that allows modifying to all the above mentioned variables. Adaptive filters adjust their coefficients, generally called "weights", to minimize the error signal. The coefficients can be determined by several algorithms, the most widely used is the least mean squares algorithm or LMS for its acronym in English. In addition, there are other algorithms such as NLMS, FxLMS, FxRLS, etc. These will be discussed later. This type of filters can be performed with finite response filters (FIR) and infinite response filters (IIR). As FIR filters are generally used, this is the type of filter that will be used in this work.

In this research work, noise is defined as any undesirable sound that you want to eliminate, noise generated by machines, ambient noise, conversations in a cafe, etc.. In other words, noise can be generated by any means.

ANC systems can be based on pre-feedback or feedforward, where the reference noise is sampled before it propagates to the second source, or on feedback where the noise is cancelled without a reference. That is, the signal is sampled after the injection of the canceling wave to correct the cancellation error.

Within the feedforward systems are 1 the narrowband systems that will be presented in the section Feedforward and 2) the broadband systems that will be discussed in the section FeedForward Systems. On the other hand, within the feedback systems is the adaptive narrowband system which will be introduced in section NarrowBand FeedBack Systems.

FeedForward Systems

Table of contents

Narrowband Feedforward

In many ANC applications noise signals are periodic. These signals can be generated by machines such as motors, fans, compressors, etc. This system uses the periodicity of these signals to cancel the noise. This type of system has the following advantages:

  • Noise feedback from the noise-cancelling speaker to the reference microphone is avoided.
  • Alignments of the reference microphone are avoided.
  • As it is periodic noise, the causality constraint is eliminated.
  • The possibility of generating reference signals allows to control each harmonic independently.
  • It is only necessary to model the transfer function on frequencies close to that of the harmonics.

A basic diagram of such a system is shown in the previous Figure. The system has a sensor that acts as the trigger of the signal generator. The reference signal generated can be of two types: 1) a pulse train with period equal to the inverse of the fundamental frequency of the periodic noise and 2) sine waves with the same frequencies as the harmonics of the periodic noise. To implement the 1) type the method called wave synthesis is used while for the 2) type an adaptive notch filter is used. No matter what type of reference signal is generated, it is processed by an adaptive filter and sent to the driver. By means of an error signal the adaptive filter is modified (thanks to different algorithms) to minimize the error.

The math details of the calculation of the synthesis method can be found in the Paper.

Broadband FeedForward

The system is illustrated in following Figure. The system has a reference microphone that takes the input signal, the signal is processed by the ANC system that reproduces a signal in the cancellation speaker. It has an error microphone that modifies the behavior of the adaptive filter to minimize the error of the ANC system.

The primary path P(z) is defined as the acoustic path between the coordinates near the reference microphone and the error microphone. There are also two secondary paths from the cancellation speaker to the reference signal S_1(z) on one side and to the error microphone S_2(z) on the other side. The adaptive filter W(z) is used to estimate P(z) to generate a noise cancelling signal.

To clarify the operation of the system, a block diagram of the system, it is illustrated in the following Figure. The error microphone is depicted as the adder module whose input signals are d(n) and y(n). The system seeks to modify W(z) so that y(n) and -d(n) have maximum correlation with each other. If this is achieved, when combining both signals, the residual error is e(n) = d(n) + y(n) = 0 since as they have maximum correlation the output will be white Gaussian noise.

With this block in mind, one can calculate the transfer function of this system, once again found in the Paper.

Finalizing the study of this type of systems it is not superfluous to mention the importance of the processing time. After the reference microphone takes the input signal, the system has a certain time to generate the signal from the cancellation speaker. If the time it takes to generate this signal (electronic delay) is longer than the time it takes for the noise to get from the reference microphone to the driver (acoustic delay), the efficiency of the system is severely impaired. This is because the system response is non-causal when the electronic delay is greater than the acoustic delay. When the causality condition is achieved the system is able to suppress random noises. On the contrary, if the causality condition is not achieved, the system can only eliminate periodic noises. As a last clarification note that this system is not limited to periodic noises, this makes it somehow superior to the previous system. That is why this system has more applications than the Narrowband Feedforward system.

NarrowBand FeedBack Systems

Table of contents

This section introduces the NarrowBand Feedback systems. A one-channel block diagram of a Feedback system is illustrated in the following Figure. The signal acquired by the error microphone is processed by the adaptive filter to generate a signal at the noise-cancelling driver. This type of system synthesizes its own reference signal based only on the input from the adaptive filter and the error signal. That is why the idea is to estimate the primary noise and use it as a reference for the adaptive filter.

Algorithms

Table of contents

For the implementation of adaptive signal filters, a distinction is made between two categories of algorithms used to minimize the quadratic error between the output and the desired result: those that estimate the filter parameters deterministically and those that do so by means of statistical methods.

The former are characterized by high convergence speeds, but at the same time imply high computational capacity requirements: the recursive least squares method (hereafter RLS) is a prominent example of this category. The latter are based on stochastic methods and therefore require fewer resources: the least mean squares method (LMS) and its variants (NMLS, FX-LMS, etc. are examples of this category).

A brief description of the various relevant algorithms is given in the Paper, with emphasis on the stochastic ones, since their computational complexity is relatively low.

Results

Table of contents

To carry out the simulation of a Broadband Feedforward system we assume the following: 1) the path S_1 is not considered, 2) the path S_2 is defined beforehand but an estimate of it is made so hat S_2 or S_2 can be used in the simulation and 3) the adaptive FX-LMS algorithm discussed in section Feedforward is used.

It should be clarified that all simulations are performed using Python programming code. Some parts of the code are shown below, however, all the code can be found in this Jupyter Notebook.

LMS Algorithms

First of all we define the VSNLMS Algorithm as follows:

class VSNLMS:
	def __init__(self, mu, mu_max, mu_min, m0, m1, alpha, delta=0.0):
		"""
		Funcion de inicialización del algoritmo VSNLMS
		@:param mu: Coeficiente de ajuste de paso inicial
		@:param mu_max: Maximo valor del coeficiente de paso (Los coeficientes se van ajustando a medida que se hacen
		iteraciones por el algoritmo VS-LMS)
		@:param mu_min: Mínimo valor del coeficiente de paso
		@:param m0_per: Cantidad de valores de gradiente que deben cambiar de signo para que se ajuste el mu. Esta cantidad
		viene dada porcentualmente del valor de N
		@:param m1_per: Cantidad de valores de gradiente que deben mantener signo para que se ajuste el mu. Esta cantidad
		viene dada porcentualmente del valor de N
		@:param alpha: parametro de ajuste del mu
		@:param delta: delta del algoritmo NLMS, esta puesto para asegurar que en el caso de que el denominador sea nulo no
		explote.
		"""
		self.mu = mu
		self.count_mu_values = 0
		self.mu_max = mu_max
		self.mu_min = mu_min
		self.alpha = alpha
		self.m0 = m0
		self.m1 = m1
		self.prev_sign = 0
		self.delta = delta
		self.prev_grad = []
		return

	def calcNewCoef(self, a_n, signal, error):
		"""
		Funcion que dados unos coeficientes previos, los actualiza correspondientemente
		:param a_n: Coeficientes a actualizar
		:param signal: Vector de señal de entrada
		:param error: Valor del error para actualizar los coeficientes
		:return: Vector de coeficientes actualizados formateados de la misma manera que a_n
		"""
		grad = np.array(signal) * error
		if len(self.prev_grad) != 0:
			if np.sum(np.sign(grad) != self.prev_grad) > self.m0 and self.mu > self.mu_min:
				self.mu /= self.alpha
			elif np.sum(np.sign(grad) == self.prev_grad) > self.m1 and self.mu < self.mu_max:
				self.mu *= self.alpha
		self.prev_grad = np.sign(grad)
		return a_n + self.mu * grad / (np.dot(signal, signal) + self.delta)  # NLMS

	def getMu(self):
		"""
		Funcion para obtener el mu actual del algoritmo
		:return: mu actual.
		"""
		return self.mu

Then once we have created the algorithm to use, we define the adaptative filter:

class AdaptativeFilter:
	def __init__(self, N, mu=1e-3, mu_max=1.1, mu_min=1e-9, m0_per=0.9, m1_per=0.9, alpha=10, delta=0.0):
		"""
		Funcion de inicializacion del filtro adaptativo
		@:param N: Es el orden del filtro
		@:param mu: Coeficiente de ajuste de paso inicial
		@:param mu_max: Maximo valor del coeficiente de paso (Los coeficientes se van ajustando a medida que se hacen
		iteraciones por el algoritmo VS-LMS)
		@:param mu_min: Mínimo valor del coeficiente de paso
		@:param m0_per: Cantidad de valores de gradiente que deben cambiar de signo para que se ajuste el mu. Esta cantidad
		viene dada porcentualmente del valor de N
		@:param m1_per: Cantidad de valores de gradiente que deben mantener signo para que se ajuste el mu. Esta cantidad
		viene dada porcentualmente del valor de N
		@:param alpha: parametro de ajuste del mu
		@:param delta: delta del algoritmo NLMS, esta puesto para asegurar que en el caso de que el denominador sea nulo no
		explote.
		"""
		self.N = N
		self.w = np.random.randn(N)
		self.mu = mu
		m0 = m0_per * N
		m1 = m1_per * N
		self.vsnlms = VSNLMS(self.mu, mu_max, mu_min, m0, m1, alpha, delta)
		self.inp_signal = list(np.zeros(N))
		self.err = 1
		return

	def fit(self, input, desired):
		"""
		Funcion que actualiza los pesos de un filtro adaptativo para que se ajusten a la respuesta deseada.
		@:param input: Vector de entrada al filtro adaptativo
		@:param desired: Vector de señal deseada del filtro adaptativo.
		"""
		self.inp_signal = list(np.zeros(self.N))
		self.err = 1
		for x, d in tqdm(zip(input, desired)):
			self.inp_signal.append(x)
			self.inp_signal.pop(0)
			self.err = d - np.dot(self.inp_signal, self.w)  # Esta definido de esta manera
			self.updateLMS()
		return

	def getFilterParameters(self):
		"""
		Función que devuelve los parámetros del filtro adaptativo
		@:return Los coeficientes del filtro
		"""
		return np.flip(self.w)

	def updateLMS(self):
		"""
		Función que actualiza los coeficientes del filtro adaptativo, utiliza los vectores self.inp_signal, sel.w, y el valor
		self.err
		"""
		self.w = self.vsnlms.calcNewCoef(self.w, self.inp_signal, self.err)
		return

	def getMu(self):
		"""
		Devuelve el Mu actual del filtro adaptativo
		@:return mu Actual
		"""
		return self.vsnlms.getMu()

	def applyFilterSame(self, input):
		"""
		Aplica el filtro adaptativo obtenido a un vector de entrada
		@:param input: vector de entrada para aplicar el filtro. (IMPORTANTE: No actualiza self.inp_signal)
		@:return Vector de salida del filtro.
		"""
		return signal.convolve(input, np.flip(self.w), mode="same")  # No esta chequeado que vaya el modo same

	def applyFilterFull(self, input):
		"""
		Aplica el filtro adaptativo obtenido a un vector de entrada
		@:param input: vector de entrada para aplicar el filtro. (IMPORTANTE: No actualiza self.inp_signal)
		@:return Vector de salida del filtro.
		"""
		return signal.convolve(input, np.flip(self.w), mode="full")  # No esta chequeado que vaya el modo same

	def resetInput(self):
		"""
		Función que borra los datos de self.inp_signal y los setea todos en cero
		"""
		self.inp_signal = list(np.zeros(self.N))
		return

	def applyFilterToTap(self, tap):
		"""
		Funcion que aplica el filtro adaptativo a un solo tap de entrada, utiliza los valores previos guardados en self.inp_signal
		y actualiza ese vector (IMPORTATNE: Actualiza los valores de self.inp_signal)
		@:param tap: Valor del tap de entrada a aplicar el filtro
		@:return Valor de salida del filtro adaptativo
		"""
		self.inp_signal.append(tap)
		self.inp_signal.pop(0)
		temp = self.applyFilterFull(self.inp_signal)
		temp2 = temp[self.N - 1]
		return temp2

	def fitFilterWithErrorTap(self, input_vector, e_tap):
		"""
		Funcion que actualiza los valores de los coeficientes del filtro adaptativo dado un tap de señal de error.
		(IMPORTANTE: La señal self.inp_signal debe estar previamente actualizada al tap de entrada correspondiente a e_tap).
		@:param input_vector: Vector de entrada al filtro para actualizar los coeficientes
		@:param e_tap: Es un tap de la señal de error medida.
		"""
		self.err = e_tap
		self.w = self.vsnlms.calcNewCoef(self.w, input_vector, self.err)
		return

	def fitFilterWithDesired(self,d_tap):
		"""
		Funcion que actualiza los coeficientes del filtro con un tap actual de la señal deseada
		(IMPORTANTE: self.inp_signal debe estar previamente cargada con el tap de entrada actual).
		:param d_tap: tap de la señal deseada
		"""
		self.err = d - np.dot(self.inp_signal, self.w)
		self.updateLMS()
		return

	def setInputVector(self, input):
		"""
		Funcion que setea el input vector desde afuera.
		:param input: Vector de input para actualizar el filtro adaptativo
		"""
		if len(input) != self.N:
			raise Exception(f"No coinciden el tamaño del filtro {self.N} con el input vector metido {len(input)}")
		self.inp_signal = input
		return

And its correspondign Filter class:

class Filter:
	def __init__(self,coefs):
		"""
		Funcion para inicializar el filtro con una lista de coeficientes dada
		:param coefs: Coeficientes del filtro a inicializar deben estar dados de la siguiente manera:
			[w0,w1,w2,w3,..wN]
		"""
		self.coefs = coefs
		return

	def applyFilter(self, input):
		"""
		Funcion para aplicar el filtro a una señal de entrada dada
		:param input: Vector de señal de entrada, con el valor mas reciente ubicado a derecha, y el valor mas viejo a
		izquierda.
		:return: Vector de la señal de salida, filtrada.
		"""
		return signal.convolve(input, self.coefs, mode="full")

	def getFilterLen(self):
		"""
		Funcion que devuelve la cantidad de parámetros del filtro.
		:return:
		"""
		return len(self.coefs)

	def getCoefs(self):
		"""
		Funcion que devuelve una lista con los coeficientes del filtro.
		:return: Lista con los coeficientes del filtro.
		"""
		return self.coefs

In order to perform a simulation of everything discussed above, we must first have the acoustic paths P(z) and S_2(z). For this we make use of the Python library pyroomacoustics which provides a simple way to simulate our system. For the acoustics path P(z) we define it as shown in the following Figure

On the other hand, for the acoustic path S_2(z) an attempt is made to mimic a supraural headphone by defining it as shown in the next Figure.

First, S_2 is simulated to study the FX-LMS algorithm. For the simulation, the LMS algorithm is used in order to approximate in offline mode as best as possible S_hat{S_2}(z) to S_2(z).

The estimation is performed as follows: 1) place x(n) white Gaussian noise at the input of the system in order to best estimate the filter so that there is no predominance at certain frequencies, 2) define S_2 as above, and 3) place an adaptive Wiener filter on S_2. When performing the simulation, S_2 will be gradually modified by minimizing e(n). The simulation is shown in teh next Figure. As can be seen, the error J_s becomes smaller and smaller as time goes by, which means that the adaptive filter becomes more and more similar to what it wants to estimate, in this case S_2.The whole procedure detailed in this paragraph is what is called offline mode in the Paper.

Having the estimate hat S_2 it is possible to simulate the complete system. The test starts with a periodic noise signal. The sound produced in the cockpit of an airplane was selected. The results are shown in the next Figure. The System input signal is the signal that is injected to be nulled, in this case it is the ambient cockpit noise, the Error signal is the resulting error signal e(n) which as stated repeatedly, is expected to tend to 0, and is what the pilot would hear in his ears. As can be seen the system works properly since the signal e(n) tends to decrease the sound quickly, and this translates to the adaptive algorithm being quick to modify the adaptive filter, achieving relative silence in the pilot's ears. In the following Figure it can be observed in a random segment of the signal, how the signal generated by the adaptive filter tries to obtain the maximum correlation with respect to the desired inverted signal.

RLS Algorithms

As with the FX LMS, we first estimated the hat S_2 filter. Finally, we simulated the same environments proposed for the LMS case and arrived at the results shown in the following Figure.

Contact

Table of contents

Please do not hesitate to reach out to me if you find any issue with the code or if you have any questions.

License

Table of contents

MIT License

Copyright (c) 2021 Ian Cruz Diaz

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.