Teensy 4.0 Audio Shield - Line In Microphones

Alfred0

Member
Hello.

I'm working on my final degree thesis, and I'm trying to make an electronic subsystem capable of active noise cancellation.

To achieve it, I'm using two Audio Shield (Rev. D) boards and a Teensy 4.0 connected in Quad Channel mode and I've now two line in inputs and, obviously the line outputs. The main issue is that I wanted the line in for the stereo audio, but I know the microphones need power to work, so I'm think into bridge the MIC point with R and L points of LINE IN to try to get power for the jacks and use the microphones without any external amplifier.

1724004941225.png


The other option I've think is to introduce two of those external amplifier boards and connect them to the 5V of the Teensy board and control the gain with a mixer in the code, but because I'm running out of time with the project, the bridge option sounds very attractive to me.

Thank you in advance for any suggestion and for your time.
Regards.
 
so I'm think into bridge the MIC point with R and L points of LINE IN to try to get power for the jacks and use the microphones without any external amplifier.

This won't work. The line inputs need a signal about 1 volt peak-to-peak. The mic signal is only millivolts. Even for very loud sounds you'll get a basically unusable low signal input.

I'm struggling to understand why you would want to do this? The drawing looks like you're going to connect the mic input to both of the line inputs. But that doesn't make any sense (at least to me). That's the end result if you simply use the built in mic input.
 
Looking at this a bit more.... I'm guessing you actually have 4 separate microphones?

If that's what you're really doing (not actually said in your question) then you really need to build 4 amplifiers to turn each into a proper line level signal. There is no easy shortcut. I know your project is running out of time, but you're only going to waste more of that little remaining time going down a fruitless path if you try to somehow connect 4 mics without 4 separate amplifiers.

Also not mentioned in your question, but guesswork... maybe you have a requirement to physically place the microphones some distance from each other? If that distance is measure in more than inches or centimeters, you'll probably also need to carefully consider shielding. Sending tiny analog signals over distance certainly is possible, but needs to be done carefully to avoid picking up lots of noise.
 
Looking at this a bit more.... I'm guessing you actually have 4 separate microphones?

If that's what you're really doing (not actually said in your question) then you really need to build 4 amplifiers to turn each into a proper line level signal. There is no easy shortcut. I know your project is running out of time, but you're only going to waste more of that little remaining time going down a fruitless path if you try to somehow connect 4 mics without 4 separate amplifiers.

Also not mentioned in your question, but guesswork... maybe you have a requirement to physically place the microphones some distance from each other? If that distance is measure in more than inches or centimeters, you'll probably also need to carefully consider shielding. Sending tiny analog signals over distance certainly is possible, but needs to be done carefully to avoid picking up lots of noise.

No exactly, first of all, thank you very much for your quick response Paul.

I use the Line In because the idea is to have the best sample possible, so how is an electronic subsystem is not strictly necessary to use directly connected microphones, you just need the channels and you are supposed to connect audio from your equipment, because if you're taking the samples from some meters away is better to have a digital sample and then send it to the Teensy, but this works against me in this case, because I can't test some simple sine tones because all I have is two microphones.

I also configure it like Audio USB, so the sample could be send at the same time to one set of speakers and to the Teensy, but the error check microphone still will not work.

The microphones I'm trying to use are some simple lavaliers, but I understand the differences between both connection even if both are a jack, so the two options I have in mind are:

  1. Buying two of this boards I found:
    1724009972787.png

    I think is possible to connect both to the 5V output of the Teensy board and they will sit in between of the Line In and the Jack port.

  2. Change both jacks to the microphone connection in each board and I haven't check it now, but I assume it should work without doing nothing special with the quad channel configuration, and work with those audio samples. The only thing I'm I little bit worried is about the way to solder the stereo jack, I assume I should bridge R and L, but that's another problem.
Thank you again, sorry if this is something a little silly, my degree is in engineering, but my specialty is in mechanic, so I know things, but not as much electronic related knowledge as I would like.
 
Looking at this a bit more.... I'm guessing you actually have 4 separate microphones?
I really didn't answer to this, yes, in practical is like having 4 separate microphones, or 2 stereo (that is the same), but everything points to the use of amplifiers.
 
I really didn't answer to this, yes, in practical is like having 4 separate microphones, or 2 stereo (that is the same), but everything points to the use of amplifiers.

Now I'm really confused. Can you say clearly or with photos and links to tech info exactly what hardware you're really trying to connect?

Really difficult to give answers or even generic advice without knowing what hardware you're really using. It is really 4 mics, or something that isn't 4 actual mics but is somehow like 4 (and how...)
 
I'm sorry, I know you are trying to help me in the best way possible and I don't mean to hinder you.

I will try to be as clear as possible about what I want to do.

To begin with I think it is important to clarify the objective I am looking for. My idea is to build an active noise cancellation system, like the one built into headphones such as the Airpods.

However, the part I want to build is the electronics, what is known as the electronic subsystem, the core that is responsible for processing the noise cancellation.

