Biquad-filter low corner frequency test-sketch

Status
Not open for further replies.

AdaZus

Member
For those which are interested in Biquad filter…
Here is a testsketch with low corner frequency:

Code:
/*
[url]https://www.pjrc.com/teensy/gui/index.html?info=AudioFilterBiquad[/url]
Biquad filters test with low corner frequency @ Teensy 3.6. 
Try out following sketch.
*/

#include <Audio.h>
#include <Wire.h>
#include <SPI.h>
#include <SD.h>
#include <SerialFlash.h>

// GUItool: begin automatically generated code
AudioInputI2S            i2s1;           //xy=105,240
AudioAmplifier           amp1;           //xy=264,226
AudioFilterBiquad        biquad1;        //xy=441,226
AudioAnalyzePeak         peak1;          //xy=621,226
AudioConnection          patchCord1(i2s1, 0, amp1, 0);
AudioConnection          patchCord2(amp1, biquad1);
AudioConnection          patchCord3(biquad1, peak1);
AudioControlSGTL5000     sgtl5000_1;     //xy=362,332
// GUItool: end automatically generated code

elapsedMillis msecs;

//Tones and frequencies
float C = 65.40;
float CIS = 69.29;
float D = 73.41;

float GIS = 103.82;
float A = 110;
float AIS = 116.54;
//Tones and frequencies


void setup() {

  Serial.begin(9600);
  
  AudioMemory(30);
  sgtl5000_1.enable();
 
  // MicIn
  sgtl5000_1.inputSelect(AUDIO_INPUT_MIC); 
  sgtl5000_1.micGain(50); // sgtl5000_1.micGain(30); original
  amp1.gain(0); //MicIn (i2s1) gain (again)
  //MicIn
  
  delay(1000);
}

      
void loop() {
    
    // Filter 
    //File > Examples > Audio > Effects > Filter
    // Butterworth filter, 12 db/octave
    // biquad1.setLowpass(0, 700, 0.707);
    
    // Linkwitz-Riley filter, 48 dB/octave
     biquad1.setBandpass(0, CIS, 15);
     biquad1.setBandpass(1, CIS, 15);
     biquad1.setBandpass(2, CIS, 15);
     biquad1.setBandpass(3, CIS, 15);
     // Filter 

      amp1.gain(0.9); // to ajusd MicIn(i2s1)-gain: Filters must have their input signals attenuated, so the signal does not exceed 1.0 (or 2 if measured peak to peak).
       
       // Amplitude to serial monitor
       if (msecs > 100) {
       if (peak1.available() ) { //&& peak2.available() commented out...only Mono needed.
       msecs = 0;
       float leftNumber = peak1.readPeakToPeak();
       //float rightNumber = Peak.read();
       Serial.println(leftNumber); //left channel
       //Serial.println();
       // Amplitude to serial monitor
        }
       }
}


The amplitude-difference (peak to peak) between the filtered tone and one halftone under and over is as follows:

103.82Hz: 0.13V
Filtered tone= 110Hz: 1.95V Amplitude
116.54Hz: 0.13V
Difference 1.82V

65.4Hz: 0.12V
Filtered tone= 69,29Hz: 1.89V Amplitude
73.41Hz: 0.12V
Difference 1.77V


Despite of written in notes @ https://www.pjrc.com/teensy/gui/index.html?info=AudioFilterBiquad
‘Biquad filters with low corner frequency (under about 400 Hz) can run into trouble with limited numerical precision, causing the filter to perform poorly` with Teensy 3.6 works well.

Maybe because the new powerful microcontroller??

These test results are really great! :)
 
Hi AdaZus,

yes, you can perform very high Q bandpass and notch filters with biquads and they filter very well.

Your example is a bit on the extreme side, a bandpass filter around C# (69Hz) with an extremely high Q of 15.

For my purposes and from my experiences with the fixed point biquad filters, I hear considerable distortion and ringing of those biquad filters when using cutoff frequencies below 400Hz. Maybe you will also find these problems with your example if you perform an FFT of your audio and look at the higher audio frequencies, not only one halftone/tone below and above your bandpass.

If you are satisfied with the audio results for your purpose (filtering only C# from your audio)[BTW, did you really listen to your audio result or did you only measure the output voltage?], thats perfect and you can use them.

All the best,

Frank DD4WH
 
Hi Frank,
Many thanks for your fast reply. :)
No I haven’t heard at the sound. I have only checked the amplitude-difference to understand if the filter works. Even I haven’t checked higher frequencies because I`m interested only in very low frequencies (below ca. 350Hz).