I don't want to take anything for granted, so I will make the complete explanation, to produce the cancellation of a sound it is necessary to emit the inverse wave, that is a basic principle of physics, but when it is transferred to the real world sounds the thing gets very complicated.

In the earphones it works effectively because the working area is very small. To be able to cancel a sound first it is necessary to know which sound has to be cancelled, so it is necessary to capture it.

As I mentioned, my specialty is not in electronics, and the idea I have behind the project is to make it accessible to anyone without great knowledge in the field, so using Teensy was a very practical solution, as it makes it much easier to develop projects using the Arduino IDE that has been widely used for years in the education of students in high schools, at least here in Spain it is something that is already commonplace.

It's simple and extensively documented, and the Teensy audio shield boards make things much easier.

The basic scheme of what I am trying to do is as shown below ( roughly):

1724020249553.png

*What I am trying to represent with the audio output jack is that the output channels I took were taken as I indicated there, the tip is the left, the ring is the right and the sheath is the ground, not that there are wires connected like that.

The two audio shields are connected in quad channel, they have each Line In, so the four channels, and the sound is routed to both outputs of the shields because I didn't bridge the pin 7 with pad 32 of the Teensy, because I didn't need 4 channels for the output. The channels are connected as shown in the scheme.

On one side we have a stereo audio source, the signal is taken, inverted (with the mixer gain as -1) and emitted to cancel the sound.

On the other hand we have another stereo audio source, it is the one that has to pick up silence, which indicates that the cancellation has been effective. If it is not, we work with that signal and the original one to correct it and achieve an effective cancellation signal.

Audio sources are literally that, sources with a left channel and a right channel.

The way to capture that information is somewhat indifferent, the most obvious is to use a microphone, but microphones are mono, they only have one channel, so technically you would be capturing either the sound of the right channel or the left channel.

If I have not understood incorrectly, a stereo microphone is actually composed of two microphones, one captures what would be corresponding to the left channel and another corresponding to the right channel.

Then, as what I need to perform the cancellation is a sample of the left and right channel of the sound to be cancelled, for example, a 200 Hz sine tone, it is somewhat indifferent how to “capture” this sound, it can be recorded with a microphone, it can be an mp3 file and can be played directly on the Teensy via USB, etc...

That's why I decided to use the line inputs, but I didn't take into account that the line inputs are not capable of feeding a condenser microphone like the ones I usually use, specifically this one in the image:

1724020784270.png

It hasn't any technical specifications like is impedance, just is described as a microphone.

Okay, so, if I have not misunderstood how the microphone inputs work, in order to “hear” the sounds it picks up, it is necessary to provide it with power, that is why the Mic Line is supplied with about ~2V (usually) on its positive connection, which is the MICBIAS, but the Line In inputs expect to receive much more powerful signals, which is just what you were telling me about earlier, so they do not supply voltage to either the R channel or the L channel.

In order to capture the sound of both channels, it would be necessary to use two microphones, one for the R channel, and another for the L channel, that is what you were telling me when you referred to the fact that I have to use 4 separate microphones each one with its amplifier:

I know your project is running out of time, but you're only going to waste more of that little remaining time going down a fruitless path if you try to somehow connect 4 mics without 4 separate amplifiers.

Reading the schematic of the audio board I realized that the MICBIAS reaches the MIC connection point, that's why I thought that it might not be necessary to introduce any amplifier between each LINE IN channel and each microphone if I made a bridge between MIC, R and L, and that was my main doubt, since if that is not feasible what I understand is that I have no choice but to introduce an amplifier in between.


The attached image is a simple amplifier that I found on Amazon that serves to preamplify microphones (that what the title says), according to the technical specifications can be feed with a DC voltage whose value can be between 3.8V and 15V, and uses as is indicated an operational amplifier AD828 and is suitable for two channels, R channel and L channel.

Given the low voltage required I understand that I can supply 5V from the Teensy board connection to both amplifier boards if it is necessary to use them, but of course, if it is possible to supply them with power from MIC and it is adequate, then I would not have to introduce those amplifiers.

I am sorry for the length of my explanation, I hope I have been able to provide you with enough information on this occasion to make it easier to understand what my objective is.

I just wanted to avoid having to use additional amplifiers in order to keep the cost low and the package as compact as possible.

Overall, thank you very much for everything, just the fact that Teensy exists has given me the opportunity to work on a project that I am really motivated just for closing my studies.
 
There are two main problems with that preamp board:
1. Lack of biasing resistors for the electret capsule. They can be added externally, like this:
ElectretMic_SGTL5000.gif
Looking at the preamp board pics the gain is set to about 9x (30C=20K / 2K2), inverting configuration.
2. The input impedance will be set with the input 2K2 resistor in parallel to the 10k and it's a bit too low for an electret mic. The impact might be from making the mic output even lower (due to loading) to distorting the audio signal.
The preamp board is advertised as a dynamic mic preamp, hence the lower input Z value. Ideally the resistor values should be increased 10x (22K input one, 200K feedback).

The SGTL5000 codec chip used in the Audio board has a a variable input gain - this is another point which potentially could help to find a compromise between using a ready made products and a signal quality.
For start i'd try that configuration, play a sine wave into the mic, observe the output signal on the PC side (via usb audio) and try to find a gain value that gives the best cleanest results.

Noise might a problem, too. Not the ambient noise, which is the main topic, but the USB power noise. I added a small RC filter for the MIC bias supply, the preamp board has a 100uF power decoupling cap, this will help, too.

If the overall gain is too high, there are pads for the feedback resistors on the board - adding another resistor in parallel ther will lower the gain.

Finally, why you can't just run the "Mic Power" wires to the Line inputs. This is not a "Mic Power". There is a 2K2 reistor (or 3K3 on my schematic) which is a biasing resistor for the internal FET transistor that live inside the microphone capsule. Something like this:
ElectretMic_int.gif
Modding the Audio board to provide the bias supply for two mics would look like this:
AudBoart_mod.jpg
With that, plus maxed gain setting for the Line inputs (in software), this might sort of work.
I'm not sure if the resulting signal quality will be enough for a task that is noise cancelling.
 
There are two main problems with that preamp board:
1. Lack of biasing resistors for the electret capsule. They can be added externally, like this:
View attachment 35512
Looking at the preamp board pics the gain is set to about 9x (30C=20K / 2K2), inverting configuration.
2. The input impedance will be set with the input 2K2 resistor in parallel to the 10k and it's a bit too low for an electret mic. The impact might be from making the mic output even lower (due to loading) to distorting the audio signal.
The preamp board is advertised as a dynamic mic preamp, hence the lower input Z value. Ideally the resistor values should be increased 10x (22K input one, 200K feedback).

The SGTL5000 codec chip used in the Audio board has a a variable input gain - this is another point which potentially could help to find a compromise between using a ready made products and a signal quality.
For start i'd try that configuration, play a sine wave into the mic, observe the output signal on the PC side (via usb audio) and try to find a gain value that gives the best cleanest results.

Noise might a problem, too. Not the ambient noise, which is the main topic, but the USB power noise. I added a small RC filter for the MIC bias supply, the preamp board has a 100uF power decoupling cap, this will help, too.

If the overall gain is too high, there are pads for the feedback resistors on the board - adding another resistor in parallel ther will lower the gain.

Finally, why you can't just run the "Mic Power" wires to the Line inputs. This is not a "Mic Power". There is a 2K2 reistor (or 3K3 on my schematic) which is a biasing resistor for the internal FET transistor that live inside the microphone capsule. Something like this:
View attachment 35513
Modding the Audio board to provide the bias supply for two mics would look like this:
View attachment 35515
With that, plus maxed gain setting for the Line inputs (in software), this might sort of work.
I'm not sure if the resulting signal quality will be enough for a task that is noise cancelling.

So, the easiest way to approach this would be to use a "good" external amplifier, I mean, anything better than the boards I'm finding around.

For example, I could connect the microphones to the computer, route to outputs and connect it with a simple line cable with 3.5mm to 3.5mm male jack connectors.