Nevertheless I have updated the test-sketch now to verify if I`m hearing also distortions or similar:
New is:
Sound to headphones, to hear what’s going on and
Notefreq, to see which fundamental is detected..


Code:
/*
https://www.pjrc.com/teensy/gui/index.html?info=AudioFilterBiquad
Biquad filters test with low corner frequency @ Teensy 3.6. 
Try out following sketch.
*/


//01 Notefreq1 after biquad1
#include <Audio.h>
#include <Wire.h>
#include <SPI.h>
#include <SD.h>
#include <SerialFlash.h>

// GUItool: begin automatically generated code
AudioInputI2S            i2s1;           //xy=105,240
AudioAmplifier           amp1;           //xy=262,224
AudioFilterBiquad        biquad1; //xy=444,223
AudioOutputI2S           i2s2;           //xy=695,161
AudioAnalyzePeak         peak1;          //xy=698,231
AudioAnalyzeNoteFrequency notefreq1;      //xy=706,305
AudioConnection          patchCord1(i2s1, 0, amp1, 0);
AudioConnection          patchCord2(amp1, biquad1);
AudioConnection          patchCord3(biquad1, 0, i2s2, 0);
AudioConnection          patchCord4(biquad1, 0, i2s2, 1);
AudioConnection          patchCord5(biquad1, peak1);
AudioConnection          patchCord6(biquad1, notefreq1);
AudioControlSGTL5000     sgtl5000_1;     //xy=362,332
// GUItool: end automatically generated code
//01 Notefreq1 after biquad1

/*
//02 Notefreq1 after amp1
#include <Audio.h>
#include <Wire.h>
#include <SPI.h>
#include <SD.h>
#include <SerialFlash.h>

// GUItool: begin automatically generated code
AudioInputI2S            i2s1;           //xy=105,240
AudioAmplifier           amp1;           //xy=262,224
AudioFilterBiquad        biquad1; //xy=444,223
AudioOutputI2S           i2s2;           //xy=695,161
AudioAnalyzePeak         peak1;          //xy=698,231
AudioAnalyzeNoteFrequency notefreq1;      //xy=706,305
AudioConnection          patchCord1(i2s1, 0, amp1, 0);
AudioConnection          patchCord2(amp1, biquad1);
AudioConnection          patchCord3(amp1, notefreq1);
AudioConnection          patchCord4(biquad1, 0, i2s2, 0);
AudioConnection          patchCord5(biquad1, 0, i2s2, 1);
AudioConnection          patchCord6(biquad1, peak1);
AudioControlSGTL5000     sgtl5000_1;     //xy=362,332
// GUItool: end automatically generated code
//02 Notefreq1 after amp1


//03 Two filter: Biquad2 and Biquad1. Notefreq1 after Biquad2 
#include <Audio.h>
#include <Wire.h>
#include <SPI.h>
#include <SD.h>
#include <SerialFlash.h>

// GUItool: begin automatically generated code
AudioInputI2S            i2s1;           //xy=105,240
AudioAmplifier           amp1;           //xy=262,224
AudioFilterBiquad        biquad2; //xy=399,224
AudioFilterBiquad        biquad1; //xy=527,171
AudioOutputI2S           i2s2;           //xy=695,161
AudioAnalyzePeak         peak1;          //xy=698,231
AudioAnalyzeNoteFrequency notefreq1;      //xy=706,305
AudioConnection          patchCord1(i2s1, 0, amp1, 0);
AudioConnection          patchCord2(amp1, biquad2);
AudioConnection          patchCord3(biquad2, biquad1);
AudioConnection          patchCord4(biquad2, notefreq1);
AudioConnection          patchCord5(biquad1, 0, i2s2, 0);
AudioConnection          patchCord6(biquad1, 0, i2s2, 1);
AudioConnection          patchCord7(biquad1, peak1);
AudioControlSGTL5000     sgtl5000_1;     //xy=362,332
// GUItool: end automatically generated code
//03 Two filter: Biquad2 and Biquad1. Notefreq1 after Biquad2 
*/

elapsedMillis msecs;

//Tones and frequencies
float C = 65.40;
float CIS = 69.29;
float D = 73.41;

float GIS = 103.82;
float A = 110;
float AIS = 116.54;
//Tones and frequencies


void setup() {

  Serial.begin(9600);
  
  AudioMemory(30);
  sgtl5000_1.enable();

  //Hearphone Out
  sgtl5000_1.volume(0.6);
  //Hearphone Out
  
  // MicIn
  sgtl5000_1.inputSelect(AUDIO_INPUT_MIC); 
  sgtl5000_1.micGain(50); // sgtl5000_1.micGain(30); original
  amp1.gain(0); //MicIn (i2s1) gain (again)
  //MicIn
  
  delay(1000);
  notefreq1.begin(.15);
}

      
void loop() {

    amp1.gain(0.9); // to ajusd MicIn(i2s1)-gain: Filters must have their input signals attenuated, so the signal does not exceed 1.0 (or 2 if measured peak to peak).
   
    // Filter 
    //File > Examples > Audio > Effects > Filter
    // Butterworth filter, 12 db/octave
    //biquad1.setLowpass(0, 400, 0.707);
   
   /*
    // Linkwitz-Riley filter, 48 dB/octave
     biquad2.setHighpass(0, 60, 1);
     biquad2.setHighpass(1, 60, 0.707);
     biquad2.setHighpass(2, 60, 1);
     biquad2.setHighpass(3, 60, 0.707);
     // Filter 
   */
    
    // Linkwitz-Riley filter, 48 dB/octave
     biquad1.setBandpass(0, CIS, 10);
     biquad1.setBandpass(1, CIS, 5);
     biquad1.setBandpass(2, CIS, 10);
     biquad1.setBandpass(3, CIS, 5);
     // Filter 


       
       if (msecs > 100) {
        
          // read back fundamental frequency
          if (notefreq1.available()  ) {
          int cpuusage = AudioProcessorUsageMax();
          float note1 = notefreq1.read();
          float prob1 = notefreq1.probability();
          Serial.printf("CPUusage1: %i | Note1: %3.2f | Probability1: %.2f\n", cpuusage, note1, prob1);
          }
          // read back fundamental frequency

          // Amplitude to serial monitor
          if (peak1.available() ) {//only Mono needed.
          msecs = 0;
          float leftNumber = peak1.readPeakToPeak();
          Serial.println(leftNumber); //left channel
          // Amplitude to serial monitor
          }
      }
 }

Result:
I couldn`t hear any distortions or ringing.
But what I have heard is the amplification of cut off frequency.

Example:
Filtered note = CIS
Headphones connected to headphone-out (Teensy AudioBoard).
Play CIS (69.29Hz) with my stereo.
The tone is recorded via microphone (MicIn) and I can hear it very well in headphones.
After stopping playing, I´m hearing the same tone but very silent in the background.
When I´m knocking on the table (or make some interruptive noise), this ‘filtered tone loop’ stops (not every time) and I´m hearing silence.

To solve it I have changed the filter parameters as follows:
// Linkwitz-Riley filter, 48 dB/octave
biquad1.setBandpass(0, CIS, 10);
biquad1.setBandpass(1, CIS, 5);
biquad1.setBandpass(2, CIS, 10);
biquad1.setBandpass(3, CIS, 5);
// Filter

This settings (actually) works well for my project.

BR
 
Status
Not open for further replies.
Back
Top