So, in case I want to use the "MicPower" the BIAS is necessary (if I'm understanding it correctly) to ensure the stable flow to the microphone, so as i need one per channel and I only have one 2k2 resistor, is needed to short the one in the board and use one per channel.

That is what I was thinking, but my doubts were the resistors role, and as you, how will affect to the quality, but thanks to your schematic is something "simple" to test without messing the things, If I've understand correctly, I can just bridge Mic with one channel and if that works, mod it for two channels.

I'll love to share the results of this work once is finish for anybody that could want to build something similar, I think that if it works as expected could be a great solution for some annoying situations with noise.

Thank you both for your clear explanations and patience.
 
Using external amplifier boards would be the easiest way to connect each microphone to one of line inputs makes sense.

I am curious: Have you an idea how to deal with the latency the signal needs from the analog input through AD, processing and the output signal? What exactly is the application scenario? Headphones...?
 
Using external amplifier boards would be the easiest way to connect each microphone to one of line inputs makes sense.

I am curious: Have you an idea how to deal with the latency the signal needs from the analog input through AD, processing and the output signal? What exactly is the application scenario? Headphones...?
So, short answer: praying

The long one, I think the latency isn't going to be the biggest problem because the point where the cancellation should take place will be enough further to give some room to processing all.

The idea is to demonstrate that is possible to build something functional that is affordable and could be use by anybody, not just in industrial environments.

The main problem right now is the FIR filter, I'm trying to test the system with a simple sine tone, but I think the actual FIR filter is not capable of do what I need, so I find this project:

Teensy FFT Convolution Filter

But understanding the process is such a big work (for me), and if I didn't implement it properly this will not work.

The real latency that is worrying me is the process of the data, because I think the first I need to do is to convert the data from the audio input with Fourier to arrays, then use that data with the convolution filter and apply it to the audio channels that output from the mixer inverted.

1724243055229.png

So right now the scheme is something like this, and the convolution filter replaces each FIR filter. Once I understand how this filter works, I should take the data from the i2s_quad1 channels #3 and #4 and as I mention, use some fft1024 for each one and take those to the fir1 and fir2 that now will be convolution1 and convolution2.

I don't know really anything right now, I need first to solve this and later I'll worry more if is too much latency.

The purpose is just to be a subsystem that you could connect in your house to one speaker set and with two sources cancel any disturbing noises, for example, the sound of an air conditioning machine on the other side of the street, something like that. Is not for an specific use, just a proof of concept, if it works with the sine tone, later anybody with more enthusiasm and knowledge could improve the system for other purposes.
 
Well, to keep continuity with the theme, I don't know if I'm using the FIR filter wrong, but there is no sound at all, it's like a dam for the sound.

I've been thinking about using part of the idea of the convolution code I mentioned here
Teensy FFT Convolution Filter
to do the signal calculations based on the Least Mean Square (LMS) algorithm, but the thing is that I don't know what exactly will happen with the filter that the signal is simply null.

I've been thinking about using fft1024 blocks so that I can have arrays of data to operate on, but I'm not 100% sure exactly if it will work either:

1724404617855.png


Is there by any chance some more documentation on how the FIR filter works in Teensy? Apart from what is in the Audio System Design Tool.

The code I'm trying right now is like this:


#include <Audio.h> #include <Wire.h> #include <SPI.h> #include <SD.h> #include <SerialFlash.h> #include <arm_math.h> #include <arm_const_structs.h> #include <filter_convolution.h> #define BUFFER_SIZE 128 #define FFT_SIZE 1024 #define MAX_NUMCOEF 513 float MU = 0.01; // Learn rate for LMS // GUItool: begin automatically generated code AudioInputUSB usb1; //xy=346,255 AudioInputI2SQuad i2s_quad1; //xy=353,312 AudioAnalyzeFFT1024 fft1024_1; //xy=626,330 AudioAnalyzeFFT1024 fft1024_2; //xy=627,365 AudioMixer4 mixer1; //xy=628,207 AudioMixer4 mixer2; //xy=629,276 AudioFilterFIR firFilter_Left; //xy=769,220 AudioFilterFIR firFilter_Right; //xy=771,270 AudioAnalyzeFFT1024 fft1024_3; //xy=892,161 AudioAnalyzeFFT1024 fft1024_4; //xy=897,327 AudioOutputI2S i2s1; //xy=953,244 AudioConnection patchCord1(usb1, 0, mixer1, 0); AudioConnection patchCord2(usb1, 1, mixer2, 0); AudioConnection patchCord3(i2s_quad1, 0, mixer1, 1); AudioConnection patchCord4(i2s_quad1, 1, mixer2, 1); AudioConnection patchCord5(i2s_quad1, 2, fft1024_1, 0); AudioConnection patchCord6(i2s_quad1, 3, fft1024_2, 0); AudioConnection patchCord7(mixer1, firFilter_Left); AudioConnection patchCord8(mixer2, firFilter_Right); AudioConnection patchCord9(firFilter_Left, 0, i2s1, 0); AudioConnection patchCord10(firFilter_Left, fft1024_3); AudioConnection patchCord11(firFilter_Right, 0, i2s1, 1); AudioConnection patchCord12(firFilter_Right, fft1024_4); AudioControlSGTL5000 sgtl5000_1; //xy=632,429 AudioControlSGTL5000 sgtl5000_2; //xy=632,464 // GUItool: end automatically generated code float vol = 0.5; float32_t FIR_Coef_Left[MAX_NUMCOEF]; // Coeff FIR filter left channel float32_t FIR_Coef_Right[MAX_NUMCOEF]; // Coeff FIR filter right channel float32_t fft_input_left[FFT_SIZE]; // Buffer left channel float32_t fft_input_right[FFT_SIZE]; // Buffer right channel float32_t fft_output[FFT_SIZE]; // Output buffer for FFT float32_t error_signal_left; // Error signal for left channel float32_t error_signal_right; // Error signal for right channel int16_t FIR_Coef_Left_int[MAX_NUMCOEF]; // Coeff FIR filter for left channel in int16_t int16_t FIR_Coef_Right_int[MAX_NUMCOEF]; // Coeff FIR filter for right channel in int16_t void setup() { Serial.begin(115200); AudioMemory(12); sgtl5000_1.setAddress(LOW); sgtl5000_1.enable(); sgtl5000_1.inputSelect(AUDIO_INPUT_LINEIN); sgtl5000_1.volume(vol); sgtl5000_2.setAddress(HIGH); sgtl5000_2.enable(); sgtl5000_2.inputSelect(AUDIO_INPUT_LINEIN); sgtl5000_2.volume(vol); mixer1.gain(0, -1.0); mixer1.gain(1, -1.0); mixer2.gain(0, -1.0); mixer2.gain(1, -1.0); pinMode(4, INPUT_PULLUP); pinMode(5, INPUT_PULLUP); } void loop() { // Obtener la señal de error de las salidas de FFT if (fft1024_1.available() && fft1024_2.available()) { // Initialize error signals float32_t error_signal_left = 0.0f; float32_t error_signal_right = 0.0f; // Initialize float coeff init_FIR_coeffs(FIR_Coef_Left, MAX_NUMCOEF); init_FIR_coeffs(FIR_Coef_Right, MAX_NUMCOEF); // Fill fft_input buffers for (int i = 0; i < FFT_SIZE; i++) { float32_t mic_left = fft1024_1.read(i); float32_t mic_right = fft1024_2.read(i); float32_t output_left = fft1024_3.read(i); float32_t output_right = fft1024_4.read(i); // Error signal calculation error_signal_left += mic_left - output_left; error_signal_right += mic_right - output_right; // Fill of fft_input fft_input_left[i] = mic_left; fft_input_right[i] = mic_right; } // Averaging error signals error_signal_left /= FFT_SIZE; error_signal_right /= FFT_SIZE; // Update of FIR filter coeff update_FIR_coeffs(FIR_Coef_Left, fft_input_left, error_signal_left, MAX_NUMCOEF); update_FIR_coeffs(FIR_Coef_Right, fft_input_right, error_signal_right, MAX_NUMCOEF); // Coeff conversion to int16_t for (int i = 0; i < MAX_NUMCOEF; i++) { FIR_Coef_Left_int[i] = static_cast<int16_t>(FIR_Coef_Left[i] * 32767); // Escalar si es necesario FIR_Coef_Right_int[i] = static_cast<int16_t>(FIR_Coef_Right[i] * 32767); // Escalar si es necesario } // Initialize FIR filters with converted coeff firFilter_Left.begin(FIR_Coef_Left_int, MAX_NUMCOEF); firFilter_Right.begin(FIR_Coef_Right_int, MAX_NUMCOEF); } // Encoder mu to change de learn rate if (digitalRead(4) == LOW) { MU += 0.05; delay(250); } if (digitalRead(5) == LOW) { if (MU > 0.01) { MU -= 0.05; delay(250); } } } // Auxiliar functions void init_FIR_coeffs(float32_t *coeffs, int numCoeffs) { for (int i = 0; i < numCoeffs; i++) { coeffs[i] = 0.0f; // Initialize coeff as zero } } void update_FIR_coeffs(float32_t *coeffs, float32_t *input, float32_t error, int numCoeffs) { for (int i = 0; i < numCoeffs; i++) { coeffs[i] += MU * error * input[i]; } }


At this point, any suggestion that can guide me to a solution is more than welcome.

If you have any questions feel free to ask.
Thank you for your time.
 
Normally you would initialize the FIR coefficients once in setup(). I don't understand what you're trying to accomplish with changing the filter response inside loop(), but from a troubleshooting perspective I'd recommend first using just a simple fixed filter response so you can confirm the filters really are working.
 
Normally you would initialize the FIR coefficients once in setup(). I don't understand what you're trying to accomplish with changing the filter response inside loop(), but from a troubleshooting perspective I'd recommend first using just a simple fixed filter response so you can confirm the filters really are working.
Ok, that's right.

I need to update the coefficients in real time because they have to adapt to the changes in the reference signal that I'm trying to cancel, so that's why I want to change the filter.

I think there's an example of FIR in the Arduino IDE, I'll check it to make something similar and test.

Thank you. 😊
 
Good morning.

First, I've learn one big issue, is obvious, but I didn't realize until now, I should define the array as int16_t to be properly used in the FIR filter module.

So I comment the begin() from the loop and initialize this in setup():

// Debugging int16_t FIR_Coef_Deb[numCoeffs] = {1, 1, 1, 1, 1, 1, 1, 1}; firFilter_Left.begin(FIR_Coef_Deb, numCoeffs); firFilter_Right.begin(FIR_Coef_Deb, numCoeffs);

The scheme is still this one:

So, if I'm using all the coefficients as 1 and if I've not misunderstand how it works, I should hear any sound from usb1 or i2s_quad1, but is not working, the output has like some residual sound but very very very low volume, is like some vinyl crisp, but no sound.

Any idea of what should be happening?
 
Last edited:
Good morning.

First, I've learn one big issue, is obvious, but I didn't realize until now, I should define the array as int16_t to be properly used in the FIR filter module.

So I comment the begin() from the loop and initialize this in setup():

// Debugging int16_t FIR_Coef_Deb[numCoeffs] = {1, 1, 1, 1, 1, 1, 1, 1}; firFilter_Left.begin(FIR_Coef_Deb, numCoeffs); firFilter_Right.begin(FIR_Coef_Deb, numCoeffs);

The scheme is still this one:


So, if I'm using all the coefficients as 1 and if I've not misunderstand how it works, I should hear any sound from usb1 or i2s_quad1, but is not working, the output has like some residual sound but very very very low volume, is like some vinyl crisp, but no sound.

Any idea of what should be happening?

Update:

I change

firFilter_Left.begin(FIR_PASSTHRU, numCoeffs); firFilter_Right.begin(FIR_PASSTHRU, numCoeffs);

Just to directly pass the input to output as the description says, but is still not working, I'm very confused right now.
 
The coefficients are fixed point, not integer, the entire audio library works with q15_t style fixed point in fact, where 1.0 is represented by 0x7FFF, not 1.
Under the hood the heavy lifting is done by the CMSIS DSP function 'arm_fir_fast_q15'
 
The coefficients are fixed point, not integer, the entire audio library works with q15_t style fixed point in fact, where 1.0 is represented by 0x7FFF, not 1.
Under the hood the heavy lifting is done by the CMSIS DSP function 'arm_fir_fast_q15'

Thank you for this information MarkT, it has been very useful, but right now I'm very lost with this, I have spent all week trying to get it to work in different ways and it does nothing.

This is what I was thinking that will work, but even making the mixers and amps just 1.0 to be a passthrough and starting the FIR filters as PASSTHRU for testing if any sound that enter is capable of exit, is just not working, and I'm done with this until I don't get the filter working.

#include <_Teensy.h> #include <Audio.h> #include <Wire.h> #include <SPI.h> #include <SD.h> #include <SerialFlash.h> #include <arm_math.h> #include <arm_const_structs.h> #include <Encoder.h> #define FFT_SIZE 511 float MU = 0.01; // Tasa de aprendizaje // GUItool: begin automatically generated code AudioInputI2SQuad i2s_quad1; //xy=360.2727355957031,303.8181953430176 AudioInputUSB usb1; //xy=368.72727966308594,224.9999942779541 AudioMixer4 mixer1; //xy=595.2727127075195,201.54543685913086 AudioMixer4 mixer2; //xy=595.3636436462402,326 AudioAmplifier amp_left; //xy=733,228 AudioAmplifier amp_right; //xy=733,291 AudioAnalyzeFFT1024 fft1024_1; //xy=739.8182373046875,171.36367797851562 AudioAnalyzeFFT1024 fft1024_2; //xy=740.1818237304688,346.45458984375 AudioFilterFIR firFilter_Right; //xy=878.0908966064453,291.6363639831543 AudioFilterFIR firFilter_Left; //xy=878.8181610107422,228.00000190734863 AudioAnalyzeFFT1024 fft1024_5; //xy=886,172 AudioAnalyzeFFT1024 fft1024_6; //xy=888,350 AudioOutputI2S i2s1; //xy=1035.5454711914062,253.8182029724121 AudioAnalyzeFFT1024 fft1024_4; //xy=1041.363540649414,349.5454730987549 AudioAnalyzeFFT1024 fft1024_3; //xy=1042.7273483276367,175.36364269256592 AudioConnection patchCord1(i2s_quad1, 0, mixer1, 1); AudioConnection patchCord2(i2s_quad1, 1, mixer2, 1); AudioConnection patchCord3(usb1, 0, mixer1, 0); AudioConnection patchCord4(usb1, 1, mixer2, 0); AudioConnection patchCord5(mixer1, amp_left); AudioConnection patchCord6(mixer1, fft1024_1); AudioConnection patchCord7(mixer2, amp_right); AudioConnection patchCord8(mixer2, fft1024_2); AudioConnection patchCord9(amp_left, fft1024_5); AudioConnection patchCord10(amp_left, firFilter_Left); AudioConnection patchCord11(amp_right, firFilter_Right); AudioConnection patchCord12(amp_right, fft1024_6); AudioConnection patchCord13(firFilter_Right, 0, i2s1, 1); AudioConnection patchCord14(firFilter_Right, fft1024_4); AudioConnection patchCord15(firFilter_Left, 0, i2s1, 0); AudioConnection patchCord16(firFilter_Left, fft1024_3); AudioControlSGTL5000 sgtl5000_1; //xy=604.7272644042969,249.00001621246338 AudioControlSGTL5000 sgtl5000_2; //xy=604.7272338867188,280.3636484146118 // GUItool: end automatically generated code float vol = 0.5; const int16_t numCoeffs = 8; double FIR_Coef_Left[numCoeffs]; // Coeficientes del filtro FIR para el canal izquierdo en double double FIR_Coef_Right[numCoeffs]; // Coeficientes del filtro FIR para el canal derecho en double double fft_input_left[FFT_SIZE]; // Buffer para el canal izquierdo de entrada al sistema double fft_input_right[FFT_SIZE]; // Buffer para el canal derecho de entrada al sistema double fft_output_left[FFT_SIZE]; // Buffer para el canal izquierdo de salida al control double fft_output_right[FFT_SIZE]; // Buffer para el canal derecho de salida al control double fft_filter_left[FFT_SIZE]; // Buffer para el canal izquierdo de entrada al filtro FIR double fft_filter_right[FFT_SIZE]; // Buffer para el canal derecho de entrada al filtro FIR double error_signal_left[FFT_SIZE]; // Señal de error para el canal izquierdo double error_signal_right[FFT_SIZE]; // Señal de error para el canal derecho short FIR_Coef_Left_int[numCoeffs]; // Coeficientes del filtro FIR para el canal izquierdo como short short FIR_Coef_Right_int[numCoeffs]; // Coeficientes del filtro FIR para el canal derecho como short Encoder encoder(4, 5); // Inicio el encoder con sus pines correspondientes void setup() { Serial.begin(115200); AudioMemory(12); sgtl5000_1.setAddress(LOW); sgtl5000_1.enable(); sgtl5000_1.inputSelect(AUDIO_INPUT_LINEIN); sgtl5000_1.volume(vol); sgtl5000_2.setAddress(HIGH); sgtl5000_2.enable(); sgtl5000_2.inputSelect(AUDIO_INPUT_LINEIN); sgtl5000_2.volume(vol); // Se configuran los mixer para que sirvan de punto de unión de ambas entradas para cada canal mixer1.gain(0, 1.0); mixer1.gain(1, 1.0); mixer2.gain(0, 1.0); mixer2.gain(1, 1.0); // Se configuran los amplificadores para que inviertan la señal amp_left.gain(1.0); amp_right.gain(1.0); // Inicializo los pines del encoder pinMode(4, INPUT_PULLUP); pinMode(5, INPUT_PULLUP); // Debugging //q15_t FIR_Coef_Deb[numCoeffs] = {0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF}; firFilter_Left.begin(FIR_PASSTHRU, 0); firFilter_Right.begin(FIR_PASSTHRU, 0); // Inicializar los coeficientes en punto flotante init_FIR_coeffs(FIR_Coef_Left); init_FIR_coeffs(FIR_Coef_Right); } void loop() { // Obtener la señal de error de las salidas de FFT // Llenar los buffers fft_input y calcular las señales de error for (int i = 0; i < FFT_SIZE; i++) { double mic_left = fft1024_1.output[i]; double mic_right = fft1024_2.output[i]; double filter_left = fft1024_5.output[i]; double filter_right = fft1024_6.output[i]; double output_left = fft1024_3.output[i]; double output_right = fft1024_4.output[i]; // Llenar los buffers fft_input fft_input_left[i] = mic_left; fft_input_right[i] = mic_right; // Llenar los buffers fft_filter fft_filter_left[i] = filter_left; fft_filter_right[i] = filter_right; // Llenar los buffers fft_output fft_output_left[i] = output_left; fft_output_right[i] = output_right; // Calcular las señales de error error_signal_left[i] = fft_input_left[i] - fft_output_left[i]; error_signal_right[i] = fft_input_right[i] - fft_output_right[i]; } // Actualizar los coeficientes del filtro FIR update_FIR_coeffs(FIR_Coef_Left, fft_filter_left, error_signal_left); update_FIR_coeffs(FIR_Coef_Right, fft_filter_right, error_signal_right); // Transformo los coeficientes para poder utilizarlos en el filtro FIR transformCoeffs(FIR_Coef_Left_int, FIR_Coef_Left, numCoeffs); transformCoeffs(FIR_Coef_Right_int, FIR_Coef_Right, numCoeffs); // Inicializar los filtros FIR con los coeficientes convertidos //firFilter_Left.begin(FIR_Coef_Left_int, numCoeffs); //firFilter_Right.begin(FIR_Coef_Right_int, numCoeffs); // Encoder MU encoderFN(); } // Funciones auxiliares //void transformCoeffs( short int out[], double in[], int k ) //{ // for ( int i = 0 ; i < k ; i++ ) // out[i] = 32768 * in[i]; //} void transformCoeffs( short out[], double in[], int k ) { for ( int i = 0 ; i < k ; i++ ) out[i] = int16_t(in[i] * 0.00003051850948 * 0x8000) + 0.5; } void init_FIR_coeffs(double coeffs[]) { for (int i = 0; i < numCoeffs; i++) { coeffs[i] = 0.0; // Inicializa los coeficientes a 0 } } void update_FIR_coeffs(double coeffs[], double input[], double error[]) { for (int i = 0; i < numCoeffs; i++) { coeffs[i] += (MU * error[i] * input[i]); // Actualiza los coeficientes del filtro según la función Lean Mean Square } } void encoderFN() { //if the button is pressed int i = 0; i = i + encoder.read(); if (i <= -4){ MU += 0.05; encoder.write(0); }else if (i >= 4){ if (MU > 0.01) { MU -= 0.05; } encoder.write(0); } }

I mean, my code could be wrong, and it will be a lot until I work deep in it, but I think that a simple test where all is in passthrough should work, and it is not.

The hardware is correctly connected, I make previously two simple tests, one with all the inputs routed with mixers to outputs, and all sounds fine, but in the second test, when I introduce the FIR filter into the system it gets no output.

Is it messing around with some common pin for quad channel or something?

I really don't know what is going so wrong here, I don't discard that maybe it's a skill issue, but the only thing I know is that if I put a filter, it doesn't work.

If you find something that can be of help, I will be very grateful, I will keep trying, but I doubt I can do much more, except to learn how to hard code a FIR filter manually.
 
Ok, update, I've found the issue.

If I use any FFT the sound is destroyed, so I have to find a way to convert the analog input signals to digital, and operate them to get the coefficients of the fir filters, I thought the fft1024 blocks would be the way, but no, I guess the level of demand to process it is too high.

Thank you all for your help, it has helped me to understand other concepts that were not clear to me about the operation of FIR filters.
 
Perhaps go back to basics with the FIR filter example?
Oh, I mean, if I use the FIR filter example, all is working, if I use the FIR filter as I intended, now is also working, but my new issue is how am I supposed to convert the input and output signal to numbers in order to recalculate the filter impulse coefficients in real time.

1725189705820.png

In my actual test code I've this distribution, but I need to convert the analog signal from mixer outputs and the analog signal from fir outputs to some actual numbers to work with.

I used fft1024 because it looked easy, but it wasn't because the system didn't work.

I've seen that there's is some ADC blocks, but the can't be use as I need, so I need a way to convert the analog signal into an array of data, operate it, update the FIR coefficients and pray for latency.

I'm sure that if I use some pre-calculated coefficients and make some adjustments, it should work, I don't know how well for it purpose, but should work, but the idea is that should be capable to adapt to the changes of the sound, so if I can´t complete it in that way I'll have not achieve all the objetives of my work.
 
but I need to convert the analog signal from mixer outputs

You have 2 options.

#1: Use the queue objects to gain access to the mixer output data. This way to can put the analysis code into your program. But you do have to manage the buffers in your program, which certainly is do-able but requires careful programming.

#2: Create a new object within the library that does your analysis. As with creating any new objects in the library, copy the template or any of the existing code, and then put your code into the update() function which gets call when new data is ready. Then you custom object could make the results available to your program, like the other analysis objects do.

Either way, you will need to craft code which takes the raw audio data and computes the FIR filter response. Do you already have an algorithm?
 
You have 2 options.

#1: Use the queue objects to gain access to the mixer output data. This way to can put the analysis code into your program. But you do have to manage the buffers in your program, which certainly is do-able but requires careful programming.

#2: Create a new object within the library that does your analysis. As with creating any new objects in the library, copy the template or any of the existing code, and then put your code into the update() function which gets call when new data is ready. Then you custom object could make the results available to your program, like the other analysis objects do.

Either way, you will need to craft code which takes the raw audio data and computes the FIR filter response. Do you already have an algorithm?

Thanks for your answer.

Regarding to option 1, I've seen that there was a queue block, but having to analyze three different points of the flow per channel, which means six in total, I think it's going to be a big problem in terms of latencies because I have to control a lot of things.

On the other hand, the second option seems interesting to me, the doubt I've got is exactly the code you make reference to, I think you are referring to if I've got the code that generates the new coefficients for the FIR filter.

If it's that code, yes, I've not written the code as such because I've had to do a lot of tests these weeks, but the algorithm that I've to implement is the Lean Mean Square (LMS), because I just want to demonstrate a basic operation of noise cancellation.

This algorithm multiplies the values of the signal entering the filter shifted one position by the values of the error signal and by the learning rate, usually known as µ (mu in the code).

So I would need to make a loop that goes through all the values of the error signal array and the reference signal and multiply it by that value µ.

Each value for the error signal is obtained by:

e(k)=d(k)-y(k);

Where d(k) should be the original signal that I want to cancel, so this is obtained from the mixer output, and y(k) is the resulting signal from the FIR filter, so is obtained after the FIR filter.

The new coefficients for the FIR filter will then result of:

w(k)=w(k)+mu*e(k)*xk(k);

xk(k) is the signal that enters to the FIR filter, so is obtained at that point, and their values are shifted to be the "x" precedent ones where "x" is the same as the length of the coeficientes w array.

In fact, if I am not mistaken, the signal xk of shifted values corresponds to the one used by the FIR filter itself to perform the convolution with the coefficients, so technically this signal should already exist as an array even if I do not have access to it.

I think the error signal is also modified by the error microphone that I've to use in the second Line In input, but I've not checked it yet, because as I said I've been very focus into making it sound first.

That's all I know about the LMS algorithm and how it modifies the FIR coefficients values.

Thank you again for your time.
 
Where d(k) should be the original signal that I want to cancel, so this is obtained from the mixer output
Sorry, this is a mistake, d(k) is the signal measured at the point where I want the cancellation to be done, so it's the input from the second Line In, because it is measure with the microphone.

The rest of terms are properly label, y(k) is the output and x(k) is the input signal to treat with the FIR filter to cancel d(k).

Thank you for all your help, right now I'm going to try to measure things outside the Teensy to use a predefined coefficients and build an FXLMS system fixed instead of adaptive, and if it works, in the future I'll try again the adaptive part.
 
Back
Top